diff options
Diffstat (limited to 'indra')
178 files changed, 10836 insertions, 3714 deletions
diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index 1ccdb0f20b..84e3477ce6 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -11,6 +11,7 @@ include(LLCommon) include(LLImage) include(LLImageJ2COJ) # ugh, needed for images include(LLMath) +include(LLMessage) include(LLRender) include(LLWindow) include(LLUI) @@ -67,6 +68,7 @@ endif (DARWIN) # Sort by high-level to low-level target_link_libraries(llui_libtest llui + llmessage ${OS_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} ) diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index b93890ab32..4b0bf6a2d9 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -90,7 +90,7 @@ bool translate_init(std::string comma_delim_path_list, // extract paths string vector from comma-delimited flat string std::vector<std::string> paths; - LLStringUtil::getTokens(comma_delim_path_list, paths); // split over ',' + LLStringUtil::getTokens(comma_delim_path_list, paths, ","); // split over ',' // suck the translation xml files into memory LLXMLNodePtr root; diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 80245fd569..9e9e1aaeae 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -62,7 +62,8 @@ if (FMOD) if (LINUX) if (${CXX_VERSION} MATCHES "4.[23]") set_source_files_properties(llaudioengine_fmod.cpp - COMPILE_FLAGS -Wno-error=write-strings) + llstreamingaudio_fmod.cpp + COMPILE_FLAGS -Wno-write-strings) endif (${CXX_VERSION} MATCHES "4.[23]") endif (LINUX) endif (FMOD) diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h index 7b010d6739..acd0da61a4 100644 --- a/indra/llcommon/llchat.h +++ b/indra/llcommon/llchat.h @@ -65,6 +65,12 @@ typedef enum e_chat_audible_level CHAT_AUDIBLE_FULLY = 1 } EChatAudible; +typedef enum e_chat_style +{ + CHAT_STYLE_NORMAL, + CHAT_STYLE_IRC +}EChatStyle; + // A piece of chat class LLChat { @@ -79,7 +85,8 @@ public: mMuted(FALSE), mTime(0.0), mPosAgent(), - mURL() + mURL(), + mChatStyle(CHAT_STYLE_NORMAL) { } std::string mText; // UTF-8 line of text @@ -92,6 +99,7 @@ public: F64 mTime; // viewer only, seconds from viewer start LLVector3 mPosAgent; std::string mURL; + EChatStyle mChatStyle; }; #endif diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 7bc9e16bc9..6a82a848be 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -94,8 +94,12 @@ std::string LLDate::asRFC1123() const return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } +LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format"); + std::string LLDate::toHTTPDateString (std::string fmt) const { + LLFastTimer ft1(FT_DATE_FORMAT); + std::ostringstream stream; time_t locSeconds = (time_t) mSecondsSinceEpoch; struct tm * gmt = gmtime (&locSeconds); @@ -107,6 +111,8 @@ std::string LLDate::toHTTPDateString (std::string fmt) const std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) { + LLFastTimer ft1(FT_DATE_FORMAT); + std::ostringstream stream; stream.imbue (std::locale(LLStringUtil::getLocale().c_str())); toHTTPDateStream (stream, gmt, fmt); @@ -115,11 +121,11 @@ std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) void LLDate::toHTTPDateStream(std::ostream& s, tm * gmt, std::string fmt) { - using namespace std; + LLFastTimer ft1(FT_DATE_FORMAT); const char * pBeg = fmt.c_str(); const char * pEnd = pBeg + fmt.length(); - const time_put<char>& tp = use_facet<time_put<char> >(s.getloc()); + const std::time_put<char>& tp = std::use_facet<std::time_put<char> >(s.getloc()); tp.put (s, s, s.fill(), gmt, pBeg, pEnd); } diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index d7da40d645..78e835dc95 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -42,7 +42,7 @@ #include <winnls.h> // for WideCharToMultiByte #endif -LLFastTimer::DeclareTimer STRING_LOCALIZATION("String Localization"); +LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format"); std::string ll_safe_string(const char* in) @@ -776,12 +776,12 @@ namespace LLStringFn // https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on // allowable code points for XML. Specifically, they are: // 0x09, 0x0a, 0x0d, and 0x20 on up. JC - std::string strip_invalid_xml(const std::string& input) + std::string strip_invalid_xml(const std::string& instr) { std::string output; - output.reserve( input.size() ); - std::string::const_iterator it = input.begin(); - while (it != input.end()) + output.reserve( instr.size() ); + std::string::const_iterator it = instr.begin(); + while (it != instr.end()) { // Must compare as unsigned for >= // Test most likely match first @@ -817,6 +817,315 @@ namespace LLStringFn } } +//////////////////////////////////////////////////////////// + +//static +template<> +void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims) +{ + std::string currToken; + std::string::size_type begIdx, endIdx; + + begIdx = instr.find_first_not_of (delims); + while (begIdx != std::string::npos) + { + endIdx = instr.find_first_of (delims, begIdx); + if (endIdx == std::string::npos) + { + endIdx = instr.length(); + } + + currToken = instr.substr(begIdx, endIdx - begIdx); + LLStringUtil::trim (currToken); + tokens.push_back(currToken); + begIdx = instr.find_first_not_of (delims, endIdx); + } +} + +template<> +LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector<std::string>& tokens) +{ + const std::string delims (","); + + // Find the first ] + size_type pos2 = instr.find(']', start); + if (pos2 == std::string::npos) + return std::string::npos; + + // Find the last [ before ] + size_type pos1 = instr.find_last_of('[', pos2-1); + if (pos1 == std::string::npos || pos1 < start) + return std::string::npos; + + getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims); + start = pos2+1; + + return pos1; +} + +// static +template<> +bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const format_map_t& substitutions) +{ + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + format_map_t::const_iterator iter = substitutions.find(token); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + // if not, see if there's one WITH brackets + iter = substitutions.find(std::string("[" + token + "]")); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + + return false; +} + +// static +template<> +bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const LLSD& substitutions) +{ + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + if (substitutions.has(token)) + { + replacement = substitutions[token].asString(); + return true; + } + // if not, see if there's one WITH brackets + else if (substitutions.has(std::string("[" + token + "]"))) + { + replacement = substitutions[std::string("[" + token + "]")].asString(); + return true; + } + + return false; +} + +// static +template<> +void LLStringUtil::formatNumber(std::string& numStr, std::string decimals) +{ + std::stringstream strStream; + S32 intDecimals = 0; + + convertToS32 (decimals, intDecimals); + if (!sLocale.empty()) + { + strStream.imbue (std::locale(sLocale.c_str())); + } + + if (!intDecimals) + { + S32 intStr; + + if (convertToS32(numStr, intStr)) + { + strStream << intStr; + numStr = strStream.str(); + } + } + else + { + F32 floatStr; + + if (convertToF32(numStr, floatStr)) + { + strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr; + numStr = strStream.str(); + } + } +} + +// static +template<> +bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, + std::string param, S32 secFromEpoch) +{ + if (param == "local") // local + { + secFromEpoch -= LLStringOps::getLocalTimeOffset(); + } + else if (param != "utc") // slt + { + secFromEpoch -= LLStringOps::getSltOffset(); + } + + // if never fell into those two ifs above, param must be utc + if (secFromEpoch < 0) secFromEpoch = 0; + + LLDate * datetime = new LLDate((F64)secFromEpoch); + std::string code = LLStringOps::getDatetimeCode (token); + + // special case to handle timezone + if (code == "%Z") { + if (param == "utc") replacement = "GMT"; + else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST"; + return true; + } + replacement = datetime->toHTTPDateString(code); + + if (code.empty()) + { + return false; + } + else + { + return true; + } +} + +// LLStringUtil::format recogizes the following patterns. +// All substitutions *must* be encased in []'s in the input string. +// The []'s are optional in the substitution map. +// [FOO_123] +// [FOO,number,precision] +// [FOO,datetime,format] + + +// static +template<> +S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) +{ + LLFastTimer ft(FT_STRING_FORMAT); + S32 res = 0; + + std::string output; + std::vector<std::string> tokens; + + std::string::size_type start = 0; + std::string::size_type prev_start = 0; + std::string::size_type key_start = 0; + while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) + { + output += std::string(s, prev_start, key_start-prev_start); + prev_start = start; + + bool found_replacement = false; + std::string replacement; + + if (tokens.size() == 1) + { + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::string param; + if (tokens.size() > 2) param = tokens[2]; + + format_map_t::const_iterator iter = substitutions.find("datetime"); + if (iter != substitutions.end()) + { + S32 secFromEpoch = 0; + BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch); + if (r) + { + found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch); + } + } + } + + if (found_replacement) + { + output += replacement; + res++; + } + else + { + // we had no replacement, so leave the string we searched for so that it gets noticed by QA + // "hello [NAME_NOT_FOUND]" is output + output += std::string("[") + tokens[0] + std::string("]"); + } + tokens.clear(); + } + // send the remainder of the string (with no further matches for bracketed names) + output += std::string(s, start); + s = output; + return res; +} + +//static +template<> +S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) +{ + LLFastTimer ft(FT_STRING_FORMAT); + S32 res = 0; + + if (!substitutions.isMap()) + { + return res; + } + + std::string output; + std::vector<std::string> tokens; + + std::string::size_type start = 0; + std::string::size_type prev_start = 0; + std::string::size_type key_start = 0; + while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) + { + output += std::string(s, prev_start, key_start-prev_start); + prev_start = start; + + bool found_replacement = false; + std::string replacement; + + if (tokens.size() == 1) + { + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::string param; + if (tokens.size() > 2) param = tokens[2]; + + S32 secFromEpoch = (S32) substitutions["datetime"].asInteger(); + found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch); + } + + if (found_replacement) + { + output += replacement; + res++; + } + else + { + // we had no replacement, so leave the string we searched for so that it gets noticed by QA + // "hello [NAME_NOT_FOUND]" is output + output += std::string("[") + tokens[0] + std::string("]"); + } + tokens.clear(); + } + // send the remainder of the string (with no further matches for bracketed names) + output += std::string(s, start); + s = output; + return res; +} //////////////////////////////////////////////////////////// // Testing diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index c6dcdd6d12..3b1379c76a 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -231,7 +231,8 @@ public: static std::basic_string<T> null; typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; - static void getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens); + static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims); + static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens); static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals); static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch); static S32 format(std::basic_string<T>& s, const format_map_t& substitutions); @@ -597,302 +598,12 @@ namespace LLStringFn } //////////////////////////////////////////////////////////// +// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp. +// There is no LLWStringUtil::format implementation currently. +// Calling thse for anything other than LLStringUtil will produce link errors. -//static -template<class T> -void LLStringUtilBase<T>::getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens) -{ - const std::basic_string<T> delims (","); - std::basic_string<T> currToken; - size_type begIdx, endIdx; - - begIdx = input.find_first_not_of (delims); - while (begIdx != std::basic_string<T>::npos) - { - endIdx = input.find_first_of (delims, begIdx); - if (endIdx == std::basic_string<T>::npos) - { - endIdx = input.length(); - } - - currToken = input.substr(begIdx, endIdx - begIdx); - trim (currToken); - tokens.push_back(currToken); - begIdx = input.find_first_not_of (delims, endIdx); - } -} - -extern LLFastTimer::DeclareTimer STRING_LOCALIZATION; - -// static -template<class T> -S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& substitutions) -{ - LLFastTimer ft(STRING_LOCALIZATION); - S32 res = 0; - - std::basic_ostringstream<T> output; - // match strings like [NAME,number,3] - const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]"); - - - typename std::basic_string<T>::const_iterator start = s.begin(); - typename std::basic_string<T>::const_iterator end = s.end(); - boost::smatch match; - - - while (boost::regex_search(start, end, match, key, boost::match_default)) - { - bool found_replacement = false; - std::vector<std::basic_string<T> > tokens; - std::basic_string<T> replacement; - - getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens); - - if (tokens.size() == 1) - { - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - } - else if (tokens[1] == "number") - { - std::basic_string<T> param = "0"; - - if (tokens.size() > 2) param = tokens[2]; - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - if (found_replacement) formatNumber (replacement, param); - } - else if (tokens[1] == "datetime") - { - std::basic_string<T> param; - if (tokens.size() > 2) param = tokens[2]; - - format_map_t::const_iterator iter = substitutions.find("datetime"); - if (iter != substitutions.end()) - { - S32 secFromEpoch = 0; - BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch); - if (r) - { - found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch); - } - } - } - - if (found_replacement) - { - output << std::basic_string<T>(start, match[0].first) << replacement; - res++; - } - else - { - // we had no replacement, so leave the string we searched for so that it gets noticed by QA - // "hello [NAME_NOT_FOUND]" is output - output << std::basic_string<T>(start, match[0].second); - } - - // update search position - start = match[0].second; - } - // send the remainder of the string (with no further matches for bracketed names) - output << std::basic_string<T>(start, end); - s = output.str(); - return res; -} - -//static -template<class T> -S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutions) -{ - LLFastTimer ft(STRING_LOCALIZATION); - - S32 res = 0; - - if (!substitutions.isMap()) - { - return res; - } - - std::basic_ostringstream<T> output; - // match strings like [NAME,number,3] - const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]"); - - - typename std::basic_string<T>::const_iterator start = s.begin(); - typename std::basic_string<T>::const_iterator end = s.end(); - boost::smatch match; - - - while (boost::regex_search(start, end, match, key, boost::match_default)) - { - bool found_replacement = false; - std::vector<std::basic_string<T> > tokens; - std::basic_string<T> replacement; - - getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens); - - if (tokens.size() == 1) - { - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - } - else if (tokens[1] == "number") - { - std::basic_string<T> param = "0"; - - if (tokens.size() > 2) param = tokens[2]; - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - if (found_replacement) formatNumber (replacement, param); - } - else if (tokens[1] == "datetime") - { - std::basic_string<T> param; - if (tokens.size() > 2) param = tokens[2]; - - S32 secFromEpoch = (S32) substitutions["datetime"].asInteger(); - found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch); - } - - if (found_replacement) - { - output << std::basic_string<T>(start, match[0].first) << replacement; - res++; - } - else - { - // we had no replacement, so leave the string we searched for so that it gets noticed by QA - // "hello [NAME_NOT_FOUND]" is output - output << std::basic_string<T>(start, match[0].second); - } - - // update search position - start = match[0].second; - } - // send the remainder of the string (with no further matches for bracketed names) - output << std::basic_string<T>(start, end); - s = output.str(); - return res; -} - -// static -template<class T> -bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const format_map_t& substitutions) -{ - // see if we have a replacement for the bracketed string (without the brackets) - // test first using has() because if we just look up with operator[] we get back an - // empty string even if the value is missing. We want to distinguish between - // missing replacements and deliberately empty replacement strings. - format_map_t::const_iterator iter = substitutions.find(token); - if (iter != substitutions.end()) - { - replacement = iter->second; - return true; - } - // if not, see if there's one WITH brackets - iter = substitutions.find(std::basic_string<T>("[" + token + "]")); - if (iter != substitutions.end()) - { - replacement = iter->second; - return true; - } - - return false; -} - -// static -template<class T> -bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD& substitutions) -{ - // see if we have a replacement for the bracketed string (without the brackets) - // test first using has() because if we just look up with operator[] we get back an - // empty string even if the value is missing. We want to distinguish between - // missing replacements and deliberately empty replacement strings. - if (substitutions.has(token)) - { - replacement = substitutions[token].asString(); - return true; - } - // if not, see if there's one WITH brackets - else if (substitutions.has(std::basic_string<T>("[" + token + "]"))) - { - replacement = substitutions[std::basic_string<T>("[" + token + "]")].asString(); - return true; - } - - return false; -} - -// static -template<class T> -void LLStringUtilBase<T>::formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals) -{ - typedef typename std::basic_string<T>::size_type string_size_type_t; - std::basic_stringstream<T> strStream; - S32 intDecimals = 0; - - convertToS32 (decimals, intDecimals); - if (!sLocale.empty()) - { - strStream.imbue (std::locale(sLocale.c_str())); - } - - if (!intDecimals) - { - S32 intStr; - - if (convertToS32(numStr, intStr)) - { - strStream << intStr; - numStr = strStream.str(); - } - } - else - { - F32 floatStr; - - if (convertToF32(numStr, floatStr)) - { - strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr; - numStr = strStream.str(); - } - } -} - -// static -template<class T> -bool LLStringUtilBase<T>::formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, - std::basic_string<T> param, S32 secFromEpoch) -{ - if (param == "local") // local - { - secFromEpoch -= LLStringOps::getLocalTimeOffset(); - } - else if (param != "utc") // slt - { - secFromEpoch -= LLStringOps::getSltOffset(); - } - - // if never fell into those two ifs above, param must be utc - if (secFromEpoch < 0) secFromEpoch = 0; - - LLDate * datetime = new LLDate((F64)secFromEpoch); - std::string code = LLStringOps::getDatetimeCode (token); - - // special case to handle timezone - if (code == "%Z") { - if (param == "utc") replacement = "GMT"; - else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST"; - return true; - } +//////////////////////////////////////////////////////////// - replacement = datetime->toHTTPDateString(code); - if (code.empty()) - { - return false; - } - else - { - return true; - } -} // static template<class T> diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 32f19d6be5..bd581e860f 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -99,7 +99,7 @@ public: BOOL getIsLinkType() const; // mutators - will not call updateServer(); void setUUID(const LLUUID& new_uuid); - void rename(const std::string& new_name); + virtual void rename(const std::string& new_name); void setParent(const LLUUID& new_parent); void setType(LLAssetType::EType type); diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 99f364a589..45573cd817 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -105,7 +105,7 @@ bool removeSubString(std::string& str, const std::string& substr) size_t pos = str.find(substr); if (pos != string::npos) { - str.erase(pos); + str.erase(pos, substr.size()); return true; } return false; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 8b0fcc68c4..95d693cdc4 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -34,6 +34,8 @@ set(llui_SOURCE_FILES llconsole.cpp llcontainerview.cpp llctrlselectioninterface.cpp + lldockablefloater.cpp + lldockcontrol.cpp lldraghandle.cpp lleditmenuhandler.cpp llf32uictrl.cpp @@ -47,7 +49,7 @@ set(llui_SOURCE_FILES llkeywords.cpp lllayoutstack.cpp lllineeditor.cpp - lllink.cpp + lllistctrl.cpp llmenugl.cpp llmodaldialog.cpp llmultifloater.cpp @@ -78,6 +80,7 @@ set(llui_SOURCE_FILES llstatview.cpp llstyle.cpp lltabcontainer.cpp + lltextbase.cpp lltextbox.cpp lltexteditor.cpp lltextparser.cpp @@ -89,6 +92,10 @@ set(llui_SOURCE_FILES lluiimage.cpp lluistring.cpp llundo.cpp + llurlaction.cpp + llurlentry.cpp + llurlmatch.cpp + llurlregistry.cpp llviewborder.cpp llviewmodel.cpp llview.cpp @@ -108,6 +115,8 @@ set(llui_HEADER_FILES llcontainerview.h llctrlselectioninterface.h lldraghandle.h + lldockablefloater.h + lldockcontrol.h lleditmenuhandler.h llf32uictrl.h llfiltereditor.h @@ -123,7 +132,7 @@ set(llui_HEADER_FILES lllayoutstack.h lllazyvalue.h lllineeditor.h - lllink.h + lllistctrl.h llmenugl.h llmodaldialog.h llmultifloater.h @@ -154,6 +163,7 @@ set(llui_HEADER_FILES llstatview.h llstyle.h lltabcontainer.h + lltextbase.h lltextbox.h lltexteditor.h lltextparser.h @@ -167,6 +177,10 @@ set(llui_HEADER_FILES lluiimage.h lluistring.h llundo.h + llurlaction.h + llurlentry.h + llurlmatch.h + llurlregistry.h llviewborder.h llviewmodel.h llview.h @@ -182,12 +196,21 @@ add_library (llui ${llui_SOURCE_FILES}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries(llui - llrender - llwindow - llimage - llvfs # ugh, just for LLDir - llxuixml - llxml - llcommon # must be after llimage, llwindow, llrender - llmath + ${LLMESSAGE_LIBRARIES} + ${LLRENDER_LIBRARIES} + ${LLWINDOW_LIBRARIES} + ${LLIMAGE_LIBRARIES} + ${LLVFS_LIBRARIES} # ugh, just for LLDir + ${LLXUIXML_LIBRARIES} + ${LLXML_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender ) + +# Add tests +include(LLAddBuildTest) +SET(llui_TEST_SOURCE_FILES + llurlmatch.cpp + llurlentry.cpp + ) +LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}") diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 98e8c9a988..bf58e19949 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -355,11 +355,19 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) setFocus(TRUE); } + /* + * ATTENTION! This call fires another mouse down callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseDownSignal(x, y, mask); + */ + LLUICtrl::handleMouseDown(x, y, mask); + mMouseDownSignal(this, LLSD()); mMouseDownTimer.start(); mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); mMouseHeldDownCount = 0; + if (getSoundFlags() & MOUSE_DOWN) { @@ -378,6 +386,13 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) // Always release the mouse gFocusMgr.setMouseCapture( NULL ); + /* + * ATTENTION! This call fires another mouse up callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseUpSignal(x, y, mask); + */ + LLUICtrl::handleMouseUp(x, y, mask); + // Regardless of where mouseup occurs, handle callback mMouseUpSignal(this, LLSD()); @@ -460,12 +475,16 @@ BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask) void LLButton::onMouseEnter(S32 x, S32 y, MASK mask) { + LLUICtrl::onMouseEnter(x, y, mask); + if (isInEnabledChain()) mNeedsHighlight = TRUE; } void LLButton::onMouseLeave(S32 x, S32 y, MASK mask) { + LLUICtrl::onMouseLeave(x, y, mask); + mNeedsHighlight = FALSE; } diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp new file mode 100644 index 0000000000..d0789d6502 --- /dev/null +++ b/indra/llui/lldockablefloater.cpp @@ -0,0 +1,86 @@ +/** + * @file lldockablefloater.cpp + * @brief Creates a panel of a specific kind for a toast + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lldockablefloater.h" + +LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, + const LLSD& key, const Params& params) : + LLFloater(key, params), mDockControl(dockControl) +{ +} + +LLDockableFloater::~LLDockableFloater() +{ +} + +BOOL LLDockableFloater::postBuild() +{ + mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); + LLFloater::setDocked(true); + return LLView::postBuild(); +} + +void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) +{ + if (docked) + { + mDockControl.get()->on(); + } + else + { + mDockControl.get()->off(); + } + LLFloater::setDocked(docked, pop_on_undock); +} + +void LLDockableFloater::draw() +{ + mDockControl.get()->repositionDockable(); + mDockControl.get()->drawToungue(); + LLFloater::draw(); +} + +void LLDockableFloater::setDockControl(LLDockControl* dockControl) +{ + mDockControl.reset(dockControl); +} +const LLUIImagePtr& LLDockableFloater::getDockTongue() +{ + return mDockTongue; +} + +LLDockControl* LLDockableFloater::getDockControl() +{ + return mDockControl.get(); +} diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h new file mode 100644 index 0000000000..5ece78a925 --- /dev/null +++ b/indra/llui/lldockablefloater.h @@ -0,0 +1,65 @@ +/** + * @file lldockablefloater.h + * @brief Creates a panel of a specific kind for a toast. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_DOCKABLEFLOATER_H +#define LL_DOCKABLEFLOATER_H + +#include "llerror.h" +#include "llfloater.h" +#include "lldockcontrol.h" + +/** + * Represents floater that can dock. + * In case impossibility deriving from LLDockableFloater use LLDockControl. + */ +class LLDockableFloater : public LLFloater +{ +public: + LOG_CLASS(LLDockableFloater); + LLDockableFloater(LLDockControl* dockControl, const LLSD& key, const Params& params = getDefaultParams()); + virtual ~LLDockableFloater(); + + /* virtula */BOOL postBuild(); + /* virtual */void setDocked(bool docked, bool pop_on_undock = true); + /* virtual */void draw(); + +protected: + void setDockControl(LLDockControl* dockControl); + LLDockControl* getDockControl(); + const LLUIImagePtr& getDockTongue(); + +private: + std::auto_ptr<LLDockControl> mDockControl; + LLUIImagePtr mDockTongue; +}; + +#endif /* LL_DOCKABLEFLOATER_H */ diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp new file mode 100644 index 0000000000..bec7f04cc0 --- /dev/null +++ b/indra/llui/lldockcontrol.cpp @@ -0,0 +1,126 @@ +/** + * @file lldockcontrol.cpp + * @brief Creates a panel of a specific kind for a toast + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lldockcontrol.h" + +LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, + const LLUIImagePtr& dockTongue, DocAt dockAt, bool enabled) : + mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue( + dockTongue) +{ + mDockAt = dockAt; + if (enabled) + { + on(); + } + else + { + off(); + } +} + +LLDockControl::~LLDockControl() +{ +} + +void LLDockControl::repositionDockable() +{ + if (mEnabled) + { + calculateDockablePosition(); + } +} + +void LLDockControl::calculateDockablePosition() +{ + LLRect dockRect = mDockWidget->calcScreenRect(); + if (mPrevDockRect != dockRect || mRecalculateDocablePosition) + { + LLRect dockableRect = mDockableFloater->calcScreenRect(); + LLRect rootRect = mDockableFloater->getRootView()->getRect(); + + S32 x = 0; + S32 y = 0; + switch (mDockAt) + { + case TOP: + x = dockRect.getCenterX() - dockableRect.getWidth() / 2; + y = dockRect.mTop + mDockTongue->getHeight() + + dockableRect.getHeight(); + if (x < rootRect.mLeft) + { + x = rootRect.mLeft; + } + if (x + dockableRect.getWidth() > rootRect.mRight) + { + x = rootRect.mRight - dockableRect.getWidth(); + } + mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; + mDockTongueY = dockRect.mTop; + break; + } + dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), + dockableRect.getHeight()); + LLRect localDocableParentRect; + mDockableFloater->getParent()->screenRectToLocal(dockableRect, + &localDocableParentRect); + mDockableFloater->setRect(localDocableParentRect); + + mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, + &mDockTongueX, &mDockTongueY); + mPrevDockRect = dockRect; + mRecalculateDocablePosition = false; + } +} + +void LLDockControl::on() +{ + mDockableFloater->setCanDrag(false); + mEnabled = true; + mRecalculateDocablePosition = true; +} + +void LLDockControl::off() +{ + mDockableFloater->setCanDrag(true); + mEnabled = false; +} + +void LLDockControl::drawToungue() +{ + if (mEnabled) + { + mDockTongue->draw(mDockTongueX, mDockTongueY); + } +} diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h new file mode 100644 index 0000000000..0e1f4c8e64 --- /dev/null +++ b/indra/llui/lldockcontrol.h @@ -0,0 +1,81 @@ +/** + * @file lldockcontrol.h + * @brief Creates a panel of a specific kind for a toast. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-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_DOCKCONTROL_H +#define LL_DOCKCONTROL_H + +#include "llerror.h" +#include "llview.h" +#include "llfloater.h" +#include "lluiimage.h" + +/** + * Provides services for docking of specified floater. + * This class should be used in case impossibility deriving from LLDockableFloater. + */ +class LLDockControl +{ +public: + enum DocAt + { + TOP + }; + +public: + LOG_CLASS(LLDockControl); + LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, + const LLUIImagePtr& dockTongue, DocAt dockAt, + bool enabled); + virtual ~LLDockControl(); + +public: + void on(); + void off(); + void setDock(LLView* dockWidget) + { mDockWidget = dockWidget;}; + void repositionDockable(); + void drawToungue(); +protected: + virtual void calculateDockablePosition(); +private: + bool mEnabled; + bool mRecalculateDocablePosition; + DocAt mDockAt; + LLView* mDockWidget; + LLRect mPrevDockRect; + LLFloater* mDockableFloater; + LLUIImagePtr mDockTongue; + S32 mDockTongueX; + S32 mDockTongueY; +}; + +#endif /* LL_DOCKCONTROL_H */ diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 13f862f3af..556ff80991 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -66,9 +66,12 @@ static LLDefaultChildRegistry::Register<LLScrollContainer> r("scroll_container") #include "llscrollingpanellist.h" #include "llcontainerview.h" #include "llpanel.h" +#include "lllistctrl.h" + static ScrollContainerRegistry::Register<LLScrollingPanelList> r1("scrolling_panel_list"); static ScrollContainerRegistry::Register<LLContainerView> r2("container_view"); static ScrollContainerRegistry::Register<LLPanel> r3("panel", &LLPanel::fromXML); +static ScrollContainerRegistry::Register<LLListCtrl> r4("list"); LLScrollContainer::Params::Params() : is_opaque("opaque"), diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 637642cdcd..36a3b007b6 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -57,6 +57,11 @@ #include "llviewborder.h" #include "lltextbox.h" #include "llsdparam.h" +#include "llcachename.h" +#include "llmenugl.h" +#include "llurlaction.h" + +#include <boost/bind.hpp> static LLDefaultChildRegistry::Register<LLScrollListCtrl> r("scroll_list"); @@ -118,6 +123,7 @@ LLScrollListCtrl::Params::Params() sort_ascending("sort_ascending", true), commit_on_keyboard_movement("commit_on_keyboard_movement", true), heading_height("heading_height"), + page_lines("page_lines", 0), background_visible("background_visible"), draw_stripes("draw_stripes"), column_padding("column_padding"), @@ -140,7 +146,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) : LLUICtrl(p), mLineHeight(0), mScrollLines(0), - mPageLines(0), + mPageLines(p.page_lines), mMaxSelectable(0), mAllowKeyboardMovement(TRUE), mCommitOnKeyboardMovement(p.commit_on_keyboard_movement), @@ -157,6 +163,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mOnSortChangedCallback( NULL ), mHighlightedItem(-1), mBorder(NULL), + mPopupMenu(NULL), mNumDynamicWidthColumns(0), mTotalStaticColumnWidth(0), mTotalColumnPadding(0), @@ -179,7 +186,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mHighlightedColor(p.highlighted_color()), mHoveredColor(p.hovered_color()), mSearchColumn(p.search_column), - mColumnPadding(p.column_padding) + mColumnPadding(p.column_padding), + mContextMenuType(MENU_NONE) { mItemListRect.setOriginAndSize( mBorderThickness, @@ -189,8 +197,6 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) updateLineHeight(); - mPageLines = mLineHeight? (mItemListRect.getHeight()) / mLineHeight : 0; - // Init the scrollbar static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); @@ -207,7 +213,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) sbparams.orientation(LLScrollbar::VERTICAL); sbparams.doc_size(getItemCount()); sbparams.doc_pos(mScrollLines); - sbparams.page_size(mPageLines); + sbparams.page_size( mPageLines ? mPageLines : getItemCount() ); sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2)); sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); sbparams.visible(false); @@ -462,8 +468,12 @@ void LLScrollListCtrl::updateLayout() getChildView("comment_text")->setShape(mItemListRect); // how many lines of content in a single "page" - mPageLines = mLineHeight? mItemListRect.getHeight() / mLineHeight : 0; - BOOL scrollbar_visible = getItemCount() > mPageLines; + S32 page_lines = mLineHeight? mItemListRect.getHeight() / mLineHeight : getItemCount(); + //if mPageLines is NOT provided display all item + if(mPageLines) + page_lines = mPageLines; + + BOOL scrollbar_visible = mLineHeight * getItemCount() > mItemListRect.getHeight(); if (scrollbar_visible) { // provide space on the right for scrollbar @@ -472,7 +482,7 @@ void LLScrollListCtrl::updateLayout() mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - scrollbar_size, mItemListRect.mBottom); mScrollbar->reshape(scrollbar_size, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); - mScrollbar->setPageSize( mPageLines ); + mScrollbar->setPageSize(page_lines); mScrollbar->setDocSize( getItemCount() ); mScrollbar->setVisible(scrollbar_visible); @@ -484,6 +494,9 @@ void LLScrollListCtrl::updateLayout() void LLScrollListCtrl::fitContents(S32 max_width, S32 max_height) { S32 height = llmin( getRequiredRect().getHeight(), max_height ); + if(mPageLines) + height = llmin( mPageLines * mLineHeight + (mDisplayColumnHeaders ? mHeadingHeight : 0), height ); + S32 width = getRect().getWidth(); reshape( width, height ); @@ -714,6 +727,12 @@ void LLScrollListCtrl::setHeadingHeight(S32 heading_height) updateLayout(); } +void LLScrollListCtrl::setPageLines(S32 new_page_lines) +{ + mPageLines = new_page_lines; + + updateLayout(); +} BOOL LLScrollListCtrl::selectFirstItem() { @@ -1360,7 +1379,7 @@ void LLScrollListCtrl::drawItems() S32 y = mItemListRect.mTop - mLineHeight; // allow for partial line at bottom - S32 num_page_lines = mPageLines + 1; + S32 num_page_lines = (mPageLines)? mPageLines : getItemCount() + 1; LLRect item_rect; @@ -1692,6 +1711,72 @@ BOOL LLScrollListCtrl::handleMouseUp(S32 x, S32 y, MASK mask) return LLUICtrl::handleMouseUp(x, y, mask); } +// virtual +BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + LLScrollListItem *item = hitItem(x, y); + if (item) + { + // check to see if we have a UUID for this row + std::string id = item->getValue().asString(); + LLUUID uuid(id); + if (! uuid.isNull() && mContextMenuType != MENU_NONE) + { + // set up the callbacks for all of the avatar/group menu items + // (N.B. callbacks don't take const refs as id is local scope) + bool is_group = (mContextMenuType == MENU_GROUP); + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group)); + registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group)); + registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group)); + + // create the context menu from the XUI file and display it + std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml"; + delete mPopupMenu; + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( + menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + if (mPopupMenu) + { + mPopupMenu->show(x, y); + LLMenuGL::showPopup(this, mPopupMenu, x, y); + return TRUE; + } + } + } + return FALSE; +} + +void LLScrollListCtrl::showNameDetails(std::string id, bool is_group) +{ + // show the resident's profile or the group profile + std::string sltype = is_group ? "group" : "agent"; + std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; + LLUrlAction::clickAction(slurl); +} + +void LLScrollListCtrl::copyNameToClipboard(std::string id, bool is_group) +{ + // copy the name of the avatar or group to the clipboard + std::string name; + if (is_group) + { + gCacheName->getGroupName(LLUUID(id), name); + } + else + { + gCacheName->getFullName(LLUUID(id), name); + } + LLUrlAction::copyURLToClipboard(name); +} + +void LLScrollListCtrl::copySLURLToClipboard(std::string id, bool is_group) +{ + // copy a SLURL for the avatar or group to the clipboard + std::string sltype = is_group ? "group" : "agent"; + std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about"; + LLUrlAction::copyURLToClipboard(slurl); +} + BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) { //BOOL handled = FALSE; @@ -1783,7 +1868,7 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) mLineHeight ); // allow for partial line at bottom - S32 num_page_lines = mPageLines + 1; + S32 num_page_lines = (mPageLines)? mPageLines : getItemCount() + 1; S32 line = 0; item_list::iterator iter; @@ -2348,7 +2433,8 @@ void LLScrollListCtrl::scrollToShowSelected() } S32 lowest = mScrollLines; - S32 highest = mScrollLines + mPageLines; + S32 page_lines = (mPageLines)? mPageLines : getItemCount(); + S32 highest = mScrollLines + page_lines; if (index < lowest) { @@ -2357,7 +2443,7 @@ void LLScrollListCtrl::scrollToShowSelected() } else if (highest <= index) { - setScrollPos(index - mPageLines + 1); + setScrollPos(index - page_lines + 1); } } diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 253a58ab73..5c18f85160 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -54,6 +54,7 @@ class LLScrollListCell; class LLTextBox; +class LLContextMenu; class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, public LLCtrlListInterface, public LLCtrlScrollInterface @@ -86,6 +87,7 @@ public: // layout Optional<S32> column_padding, + page_lines, heading_height; // sort and search behavior @@ -270,10 +272,15 @@ public: void clearSearchString() { mSearchString.clear(); } + // support right-click context menus for avatar/group lists + enum ContextMenuType { MENU_NONE, MENU_AVATAR, MENU_GROUP }; + void setContextMenu(const ContextMenuType &menu) { mContextMenuType = menu; } + // Overridden from LLView /*virtual*/ void draw(); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); @@ -308,6 +315,11 @@ public: S32 getMaxContentWidth() { return mMaxContentWidth; } void setHeadingHeight(S32 heading_height); + /** + * Sets max visible lines without scroolbar, if this value equals to 0, + * then display all items. + */ + void setPageLines(S32 page_lines ); void setCollapseEmptyColumns(BOOL collapse); LLScrollListItem* hitItem(S32 x,S32 y); @@ -362,11 +374,13 @@ protected: typedef std::deque<LLScrollListItem *> item_list; item_list& getItemList() { return mItemList; } + void updateLineHeight(); + private: void selectPrevItem(BOOL extend_selection); void selectNextItem(BOOL extend_selection); void drawItems(); - void updateLineHeight(); + void updateLineHeightInsert(LLScrollListItem* item); void reportInvalidInput(); BOOL isRepeatedChars(const LLWString& string) const; @@ -375,6 +389,10 @@ private: void commitIfChanged(); BOOL setSort(S32 column, BOOL ascending); + static void showNameDetails(std::string id, bool is_group); + static void copyNameToClipboard(std::string id, bool is_group); + static void copySLURLToClipboard(std::string id, bool is_group); + S32 mLineHeight; // the max height of a single line S32 mScrollLines; // how many lines we've scrolled down S32 mPageLines; // max number of lines is it possible to see on the screen given mRect and mLineHeight @@ -421,6 +439,7 @@ private: S32 mHighlightedItem; class LLViewBorder* mBorder; + LLContextMenu *mPopupMenu; LLWString mSearchString; LLFrameTimer mSearchTimer; @@ -438,6 +457,8 @@ private: BOOL mDirty; S32 mOriginalSelection; + ContextMenuType mContextMenuType; + typedef std::vector<LLScrollListColumn*> ordered_columns_t; ordered_columns_t mColumnsIndexed; diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp index 929a809d88..c16ac08014 100644 --- a/indra/llui/llstyle.cpp +++ b/indra/llui/llstyle.cpp @@ -54,8 +54,6 @@ LLStyle::LLStyle(const LLStyle::Params& p) mFont(p.font()), mLink(p.link_href), mDropShadow(p.drop_shadow), - mImageHeight(0), - mImageWidth(0), mImagep(p.image()) {} @@ -100,9 +98,7 @@ void LLStyle::setImage(const LLUUID& src) mImagep = LLUI::getUIImageByID(src); } - -void LLStyle::setImageSize(S32 width, S32 height) +void LLStyle::setImage(const std::string& name) { - mImageWidth = width; - mImageHeight = height; + mImagep = LLUI::getUIImage(name); } diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h index dcf274a651..5e8883afd7 100644 --- a/indra/llui/llstyle.h +++ b/indra/llui/llstyle.h @@ -69,9 +69,9 @@ public: LLUIImagePtr getImage() const; void setImage(const LLUUID& src); + void setImage(const std::string& name); - BOOL isImage() const { return ((mImageWidth != 0) && (mImageHeight != 0)); } - void setImageSize(S32 width, S32 height); + BOOL isImage() const { return mImagep.notNull(); } // inlined here to make it easier to compare to member data below. -MG bool operator==(const LLStyle &rhs) const @@ -82,8 +82,6 @@ public: && mFont == rhs.mFont && mLink == rhs.mLink && mImagep == rhs.mImagep - && mImageHeight == rhs.mImageHeight - && mImageWidth == rhs.mImageWidth && mItalic == rhs.mItalic && mBold == rhs.mBold && mUnderline == rhs.mUnderline @@ -97,8 +95,6 @@ public: BOOL mBold; BOOL mUnderline; BOOL mDropShadow; - S32 mImageWidth; - S32 mImageHeight; protected: ~LLStyle() { } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp new file mode 100644 index 0000000000..038ea2188f --- /dev/null +++ b/indra/llui/lltextbase.cpp @@ -0,0 +1,451 @@ +/** + * @file lltextbase.cpp + * @author Martin Reddy + * @brief The base class of text box/editor, providing Url handling support + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltextbase.h" +#include "llstl.h" +#include "llview.h" +#include "llwindow.h" +#include "llmenugl.h" +#include "lluictrl.h" +#include "llurlaction.h" +#include "llurlregistry.h" + +#include <boost/bind.hpp> + +// global state for all text fields +LLUIColor LLTextBase::mLinkColor = LLColor4::blue; + +bool LLTextBase::compare_segment_end::operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const +{ + return a->getEnd() < b->getEnd(); +} + +// +// LLTextSegment +// + +LLTextSegment::~LLTextSegment() +{} + +S32 LLTextSegment::getWidth(S32 first_char, S32 num_chars) const { return 0; } +S32 LLTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return 0; } +S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const { return 0; } +void LLTextSegment::updateLayout(const LLTextBase& editor) {} +F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { return draw_rect.mLeft; } +S32 LLTextSegment::getMaxHeight() const { return 0; } +bool LLTextSegment::canEdit() const { return false; } +void LLTextSegment::unlinkFromDocument(LLTextBase*) {} +void LLTextSegment::linkToDocument(LLTextBase*) {} +void LLTextSegment::setHasMouseHover(bool hover) {} +const LLColor4& LLTextSegment::getColor() const { return LLColor4::white; } +void LLTextSegment::setColor(const LLColor4 &color) {} +const LLStyleSP LLTextSegment::getStyle() const {static LLStyleSP sp(new LLStyle()); return sp; } +void LLTextSegment::setStyle(const LLStyleSP &style) {} +void LLTextSegment::setToken( LLKeywordToken* token ) {} +LLKeywordToken* LLTextSegment::getToken() const { return NULL; } +BOOL LLTextSegment::getToolTip( std::string& msg ) const { return FALSE; } +void LLTextSegment::setToolTip( const std::string &msg ) {} +void LLTextSegment::dump() const {} + + +// +// LLNormalTextSegment +// + +LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextBase& editor ) +: LLTextSegment(start, end), + mStyle( style ), + mToken(NULL), + mHasMouseHover(false), + mEditor(editor) +{ + mMaxHeight = llceil(mStyle->getFont()->getLineHeight()); +} + +LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) +: LLTextSegment(start, end), + mToken(NULL), + mHasMouseHover(false), + mEditor(editor) +{ + mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); + + mMaxHeight = llceil(mStyle->getFont()->getLineHeight()); +} + +F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) +{ + if( end - start > 0 ) + { + if ( mStyle->isImage() && (start >= 0) && (end <= mEnd - mStart)) + { + LLUIImagePtr image = mStyle->getImage(); + S32 style_image_height = image->getHeight(); + S32 style_image_width = image->getWidth(); + image->draw(draw_rect.mLeft, draw_rect.mTop-style_image_height, + style_image_width, style_image_height); + } + + return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect.mLeft, draw_rect.mBottom); + } + return draw_rect.mLeft; +} + +// Draws a single text segment, reversing the color for selection if needed. +F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, F32 x, F32 y) +{ + const LLWString &text = mEditor.getWText(); + + F32 right_x = x; + if (!mStyle->isVisible()) + { + return right_x; + } + + const LLFontGL* font = mStyle->getFont(); + + LLColor4 color = mStyle->getColor(); + + font = mStyle->getFont(); + + if( selection_start > seg_start ) + { + // Draw normally + S32 start = seg_start; + S32 end = llmin( selection_start, seg_end ); + S32 length = end - start; + font->render(text, start, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems()); + } + x = right_x; + + if( (selection_start < seg_end) && (selection_end > seg_start) ) + { + // Draw reversed + S32 start = llmax( selection_start, seg_start ); + S32 end = llmin( selection_end, seg_end ); + S32 length = end - start; + + font->render(text, start, x, y, + LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ), + LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems()); + } + x = right_x; + if( selection_end < seg_end ) + { + // Draw normally + S32 start = llmax( selection_end, seg_start ); + S32 end = seg_end; + S32 length = end - start; + font->render(text, start, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems()); + } + return right_x; +} + +S32 LLNormalTextSegment::getMaxHeight() const +{ + return mMaxHeight; +} + +BOOL LLNormalTextSegment::getToolTip(std::string& msg) const +{ + // do we have a tooltip for a loaded keyword (for script editor)? + if (mToken && !mToken->getToolTip().empty()) + { + const LLWString& wmsg = mToken->getToolTip(); + msg = wstring_to_utf8str(wmsg); + return TRUE; + } + // or do we have an explicitly set tooltip (e.g., for Urls) + if (! mTooltip.empty()) + { + msg = mTooltip; + return TRUE; + } + return FALSE; +} + +void LLNormalTextSegment::setToolTip(const std::string& tooltip) +{ + // we cannot replace a keyword tooltip that's loaded from a file + if (mToken) + { + llwarns << "LLTextSegment::setToolTip: cannot replace keyword tooltip." << llendl; + return; + } + mTooltip = tooltip; +} + +S32 LLNormalTextSegment::getWidth(S32 first_char, S32 num_chars) const +{ + LLWString text = mEditor.getWText(); + return mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); +} + +S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const +{ + LLWString text = mEditor.getWText(); + return mStyle->getFont()->charFromPixelOffset(text.c_str(), mStart + start_offset, + (F32)segment_local_x_coord, + F32_MAX, + num_chars, + round); +} + +S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const +{ + LLWString text = mEditor.getWText(); + S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart, + (F32)num_pixels, + max_chars, + mEditor.getWordWrap()); + + if (num_chars == 0 + && line_offset == 0 + && max_chars > 0) + { + // If at the beginning of a line, and a single character won't fit, draw it anyway + num_chars = 1; + } + if (mStart + segment_offset + num_chars == mEditor.getLength()) + { + // include terminating NULL + num_chars++; + } + return num_chars; +} + +void LLNormalTextSegment::dump() const +{ + llinfos << "Segment [" << +// mColor.mV[VX] << ", " << +// mColor.mV[VY] << ", " << +// mColor.mV[VZ] << "]\t[" << + mStart << ", " << + getEnd() << "]" << + llendl; +} + +////////////////////////////////////////////////////////////////////////// +// +// LLTextBase +// + +LLTextBase::LLTextBase(const LLUICtrl::Params &p) : + mHoverSegment(NULL), + mDefaultFont(p.font), + mParseHTML(TRUE), + mPopupMenu(NULL) +{ +} + +LLTextBase::~LLTextBase() +{ + clearSegments(); +} + +void LLTextBase::clearSegments() +{ + setHoverSegment(NULL); + mSegments.clear(); +} + +void LLTextBase::setHoverSegment(LLTextSegmentPtr segment) +{ + if (mHoverSegment) + { + mHoverSegment->setHasMouseHover(false); + } + if (segment) + { + segment->setHasMouseHover(true); + } + mHoverSegment = segment; +} + +void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const +{ + *seg_iter = getSegIterContaining(startpos); + if (*seg_iter == mSegments.end()) + { + *offsetp = 0; + } + else + { + *offsetp = startpos - (**seg_iter)->getStart(); + } +} + +void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ) +{ + *seg_iter = getSegIterContaining(startpos); + if (*seg_iter == mSegments.end()) + { + *offsetp = 0; + } + else + { + *offsetp = startpos - (**seg_iter)->getStart(); + } +} + +LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index) +{ + segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index)); + return it; +} + +LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 index) const +{ + LLTextBase::segment_set_t::const_iterator it = mSegments.upper_bound(new LLIndexSegment(index)); + return it; +} + +// Finds the text segment (if any) at the give local screen position +LLTextSegmentPtr LLTextBase::getSegmentAtLocalPos( S32 x, S32 y ) +{ + // Find the cursor position at the requested local screen position + S32 offset = getDocIndexFromLocalCoord( x, y, FALSE ); + segment_set_t::iterator seg_iter = getSegIterContaining(offset); + if (seg_iter != mSegments.end()) + { + return *seg_iter; + } + else + { + return LLTextSegmentPtr(); + } +} + +BOOL LLTextBase::handleHoverOverUrl(S32 x, S32 y) +{ + setHoverSegment(NULL); + + // Check to see if we're over an HTML-style link + LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); + if (cur_segment) + { + setHoverSegment(cur_segment); + + LLStyleSP style = cur_segment->getStyle(); + if (style && style->isLink()) + { + return TRUE; + } + } + + return FALSE; +} + +BOOL LLTextBase::handleMouseUpOverUrl(S32 x, S32 y) +{ + if (mParseHTML && mHoverSegment) + { + LLStyleSP style = mHoverSegment->getStyle(); + if (style && style->isLink()) + { + LLUrlAction::clickAction(style->getLinkHREF()); + return TRUE; + } + } + + return FALSE; +} + +BOOL LLTextBase::handleRightMouseDownOverUrl(LLView *view, S32 x, S32 y) +{ + // pop up a context menu for any Url under the cursor + const LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->getStyle() && cur_segment->getStyle()->isLink()) + { + delete mPopupMenu; + mPopupMenu = createUrlContextMenu(cur_segment->getStyle()->getLinkHREF()); + if (mPopupMenu) + { + mPopupMenu->show(x, y); + LLMenuGL::showPopup(view, mPopupMenu, x, y); + return TRUE; + } + } + + return FALSE; +} + +BOOL LLTextBase::handleToolTipForUrl(LLView *view, S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) +{ + const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); + if (cur_segment && cur_segment->getToolTip( msg ) && view) + { + // Use a slop area around the cursor + const S32 SLOP = 8; + // Convert rect local to screen coordinates + view->localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect_screen->mLeft), + &(sticky_rect_screen->mBottom)); + sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; + sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; + } + return TRUE; +} + +LLContextMenu *LLTextBase::createUrlContextMenu(const std::string &in_url) +{ + // work out the XUI menu file to use for this url + LLUrlMatch match; + std::string url = in_url; + if (! LLUrlRegistry::instance().findUrl(url, match)) + { + return NULL; + } + + std::string xui_file = match.getMenuName(); + if (xui_file.empty()) + { + return NULL; + } + + // set up the callbacks for all of the potential menu items, N.B. we + // don't use const ref strings in callbacks in case url goes out of scope + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Url.Open", boost::bind(&LLUrlAction::openURL, url)); + registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url)); + registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url)); + registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url)); + registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); + registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); + registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); + + // create and return the context menu from the XUI file + return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer, + LLMenuHolderGL::child_registry_t::instance()); +} diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h new file mode 100644 index 0000000000..27b88761a8 --- /dev/null +++ b/indra/llui/lltextbase.h @@ -0,0 +1,198 @@ +/** + * @file lltextbase.h + * @author Martin Reddy + * @brief The base class of text box/editor, providing Url handling support + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXTBASE_H +#define LL_LLTEXTBASE_H + +#include "v4color.h" +#include "llstyle.h" +#include "llkeywords.h" +#include "lluictrl.h" + +#include <string> +#include <set> + +class LLContextMenu; +class LLTextSegment; + +typedef LLPointer<LLTextSegment> LLTextSegmentPtr; + +/// +/// The LLTextBase class provides a base class for all text fields, such +/// as LLTextEditor and LLTextBox. It implements shared functionality +/// such as Url highlighting and opening. +/// +class LLTextBase +{ +public: + LLTextBase(const LLUICtrl::Params &p); + virtual ~LLTextBase(); + + /// specify the color to display Url hyperlinks in the text + static void setLinkColor(LLColor4 color) { mLinkColor = color; } + + /// enable/disable the automatic hyperlinking of Urls in the text + void setParseHTML(BOOL parsing) { mParseHTML=parsing; } + + // public text editing virtual methods + virtual LLWString getWText() const = 0; + virtual BOOL allowsEmbeddedItems() const { return FALSE; } + virtual BOOL getWordWrap() { return mWordWrap; } + virtual S32 getLength() const = 0; + +protected: + struct compare_segment_end + { + bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const; + }; + typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t; + + // routines to manage segments + void getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const; + void getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ); + LLTextSegmentPtr getSegmentAtLocalPos( S32 x, S32 y ); + segment_set_t::iterator getSegIterContaining(S32 index); + segment_set_t::const_iterator getSegIterContaining(S32 index) const; + void clearSegments(); + void setHoverSegment(LLTextSegmentPtr segment); + + // event handling for Urls within the text field + BOOL handleHoverOverUrl(S32 x, S32 y); + BOOL handleMouseUpOverUrl(S32 x, S32 y); + BOOL handleRightMouseDownOverUrl(LLView *view, S32 x, S32 y); + BOOL handleToolTipForUrl(LLView *view, S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen); + + // pure virtuals that have to be implemented by any subclasses + virtual S32 getLineCount() const = 0; + virtual S32 getLineStart( S32 line ) const = 0; + virtual S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const = 0; + + // protected member variables + static LLUIColor mLinkColor; + const LLFontGL *mDefaultFont; + segment_set_t mSegments; + LLTextSegmentPtr mHoverSegment; + BOOL mParseHTML; + BOOL mWordWrap; + +private: + // create a popup context menu for the given Url + static LLContextMenu *createUrlContextMenu(const std::string &url); + + LLContextMenu *mPopupMenu; +}; + +/// +/// A text segment is used to specify a subsection of a text string +/// that should be formatted differently, such as a hyperlink. It +/// includes a start/end offset from the start of the string, a +/// style to render with, an optional tooltip, etc. +/// +class LLTextSegment : public LLRefCount +{ +public: + LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){}; + virtual ~LLTextSegment(); + + virtual S32 getWidth(S32 first_char, S32 num_chars) const; + virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; + virtual S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; + virtual void updateLayout(const class LLTextBase& editor); + virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); + virtual S32 getMaxHeight() const; + virtual bool canEdit() const; + virtual void unlinkFromDocument(class LLTextBase* editor); + virtual void linkToDocument(class LLTextBase* editor); + + virtual void setHasMouseHover(bool hover); + virtual const LLColor4& getColor() const; + virtual void setColor(const LLColor4 &color); + virtual const LLStyleSP getStyle() const; + virtual void setStyle(const LLStyleSP &style); + virtual void setToken( LLKeywordToken* token ); + virtual LLKeywordToken* getToken() const; + virtual BOOL getToolTip( std::string& msg ) const; + virtual void setToolTip(const std::string& tooltip); + virtual void dump() const; + + S32 getStart() const { return mStart; } + void setStart(S32 start) { mStart = start; } + S32 getEnd() const { return mEnd; } + void setEnd( S32 end ) { mEnd = end; } + +protected: + S32 mStart; + S32 mEnd; +}; + +class LLNormalTextSegment : public LLTextSegment +{ +public: + LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextBase& editor ); + LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + + /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const; + /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; + /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); + /*virtual*/ S32 getMaxHeight() const; + /*virtual*/ bool canEdit() const { return true; } + /*virtual*/ void setHasMouseHover(bool hover) { mHasMouseHover = hover; } + /*virtual*/ const LLColor4& getColor() const { return mStyle->getColor(); } + /*virtual*/ void setColor(const LLColor4 &color) { mStyle->setColor(color); } + /*virtual*/ const LLStyleSP getStyle() const { return mStyle; } + /*virtual*/ void setStyle(const LLStyleSP &style) { mStyle = style; } + /*virtual*/ void setToken( LLKeywordToken* token ) { mToken = token; } + /*virtual*/ LLKeywordToken* getToken() const { return mToken; } + /*virtual*/ BOOL getToolTip( std::string& msg ) const; + /*virtual*/ void setToolTip(const std::string& tooltip); + /*virtual*/ void dump() const; + +protected: + F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, F32 x, F32 y); + + class LLTextBase& mEditor; + LLStyleSP mStyle; + S32 mMaxHeight; + LLKeywordToken* mToken; + bool mHasMouseHover; + std::string mTooltip; +}; + +class LLIndexSegment : public LLTextSegment +{ +public: + LLIndexSegment(S32 pos) : LLTextSegment(pos, pos) {} +}; + +#endif diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 96e72487b8..30bf182deb 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -32,30 +32,24 @@ #include "linden_common.h" #include "lltextbox.h" -#include "lllink.h" #include "lluictrlfactory.h" #include "llfocusmgr.h" #include "llwindow.h" +#include "llurlregistry.h" +#include "llstyle.h" static LLDefaultChildRegistry::Register<LLTextBox> r("text"); -//*NOTE -// LLLink is not used in code for now, therefor Visual Studio doesn't build it. -// "link" is registered here to force Visual Studio to build LLLink class. -static LLDefaultChildRegistry::Register<LLLink> register_link("link"); - LLTextBox::Params::Params() : text_color("text_color"), length("length"), type("type"), - highlight_on_hover("hover", false), border_visible("border_visible", false), border_drop_shadow_visible("border_drop_shadow_visible", false), bg_visible("bg_visible", false), use_ellipses("use_ellipses"), word_wrap("word_wrap", false), drop_shadow_visible("drop_shadow_visible"), - hover_color("hover_color"), disabled_color("disabled_color"), background_color("background_color"), border_color("border_color"), @@ -68,9 +62,7 @@ LLTextBox::Params::Params() LLTextBox::LLTextBox(const LLTextBox::Params& p) : LLUICtrl(p), - mFontGL(p.font), - mHoverActive( p.highlight_on_hover ), - mHasHover( FALSE ), + LLTextBase(p), mBackgroundVisible( p.bg_visible ), mBorderVisible( p.border_visible ), mShadowType( p.font_shadow ), @@ -84,12 +76,11 @@ LLTextBox::LLTextBox(const LLTextBox::Params& p) mDisabledColor(p.disabled_color()), mBackgroundColor(p.background_color()), mBorderColor(p.border_color()), - mHoverColor(p.hover_color()), mHAlign(p.font_halign), mLineSpacing(p.line_spacing), - mWordWrap( p.word_wrap ), mDidWordWrap(FALSE) { + mWordWrap = p.word_wrap; setText( p.text() ); } @@ -97,9 +88,9 @@ BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; - // HACK: Only do this if there actually is a click callback, so that + // HACK: Only do this if there actually is something to click, so that // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback) + if (isClickable()) { handled = TRUE; @@ -121,10 +112,9 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) // We only handle the click if the click both started and ended within us - // HACK: Only do this if there actually is a click callback, so that + // HACK: Only do this if there actually is something to click, so that // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback - && hasMouseCapture()) + if (isClickable() && hasMouseCapture()) { handled = TRUE; @@ -136,27 +126,44 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) make_ui_sound("UISndClickRelease"); } - // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. - // If mouseup in the widget, it's been clicked - if (mClickedCallback) + // handle clicks on Urls in the textbox first + if (! handleMouseUpOverUrl(x, y)) { - mClickedCallback(); + // DO THIS AT THE VERY END to allow the button to be destroyed + // as a result of being clicked. If mouseup in the widget, + // it's been clicked + if (mClickedCallback && ! handled) + { + mClickedCallback(); + } } } return handled; } +BOOL LLTextBox::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + // pop up a context menu for any Url under the cursor + return handleRightMouseDownOverUrl(this, x, y); +} + BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = LLView::handleHover(x,y,mask); - if(mHoverActive) + // Check to see if we're over an HTML-style link + if (handleHoverOverUrl(x, y)) { - mHasHover = TRUE; // This should be set every frame during a hover. - getWindow()->setCursor(UI_CURSOR_ARROW); + lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; + getWindow()->setCursor(UI_CURSOR_HAND); + return TRUE; } - return (handled || mHasHover); + return LLView::handleHover(x,y,mask); +} + +BOOL LLTextBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) +{ + return handleToolTipForUrl(this, x, y, msg, sticky_rect_screen); } void LLTextBox::setText(const LLStringExplicit& text) @@ -168,7 +175,7 @@ void LLTextBox::setText(const LLStringExplicit& text) else { mText.assign(text); - setLineLengths(); + updateDisplayTextAndSegments(); } } @@ -177,11 +184,11 @@ void LLTextBox::setLineLengths() mLineLengthList.clear(); std::string::size_type cur = 0; - std::string::size_type len = mText.getWString().size(); + std::string::size_type len = mDisplayText.size(); while (cur < len) { - std::string::size_type end = mText.getWString().find('\n', cur); + std::string::size_type end = mDisplayText.find('\n', cur); std::string::size_type runLen; if (end == std::string::npos) @@ -199,20 +206,12 @@ void LLTextBox::setLineLengths() } } -void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width) +LLWString LLTextBox::wrapText(const LLWString &wtext, S32 &hoffset, S32 &line_num, F32 max_width) { - if (max_width < 0.0f) - { - max_width = (F32)getRect().getWidth(); - } - - LLWString wtext = utf8str_to_wstring(in_text); LLWString final_wtext; - LLWString::size_type cur = 0;; - LLWString::size_type len = wtext.size(); - F32 line_height = mFontGL->getLineHeight(); - S32 line_num = 1; + LLWString::size_type cur = 0; + LLWString::size_type len = wtext.size(); while (cur < len) { LLWString::size_type end = wtext.find('\n', cur); @@ -221,41 +220,121 @@ void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width) end = len; } + bool charsRemaining = true; LLWString::size_type runLen = end - cur; if (runLen > 0) { + // work out how many chars can fit onto the current line LLWString run(wtext, cur, runLen); LLWString::size_type useLen = - mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); + mDefaultFont->maxDrawableChars(run.c_str(), max_width-hoffset, runLen, TRUE); + charsRemaining = (cur + useLen < len); + // try to break lines on word boundaries + if (useLen < run.size()) + { + LLWString::size_type prev_use_len = useLen; + while (useLen > 0 && ! isspace(run[useLen-1]) && ! ispunct(run[useLen-1])) + { + --useLen; + } + if (useLen == 0) + { + useLen = prev_use_len; + } + } + + // add the chars that could fit onto one line to our result final_wtext.append(wtext, cur, useLen); cur += useLen; - // not enough room to add any more characters - if (useLen == 0) break; + hoffset += mDefaultFont->getWidth(run.substr(0, useLen).c_str()); + + // abort if not enough room to add any more characters + if (useLen == 0) + { + break; + } } - if (cur < len) + if (charsRemaining) { if (wtext[cur] == '\n') { cur += 1; } - line_num +=1; - // Don't wrap the last line if the text is going to spill off - // the bottom of the rectangle. Assume we prefer to run off - // the right edge. - // *TODO: Is this the right behavior? - if((line_num-1)*line_height <= (F32)getRect().getHeight()) + final_wtext += '\n'; + hoffset = 0; + line_num += 1; + } + } + + return final_wtext; +} + +void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width) +{ + mDidWordWrap = TRUE; + setText(wstring_to_utf8str(getWrappedText(in_text, max_width))); +} + +LLWString LLTextBox::getWrappedText(const LLStringExplicit& in_text, F32 max_width) +{ + // + // we don't want to wrap Urls otherwise we won't be able to detect their + // presence for hyperlinking. So we look for all Urls, and then word wrap + // the text before and after, but never break a Url in the middle. We + // also need to consider that the Url will be displayed as a label (not + // necessary the actual Url string). + // + + if (max_width < 0.0f) + { + max_width = (F32)getRect().getWidth(); + } + + LLWString wtext = utf8str_to_wstring(in_text); + LLWString final_wtext; + S32 line_num = 1; + S32 hoffset = 0; + + // find the next Url in the text string + LLUrlMatch match; + while ( LLUrlRegistry::instance().findUrl(wstring_to_utf8str(wtext), match)) + { + S32 start = match.getStart(); + S32 end = match.getEnd() + 1; + + // perform word wrap on the text before the Url + final_wtext += wrapText(wtext.substr(0, start), hoffset, line_num, max_width); + + // add the Url (but compute width based on its label) + S32 label_width = mDefaultFont->getWidth(match.getLabel()); + if (hoffset > 0 && hoffset + label_width > max_width) + { + final_wtext += '\n'; + line_num++; + hoffset = 0; + } + final_wtext += wtext.substr(start, end-start); + hoffset += label_width; + if (hoffset > max_width) + { + final_wtext += '\n'; + line_num++; + hoffset = 0; + // eat any leading whitespace on the next line + while (isspace(wtext[end]) && end < (S32)wtext.size()) { - final_wtext += '\n'; + end++; } } + + // move on to the rest of the text after the Url + wtext = wtext.substr(end, wtext.size() - end + 1); } - - mDidWordWrap = TRUE; - std::string final_text = wstring_to_utf8str(final_wtext); - setText(final_text); + final_wtext += wrapText(wtext, hoffset, line_num, max_width); + return final_wtext; } S32 LLTextBox::getTextPixelWidth() @@ -268,7 +347,7 @@ S32 LLTextBox::getTextPixelWidth() iter != mLineLengthList.end(); ++iter) { S32 line_length = *iter; - S32 line_width = mFontGL->getWidth( mText.getWString().c_str(), cur_pos, line_length ); + S32 line_width = mDefaultFont->getWidth( mDisplayText.c_str(), cur_pos, line_length ); if( line_width > max_line_width ) { max_line_width = line_width; @@ -278,7 +357,7 @@ S32 LLTextBox::getTextPixelWidth() } else { - max_line_width = mFontGL->getWidth(mText.getWString().c_str()); + max_line_width = mDefaultFont->getWidth(mDisplayText.c_str()); } return max_line_width; } @@ -290,7 +369,7 @@ S32 LLTextBox::getTextPixelHeight() { num_lines = 1; } - return (S32)(num_lines * mFontGL->getLineHeight()); + return (S32)(num_lines * mDefaultFont->getLineHeight()); } void LLTextBox::setValue(const LLSD& value ) @@ -302,7 +381,7 @@ void LLTextBox::setValue(const LLSD& value ) BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text ) { mText.setArg(key, text); - setLineLengths(); + updateDisplayTextAndSegments(); return TRUE; } @@ -345,18 +424,11 @@ void LLTextBox::draw() if ( getEnabled() ) { - if(mHasHover) - { - drawText( text_x, text_y, mHoverColor.get() ); - } - else - { - drawText( text_x, text_y, mTextColor.get() ); - } + drawText( text_x, text_y, mDisplayText, mTextColor.get() ); } else { - drawText( text_x, text_y, mDisabledColor.get() ); + drawText( text_x, text_y, mDisplayText, mDisabledColor.get() ); } if (sDebugRects) @@ -370,41 +442,49 @@ void LLTextBox::draw() //{ // drawDebugRect(); //} - - mHasHover = FALSE; // This is reset every frame. } void LLTextBox::reshape(S32 width, S32 height, BOOL called_from_parent) { - // reparse line lengths + // reparse line lengths (don't need to recalculate the display text) setLineLengths(); LLView::reshape(width, height, called_from_parent); } -void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color ) +void LLTextBox::drawText( S32 x, S32 y, const LLWString &text, const LLColor4& color ) { - if( mLineLengthList.empty() ) + if (mSegments.size() > 1) { - mFontGL->render(mText.getWString(), 0, (F32)x, (F32)y, color, - mHAlign, mVAlign, - 0, - mShadowType, - S32_MAX, getRect().getWidth(), NULL, mUseEllipses); + // we have Urls (or other multi-styled segments) + drawTextSegments(x, y, text); + } + else if( mLineLengthList.empty() ) + { + // simple case of 1 line of text in one style + mDefaultFont->render(text, 0, (F32)x, (F32)y, color, + mHAlign, mVAlign, + 0, + mShadowType, + S32_MAX, getRect().getWidth(), NULL, mUseEllipses); } else { + // simple case of multiple lines of text, all in the same style S32 cur_pos = 0; for (std::vector<S32>::iterator iter = mLineLengthList.begin(); iter != mLineLengthList.end(); ++iter) { S32 line_length = *iter; - mFontGL->render(mText.getWString(), cur_pos, (F32)x, (F32)y, color, - mHAlign, mVAlign, - 0, - mShadowType, - line_length, getRect().getWidth(), NULL, mUseEllipses ); + mDefaultFont->render(text, cur_pos, (F32)x, (F32)y, color, + mHAlign, mVAlign, + 0, + mShadowType, + line_length, getRect().getWidth(), NULL, mUseEllipses ); cur_pos += line_length + 1; - y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing; + S32 line_height = llfloor(mDefaultFont->getLineHeight()) + mLineSpacing; + y -= line_height; + if(y < line_height) + break; } } } @@ -415,3 +495,254 @@ void LLTextBox::reshapeToFitText() S32 height = getTextPixelHeight(); reshape( width + 2 * mHPad, height + 2 * mVPad ); } + +S32 LLTextBox::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const +{ + // Returns the character offset for the character under the local (x, y) coordinate. + // When round is true, if the position is on the right half of a character, the cursor + // will be put to its right. If round is false, the cursor will always be put to the + // character's left. + + LLRect rect = getLocalRect(); + rect.mLeft += mHPad; + rect.mRight -= mHPad; + rect.mTop += mVPad; + rect.mBottom -= mVPad; + + // Figure out which line we're nearest to. + S32 total_lines = getLineCount(); + S32 line_height = llround( mDefaultFont->getLineHeight() ) + mLineSpacing; + S32 line = (rect.mTop - 1 - local_y) / line_height; + if (line >= total_lines) + { + return getLength(); // past the end + } + + line = llclamp( line, 0, total_lines ); + S32 line_start = getLineStart(line); + S32 next_start = getLineStart(line+1); + S32 line_end = (next_start != line_start) ? next_start - 1 : getLength(); + if (line_start == -1) + { + return 0; + } + + S32 line_len = line_end - line_start; + S32 pos = mDefaultFont->charFromPixelOffset(mDisplayText.c_str(), line_start, + (F32)(local_x - rect.mLeft), + (F32)rect.getWidth(), + line_len, round); + + return line_start + pos; +} + +S32 LLTextBox::getLineStart( S32 line ) const +{ + line = llclamp(line, 0, getLineCount()-1); + + S32 result = 0; + for (int i = 0; i < line; i++) + { + result += mLineLengthList[i] + 1 /* add newline */; + } + + return result; +} + +void LLTextBox::updateDisplayTextAndSegments() +{ + // remove any previous segment list + clearSegments(); + + // if URL parsing is turned off, then not much to bo + if (! mParseHTML) + { + mDisplayText = mText.getWString(); + setLineLengths(); + return; + } + + // create unique text segments for Urls + mDisplayText.clear(); + S32 end = 0; + LLUrlMatch match; + LLWString text = mText.getWString(); + + // find the next Url in the text string + while ( LLUrlRegistry::instance().findUrl(wstring_to_utf8str(text), match, + boost::bind(&LLTextBox::onUrlLabelUpdated, this, _1, _2)) ) + { + // work out the char offset for the start/end of the url + S32 seg_start = mDisplayText.size(); + S32 start = seg_start + match.getStart(); + end = start + match.getLabel().size(); + + // create a segment for the text before the Url + mSegments.insert(new LLNormalTextSegment(new LLStyle(), seg_start, start, *this)); + mDisplayText += text.substr(0, match.getStart()); + + // create a segment for the Url text + LLStyleSP html(new LLStyle); + html->setVisible(true); + html->setColor(mLinkColor); + html->mUnderline = TRUE; + html->setLinkHREF(match.getUrl()); + + LLNormalTextSegment *html_seg = new LLNormalTextSegment(html, start, end, *this); + html_seg->setToolTip(match.getTooltip()); + + mSegments.insert(html_seg); + mDisplayText += utf8str_to_wstring(match.getLabel()); + + // move on to the rest of the text after the Url + text = text.substr(match.getEnd()+1, text.size() - match.getEnd()); + } + + // output a segment for the remaining text + if (text.size() > 0) + { + mSegments.insert(new LLNormalTextSegment(new LLStyle(), end, end + text.size(), *this)); + mDisplayText += text; + } + + // strip whitespace from the end of the text + while (mDisplayText.size() > 0 && isspace(mDisplayText[mDisplayText.size()-1])) + { + mDisplayText = mDisplayText.substr(0, mDisplayText.size() - 1); + + segment_set_t::iterator it = getSegIterContaining(mDisplayText.size()); + if (it != mSegments.end()) + { + LLTextSegmentPtr seg = *it; + seg->setEnd(seg->getEnd()-1); + } + } + + // we may have changed the line lengths, so recalculate them + setLineLengths(); +} + +void LLTextBox::onUrlLabelUpdated(const std::string &url, const std::string &label) +{ + if (mDidWordWrap) + { + // re-word wrap as the url label lengths may have changed + setWrappedText(mText.getString()); + } + else + { + // or just update the display text with the latest Url labels + updateDisplayTextAndSegments(); + } +} + +bool LLTextBox::isClickable() const +{ + // return true if we have been given a click callback + if (mClickedCallback) + { + return true; + } + + // also return true if we have a clickable Url in the text + segment_set_t::const_iterator it; + for (it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegmentPtr segmentp = *it; + if (segmentp) + { + const LLStyleSP style = segmentp->getStyle(); + if (style && style->isLink()) + { + return true; + } + } + } + + // otherwise there is nothing clickable here + return false; +} + +void LLTextBox::drawTextSegments(S32 init_x, S32 init_y, const LLWString &text) +{ + const S32 text_len = text.length(); + if (text_len <= 0) + { + return; + } + + S32 cur_line = 0; + S32 num_lines = getLineCount(); + S32 line_start = getLineStart(cur_line); + S32 line_height = llround( mDefaultFont->getLineHeight() ) + mLineSpacing; + F32 text_y = (F32) init_y; + segment_set_t::iterator cur_seg = mSegments.begin(); + + // render a line of text at a time + const LLRect textRect = getLocalRect(); + while((textRect.mBottom <= text_y) && (cur_line < num_lines)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // render all segments on this line + F32 text_x = init_x; + S32 seg_start = line_start; + while (seg_start < line_end && cur_seg != mSegments.end()) + { + // move to the next segment (or continue the previous one) + LLTextSegment *cur_segment = *cur_seg; + while (cur_segment->getEnd() <= seg_start) + { + if (++cur_seg == mSegments.end()) + { + return; + } + cur_segment = *cur_seg; + } + + // Draw a segment within the line + S32 clipped_end = llmin( line_end, cur_segment->getEnd() ); + S32 clipped_len = clipped_end - seg_start; + if( clipped_len > 0 ) + { + LLStyleSP style = cur_segment->getStyle(); + if (style && style->isVisible()) + { + // work out the color for the segment + LLColor4 color ; + if (getEnabled()) + { + color = style->isLink() ? mLinkColor.get() : mTextColor.get(); + } + else + { + color = mDisabledColor.get(); + } + + // render a single line worth for this segment + mDefaultFont->render(text, seg_start, text_x, text_y, color, + mHAlign, mVAlign, 0, mShadowType, clipped_len, + textRect.getWidth(), &text_x, mUseEllipses); + } + + seg_start += clipped_len; + } + } + + // move down one line + text_y -= (F32)line_height; + line_start = next_start; + cur_line++; + } +} diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index d807fe7639..940b820004 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -37,10 +37,11 @@ #include "v4color.h" #include "llstring.h" #include "lluistring.h" +#include "lltextbase.h" - -class LLTextBox -: public LLUICtrl +class LLTextBox : + public LLTextBase, + public LLUICtrl { public: @@ -51,8 +52,7 @@ public: { Optional<std::string> text; - Optional<bool> highlight_on_hover, - border_visible, + Optional<bool> border_visible, border_drop_shadow_visible, bg_visible, use_ellipses, @@ -65,7 +65,6 @@ public: length; Optional<LLUIColor> text_color, - hover_color, disabled_color, background_color, border_color; @@ -90,15 +89,14 @@ public: virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen); void setColor( const LLColor4& c ) { mTextColor = c; } void setDisabledColor( const LLColor4& c) { mDisabledColor = c; } void setBackgroundColor( const LLColor4& c) { mBackgroundColor = c; } void setBorderColor( const LLColor4& c) { mBorderColor = c; } - void setHoverColor( const LLColor4& c ) { mHoverColor = c; } - void setHoverActive( BOOL active ) { mHoverActive = active; } - void setText( const LLStringExplicit& text ); void setWrappedText(const LLStringExplicit& text, F32 max_width = -1.f); // -1 means use existing control width void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } @@ -112,35 +110,42 @@ public: void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); } // mouse down and up within button - const LLFontGL* getFont() const { return mFontGL; } + const LLFontGL* getFont() const { return mDefaultFont; } void reshapeToFitText(); const std::string& getText() const { return mText.getString(); } + LLWString getWText() const { return mDisplayText; } S32 getTextPixelWidth(); S32 getTextPixelHeight(); + S32 getLength() const { return mDisplayText.length(); } virtual void setValue(const LLSD& value ); virtual LLSD getValue() const { return LLSD(getText()); } virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); -private: +protected: + S32 getLineCount() const { return mLineLengthList.size(); } + S32 getLineStart( S32 line ) const; + S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const; + LLWString getWrappedText(const LLStringExplicit& in_text, F32 max_width = -1.f); void setLineLengths(); - void drawText(S32 x, S32 y, const LLColor4& color ); + void updateDisplayTextAndSegments(); + virtual void drawText(S32 x, S32 y, const LLWString &text, const LLColor4& color ); + void onUrlLabelUpdated(const std::string &url, const std::string &label); + bool isClickable() const; + LLWString wrapText(const LLWString &wtext, S32 &hoffset, S32 &line_num, F32 max_width); + void drawTextSegments(S32 x, S32 y, const LLWString &text); LLUIString mText; - const LLFontGL* mFontGL; - LLUIColor mTextColor; - LLUIColor mDisabledColor; - LLUIColor mBackgroundColor; - LLUIColor mBorderColor; - LLUIColor mHoverColor; - - BOOL mHoverActive; - BOOL mHasHover; + LLWString mDisplayText; + LLUIColor mTextColor; + LLUIColor mDisabledColor; + LLUIColor mBackgroundColor; + LLUIColor mBorderColor; + BOOL mBackgroundVisible; BOOL mBorderVisible; - BOOL mWordWrap; BOOL mDidWordWrap; LLFontGL::ShadowType mShadowType; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 921041d17f..51c259ff53 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -59,6 +59,7 @@ #include "lltextparser.h" #include "llscrollcontainer.h" #include "llpanel.h" +#include "llurlregistry.h" #include <queue> #include "llcombobox.h" @@ -78,10 +79,6 @@ const S32 CURSOR_THICKNESS = 2; const S32 SPACES_PER_TAB = 4; -void (* LLTextEditor::sURLcallback)(const std::string&) = NULL; -bool (* LLTextEditor::sSecondlifeURLcallback)(const std::string&) = NULL; -bool (* LLTextEditor::sSecondlifeURLcallbackRightClick)(const std::string&) = NULL; - // helper functors struct LLTextEditor::compare_bottom { @@ -331,8 +328,9 @@ LLTextEditor::Params::Params() is_unicode("is_unicode")// ignored {} -LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) - : LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)), +LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : + LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)), + LLTextBase(p), mMaxTextByteLength( p.max_text_length ), mBaseDocIsPristine(TRUE), mPristineCmd( NULL ), @@ -351,7 +349,6 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) mFocusBgColor( p.bg_focus_color() ), mLinkColor( p.link_color() ), mReadOnly(p.read_only), - mWordWrap( p.word_wrap ), mShowLineNumbers ( p.show_line_numbers ), mCommitOnFocusLost( p.commit_on_focus_lost), mTrackBottom( p.track_bottom ), @@ -363,14 +360,16 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) mReflowNeeded(FALSE), mScrollNeeded(FALSE), mLastSelectionY(-1), - mParseHTML(FALSE), mParseHighlights(FALSE), mTabsToNextField(p.ignore_tab), - mDefaultFont(p.font), mScrollIndex(-1) { static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); + mWordWrap = p.word_wrap; + mDefaultFont = p.font; + mParseHTML = FALSE; + mSourceID.generate(); // reset desired x cursor position @@ -413,7 +412,6 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) appendText(p.default_text, FALSE, FALSE); - mHTML.clear(); } void LLTextEditor::initFromParams( const LLTextEditor::Params& p) @@ -451,7 +449,6 @@ LLTextEditor::~LLTextEditor() } // Scrollbar is deleted by LLView - mHoverSegment = NULL; std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); } @@ -666,18 +663,12 @@ BOOL LLTextEditor::truncate() return did_truncate; } -void LLTextEditor::clearSegments() -{ - mHoverSegment = NULL; - mSegments.clear(); -} - void LLTextEditor::setText(const LLStringExplicit &utf8str) { + // clear out the existing text and segments clearSegments(); - // LLStringUtil::removeCRLF(utf8str); - getViewModel()->setValue(utf8str_removeCRLF(utf8str)); + getViewModel()->setValue(""); truncate(); blockUndo(); @@ -687,6 +678,11 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str) startOfDoc(); deselect(); + // append the new text (supports Url linking) + std::string text(utf8str); + LLStringUtil::removeCRLF(text); + appendStyledText(text, false, false, LLStyle::Params()); + needsReflow(); resetDirty(); @@ -696,9 +692,10 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str) void LLTextEditor::setWText(const LLWString &wtext) { + // clear out the existing text and segments clearSegments(); - getViewModel()->setDisplay(wtext); + getViewModel()->setDisplay(LLWString()); truncate(); blockUndo(); @@ -708,6 +705,9 @@ void LLTextEditor::setWText(const LLWString &wtext) startOfDoc(); deselect(); + // append the new text (supports Url linking) + appendStyledText(wstring_to_utf8str(wtext), false, false, LLStyle::Params()); + needsReflow(); resetDirty(); @@ -913,32 +913,6 @@ void LLTextEditor::getLineAndOffset( S32 startpos, S32* linep, S32* offsetp, boo } } -void LLTextEditor::getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const -{ - *seg_iter = getSegIterContaining(startpos); - if (*seg_iter == mSegments.end()) - { - *offsetp = 0; - } - else - { - *offsetp = startpos - (**seg_iter)->getStart(); - } -} - -void LLTextEditor::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ) -{ - *seg_iter = getSegIterContaining(startpos); - if (*seg_iter == mSegments.end()) - { - *offsetp = 0; - } - else - { - *offsetp = startpos - (**seg_iter)->getStart(); - } -} - const LLTextSegmentPtr LLTextEditor::getPreviousSegment() const { // find segment index at character to left of cursor (or rightmost edge of selection) @@ -1154,6 +1128,10 @@ S32 LLTextEditor::getEditableIndex(S32 index, bool increasing_direction) segment_set_t::iterator segment_iter; S32 offset; getSegmentAndOffset(index, &segment_iter, &offset); + if (segment_iter == mSegments.end()) + { + return 0; + } LLTextSegmentPtr segmentp = *segment_iter; @@ -1377,25 +1355,7 @@ BOOL LLTextEditor::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_ } } - const LLTextSegmentPtr cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment ) - { - BOOL has_tool_tip = FALSE; - has_tool_tip = cur_segment->getToolTip( msg ); - - if( has_tool_tip ) - { - // Just use a slop area around the cursor - // Convert rect local to screen coordinates - S32 SLOP = 8; - localPointToScreen( - x - SLOP, y - SLOP, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; - sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; - } - } - return TRUE; + return handleToolTipForUrl(this, x, y, msg, sticky_rect_screen); } BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) @@ -1480,12 +1440,6 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0); BOOL handled = FALSE; - if (mHoverSegment) - { - mHoverSegment->setHasMouseHover(false); - } - mHoverSegment = NULL; - if(hasMouseCapture() ) { if( mIsSelecting ) @@ -1525,30 +1479,11 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) if( !handled ) { // Check to see if we're over an HTML-style link - LLTextSegmentPtr cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment ) + handled = handleHoverOverUrl(x, y); + if( handled ) { - if(cur_segment->getStyle()->isLink()) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over link, inactive)" << llendl; - getWindow()->setCursor(UI_CURSOR_HAND); - handled = TRUE; - } - //else - //if(cur_segment->getStyle()->getIsEmbeddedItem()) - //{ - // lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over embedded item, inactive)" << llendl; - // getWindow()->setCursor(UI_CURSOR_HAND); - // //getWindow()->setCursor(UI_CURSOR_ARROW); - // handled = TRUE; - //} - if (mHoverSegment) - { - mHoverSegment->setHasMouseHover(false); - } - cur_segment->setHasMouseHover(true); - mHoverSegment = cur_segment; - mHTML = mHoverSegment->getStyle()->getLinkHREF(); + lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; + getWindow()->setCursor(UI_CURSOR_HAND); } if( !handled ) @@ -1581,9 +1516,9 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) endSelection(); } - if( !hasSelection() ) + if( !hasSelection() && hasMouseCapture() ) { - handleMouseUpOverSegment( x, y, mask ); + handleMouseUpOverUrl(x, y); } // take selection to 'primary' clipboard @@ -3477,11 +3412,8 @@ void LLTextEditor::endOfDoc() // Sets the scrollbar from the cursor position void LLTextEditor::updateScrollFromCursor() { - if (mReadOnly) - { - // no cursor in read only mode - return; - } + // Update scroll position even in read-only mode (when there's no cursor displayed) + // because startOfDoc()/endOfDoc() modify cursor position. See EXT-736. if (!mScrollNeeded) { @@ -3596,14 +3528,20 @@ void LLTextEditor::appendStyledText(const std::string &new_text, { S32 start=0,end=0; + LLUrlMatch match; std::string text = new_text; - while ( findHTML(text, &start, &end) ) + while ( LLUrlRegistry::instance().findUrl(text, match, + boost::bind(&LLTextEditor::onUrlLabelUpdated, this, _1, _2)) ) { + start = match.getStart(); + end = match.getEnd()+1; + LLStyle::Params link_params = style_params; link_params.color = mLinkColor; link_params.font.style = "UNDERLINE"; - link_params.link_href = text.substr(start,end-start); + link_params.link_href = match.getUrl(); + // output the text before the Url if (start > 0) { if (part == (S32)LLTextParser::WHOLE || @@ -3617,9 +3555,38 @@ void LLTextEditor::appendStyledText(const std::string &new_text, } std::string subtext=text.substr(0,start); appendHighlightedText(subtext,allow_undo, prepend_newline, part, style_params); + prepend_newline = false; } - - appendText(text.substr(start, end-start),allow_undo, prepend_newline, link_params); + + // output the styled Url + appendText(match.getLabel(),allow_undo, prepend_newline, link_params); + prepend_newline = false; + + // set the tooltip for the Url label + if (! match.getTooltip().empty()) + { + segment_set_t::iterator it = getSegIterContaining(getLength()-1); + if (it != mSegments.end()) + { + LLTextSegmentPtr segment = *it; + segment->setToolTip(match.getTooltip()); + } + } + + // output an optional icon after the Url + if (! match.getIcon().empty()) + { + LLUIImagePtr image = LLUI::getUIImage(match.getIcon()); + if (image) + { + LLStyle::Params icon; + icon.image = image; + // TODO: fix spacing of images and remove the fixed char spacing + appendText(" ", allow_undo, prepend_newline, icon); + } + } + + // move on to the rest of the text after the Url if (end < (S32)text.length()) { text = text.substr(end,text.length() - end); @@ -3711,7 +3678,7 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool } append(wide_text, TRUE, segmentp); - + needsReflow(); // Set the cursor and scroll position @@ -3795,6 +3762,58 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, } } +void LLTextEditor::onUrlLabelUpdated(const std::string &url, + const std::string &label) +{ + // LLUrlRegistry has given us a new label for one of our Urls + replaceUrlLabel(url, label); +} + +void LLTextEditor::replaceUrlLabel(const std::string &url, + const std::string &label) +{ + // get the full (wide) text for the editor so we can change it + LLWString text = getWText(); + LLWString wlabel = utf8str_to_wstring(label); + bool modified = false; + S32 seg_start = 0; + + // iterate through each segment looking for ones styled as links + segment_set_t::iterator it; + for (it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegment *seg = *it; + const LLStyleSP style = seg->getStyle(); + + // update segment start/end length in case we replaced text earlier + S32 seg_length = seg->getEnd() - seg->getStart(); + seg->setStart(seg_start); + seg->setEnd(seg_start + seg_length); + + // if we find a link with our Url, then replace the label + if (style->isLink() && style->getLinkHREF() == url) + { + S32 start = seg->getStart(); + S32 end = seg->getEnd(); + text = text.substr(0, start) + wlabel + text.substr(end, text.size() - end + 1); + seg->setEnd(start + wlabel.size()); + modified = true; + } + + // work out the character offset for the next segment + seg_start = seg->getEnd(); + } + + // update the editor with the new (wide) text string + if (modified) + { + getViewModel()->setDisplay(text); + deselect(); + setCursorPos(mCursorPos); + needsReflow(); + } +} + void LLTextEditor::removeTextFromEnd(S32 num_chars) { if (num_chars <= 0) return; @@ -4097,7 +4116,7 @@ void LLTextEditor::updateSegments() segment_vec_t segment_list; mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this); - mSegments.clear(); + clearSegments(); segment_set_t::iterator insert_it = mSegments.begin(); for (segment_vec_t::iterator list_it = segment_list.begin(); list_it != segment_list.end(); ++list_it) { @@ -4106,7 +4125,29 @@ void LLTextEditor::updateSegments() } createDefaultSegment(); +} +void LLTextEditor::updateLinkSegments() +{ + // update any segments that contain a link + for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegment *segment = *it; + if (segment && segment->getStyle() && segment->getStyle()->isLink()) + { + // if the link's label (what the user can edit) is a valid Url, + // then update the link's HREF to be the same as the label text. + // This lets users edit Urls in-place. + LLUrlMatch match; + LLStyleSP style = static_cast<LLStyleSP>(segment->getStyle()); + std::string url_label = getText().substr(segment->getStart(), segment->getEnd()-segment->getStart()); + if (LLUrlRegistry::instance().findUrl(url_label, match)) + { + LLStringUtil::trim(url_label); + style->setLinkHREF(url_label); + } + } + } } void LLTextEditor::insertSegment(LLTextSegmentPtr segment_to_insert) @@ -4170,57 +4211,6 @@ void LLTextEditor::insertSegment(LLTextSegmentPtr segment_to_insert) } } -BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask) -{ - if ( hasMouseCapture() ) - { - // This mouse up was part of a click. - // Regardless of where the cursor is, see if we recently touched a link - // and launch it if we did. - if (mParseHTML && mHTML.length() > 0) - { - //Special handling for slurls - if ( (sSecondlifeURLcallback!=NULL) && !(*sSecondlifeURLcallback)(mHTML) ) - { - if (sURLcallback!=NULL) (*sURLcallback)(mHTML); - } - mHTML.clear(); - } - } - - return FALSE; -} - - -// Finds the text segment (if any) at the give local screen position -LLTextSegmentPtr LLTextEditor::getSegmentAtLocalPos( S32 x, S32 y ) -{ - // Find the cursor position at the requested local screen position - S32 offset = getDocIndexFromLocalCoord( x, y, FALSE ); - segment_set_t::iterator seg_iter = getSegIterContaining(offset); - if (seg_iter != mSegments.end()) - { - return *seg_iter; - } - else - { - return LLTextSegmentPtr(); - } -} - -LLTextEditor::segment_set_t::iterator LLTextEditor::getSegIterContaining(S32 index) -{ - segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index)); - return it; -} - -LLTextEditor::segment_set_t::const_iterator LLTextEditor::getSegIterContaining(S32 index) const -{ - LLTextEditor::segment_set_t::const_iterator it = mSegments.upper_bound(new LLIndexSegment(index)); - return it; -} - - void LLTextEditor::onMouseCaptureLost() { endSelection(); @@ -4330,169 +4320,6 @@ BOOL LLTextEditor::exportBuffer(std::string &buffer ) return TRUE; } -/////////////////////////////////////////////////////////////////// -// Refactoring note: We may eventually want to replace this with boost::regex or -// boost::tokenizer capabilities since we've already fixed at least two JIRAs -// concerning logic issues associated with this function. -S32 LLTextEditor::findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const -{ - std::string openers=" \t\n('\"[{<>"; - std::string closers=" \t\n)'\"]}><;"; - - if (reverse) - { - for (int index=pos; index >= 0; index--) - { - char c = line[index]; - S32 m2 = openers.find(c); - if (m2 >= 0) - { - return index+1; - } - } - return 0; // index is -1, don't want to return that. - } - else - { - // adjust the search slightly, to allow matching parenthesis inside the URL - S32 paren_count = 0; - for (int index=pos; index<(S32)line.length(); index++) - { - char c = line[index]; - - if (c == '(') - { - paren_count++; - } - else if (c == ')') - { - if (paren_count <= 0) - { - return index; - } - else - { - paren_count--; - } - } - else - { - S32 m2 = closers.find(c); - if (m2 >= 0) - { - return index; - } - } - } - return line.length(); - } -} - -BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const -{ - - S32 m1,m2,m3; - BOOL matched = FALSE; - - m1=line.find("://",*end); - - if (m1 >= 0) //Easy match. - { - *begin = findHTMLToken(line, m1, TRUE); - *end = findHTMLToken(line, m1, FALSE); - - //Load_url only handles http and https so don't hilite ftp, smb, etc. - m2 = line.substr(*begin,(m1 - *begin)).find("http"); - m3 = line.substr(*begin,(m1 - *begin)).find("secondlife"); - - std::string badneighbors=".,<>?';\"][}{=-+_)(*&^%$#@!~`\t\r\n\\"; - - if (m2 >= 0 || m3>=0) - { - S32 bn = badneighbors.find(line.substr(m1+3,1)); - - if (bn < 0) - { - matched = TRUE; - } - } - } -/* matches things like secondlife.com (no http://) needs a whitelist to really be effective. - else //Harder match. - { - m1 = line.find(".",*end); - - if (m1 >= 0) - { - *end = findHTMLToken(line, m1, FALSE); - *begin = findHTMLToken(line, m1, TRUE); - - m1 = line.rfind(".",*end); - - if ( ( *end - m1 ) > 2 && m1 > *begin) - { - std::string badneighbors=".,<>/?';\"][}{=-+_)(*&^%$#@!~`"; - m2 = badneighbors.find(line.substr(m1+1,1)); - m3 = badneighbors.find(line.substr(m1-1,1)); - if (m3<0 && m2<0) - { - matched = TRUE; - } - } - } - } - */ - - if (matched) - { - S32 strpos, strpos2; - - std::string url = line.substr(*begin,*end - *begin); - std::string slurlID = "slurl.com/secondlife/"; - strpos = url.find(slurlID); - - if (strpos < 0) - { - slurlID="secondlife://"; - strpos = url.find(slurlID); - } - - if (strpos < 0) - { - slurlID="sl://"; - strpos = url.find(slurlID); - } - - if (strpos >= 0) - { - strpos+=slurlID.length(); - - while ( ( strpos2=url.find("/",strpos) ) == -1 ) - { - if ((*end+2) >= (S32)line.length() || line.substr(*end,1) != " " ) - { - matched=FALSE; - break; - } - - strpos = (*end + 1) - *begin; - - *end = findHTMLToken(line,(*begin + strpos),FALSE); - url = line.substr(*begin,*end - *begin); - } - } - - } - - if (!matched) - { - *begin=*end=0; - } - return matched; -} - - - void LLTextEditor::updateAllowingLanguageInput() { LLWindow* window = getWindow(); @@ -4754,193 +4581,6 @@ void LLTextEditor::onValueChange(S32 start, S32 end) } // -// LLTextSegment -// - -LLTextSegment::~LLTextSegment() -{} - -S32 LLTextSegment::getWidth(S32 first_char, S32 num_chars) const { return 0; } -S32 LLTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return 0; } -S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const { return 0; } -void LLTextSegment::updateLayout(const LLTextEditor& editor) {} -F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) { return draw_rect.mLeft; } -S32 LLTextSegment::getMaxHeight() const { return 0; } -bool LLTextSegment::canEdit() const { return false; } -void LLTextSegment::unlinkFromDocument(LLTextEditor*) {} -void LLTextSegment::linkToDocument(LLTextEditor*) {} -void LLTextSegment::setHasMouseHover(bool hover) {} -const LLColor4& LLTextSegment::getColor() const { return LLColor4::white; } -void LLTextSegment::setColor(const LLColor4 &color) {} -const LLStyleSP LLTextSegment::getStyle() const {static LLStyleSP sp(new LLStyle()); return sp; } -void LLTextSegment::setStyle(const LLStyleSP &style) {} -void LLTextSegment::setToken( LLKeywordToken* token ) {} -LLKeywordToken* LLTextSegment::getToken() const { return NULL; } -BOOL LLTextSegment::getToolTip( std::string& msg ) const { return FALSE; } -void LLTextSegment::dump() const {} - - -// -// LLNormalTextSegment -// - -LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextEditor& editor ) -: LLTextSegment(start, end), - mStyle( style ), - mToken(NULL), - mHasMouseHover(false), - mEditor(editor) -{ - mMaxHeight = llceil(mStyle->getFont()->getLineHeight()); -} - -LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextEditor& editor, BOOL is_visible) -: LLTextSegment(start, end), - mToken(NULL), - mHasMouseHover(false), - mEditor(editor) -{ - mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color)); - - mMaxHeight = llceil(mStyle->getFont()->getLineHeight()); -} - -F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) -{ - if( end - start > 0 ) - { - if ( mStyle->isImage() && (start >= 0) && (end <= mEnd - mStart)) - { - S32 style_image_height = mStyle->mImageHeight; - S32 style_image_width = mStyle->mImageWidth; - LLUIImagePtr image = mStyle->getImage(); - image->draw(draw_rect.mLeft, draw_rect.mTop-style_image_height, - style_image_width, style_image_height); - } - - return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect.mLeft, draw_rect.mBottom); - } - return draw_rect.mLeft; -} - -// Draws a single text segment, reversing the color for selection if needed. -F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, F32 x, F32 y) -{ - const LLWString &text = mEditor.getWText(); - - F32 right_x = x; - if (!mStyle->isVisible()) - { - return right_x; - } - - const LLFontGL* font = mStyle->getFont(); - - LLColor4 color = mStyle->getColor(); - - font = mStyle->getFont(); - - if( selection_start > seg_start ) - { - // Draw normally - S32 start = seg_start; - S32 end = llmin( selection_start, seg_end ); - S32 length = end - start; - font->render(text, start, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems()); - } - x = right_x; - - if( (selection_start < seg_end) && (selection_end > seg_start) ) - { - // Draw reversed - S32 start = llmax( selection_start, seg_start ); - S32 end = llmin( selection_end, seg_end ); - S32 length = end - start; - - font->render(text, start, x, y, - LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ), - LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems()); - } - x = right_x; - if( selection_end < seg_end ) - { - // Draw normally - S32 start = llmax( selection_end, seg_start ); - S32 end = seg_end; - S32 length = end - start; - font->render(text, start, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems()); - } - return right_x; -} - -S32 LLNormalTextSegment::getMaxHeight() const -{ - return mMaxHeight; -} - -BOOL LLNormalTextSegment::getToolTip(std::string& msg) const -{ - if (mToken && !mToken->getToolTip().empty()) - { - const LLWString& wmsg = mToken->getToolTip(); - msg = wstring_to_utf8str(wmsg); - return TRUE; - } - return FALSE; -} - - -S32 LLNormalTextSegment::getWidth(S32 first_char, S32 num_chars) const -{ - LLWString text = mEditor.getWText(); - return mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); -} - -S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const -{ - LLWString text = mEditor.getWText(); - return mStyle->getFont()->charFromPixelOffset(text.c_str(), mStart + start_offset, - (F32)segment_local_x_coord, - F32_MAX, - num_chars, - round); -} - -S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const -{ - LLWString text = mEditor.getWText(); - S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart, - (F32)num_pixels, - max_chars, - mEditor.getWordWrap()); - - if (num_chars == 0 - && line_offset == 0 - && max_chars > 0) - { - // If at the beginning of a line, and a single character won't fit, draw it anyway - num_chars = 1; - } - if (mStart + segment_offset + num_chars == mEditor.getLength()) - { - // include terminating NULL - num_chars++; - } - return num_chars; -} - -void LLNormalTextSegment::dump() const -{ - llinfos << "Segment [" << -// mColor.mV[VX] << ", " << -// mColor.mV[VY] << ", " << -// mColor.mV[VZ] << "]\t[" << - mStart << ", " << - getEnd() << "]" << - llendl; -} - -// // LLInlineViewSegment // @@ -4979,11 +4619,15 @@ S32 LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin } } -void LLInlineViewSegment::updateLayout(const LLTextEditor& editor) +void LLInlineViewSegment::updateLayout(const LLTextBase& editor) { - LLRect start_rect = editor.getLocalRectFromDocIndex(mStart); - LLRect doc_rect = editor.getDocumentPanel()->getRect(); - mView->setOrigin(doc_rect.mLeft + start_rect.mLeft, doc_rect.mBottom + start_rect.mBottom); + const LLTextEditor *ed = dynamic_cast<const LLTextEditor *>(&editor); + if (ed) + { + LLRect start_rect = ed->getLocalRectFromDocIndex(mStart); + LLRect doc_rect = ed->getDocumentPanel()->getRect(); + mView->setOrigin(doc_rect.mLeft + start_rect.mLeft, doc_rect.mBottom + start_rect.mBottom); + } } F32 LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) @@ -4996,12 +4640,20 @@ S32 LLInlineViewSegment::getMaxHeight() const return mView->getRect().getHeight(); } -void LLInlineViewSegment::unlinkFromDocument(LLTextEditor* editor) +void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor) { - editor->removeDocumentChild(mView); + LLTextEditor *ed = dynamic_cast<LLTextEditor *>(editor); + if (ed) + { + ed->removeDocumentChild(mView); + } } -void LLInlineViewSegment::linkToDocument(LLTextEditor* editor) +void LLInlineViewSegment::linkToDocument(LLTextBase* editor) { - editor->addDocumentChild(mView); + LLTextEditor *ed = dynamic_cast<LLTextEditor *>(editor); + if (ed) + { + ed->addDocumentChild(mView); + } } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 67c67d0f67..d537751130 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -44,6 +44,7 @@ #include "lleditmenuhandler.h" #include "lldarray.h" #include "llviewborder.h" // for params +#include "lltextbase.h" #include "llpreeditor.h" #include "llcontrol.h" @@ -55,76 +56,6 @@ class LLTextCmd; class LLUICtrlFactory; class LLScrollContainer; -class LLTextSegment : public LLRefCount -{ -public: - LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){}; - virtual ~LLTextSegment(); - - virtual S32 getWidth(S32 first_char, S32 num_chars) const; - virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; - virtual S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; - virtual void updateLayout(const class LLTextEditor& editor); - virtual F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); - virtual S32 getMaxHeight() const; - virtual bool canEdit() const; - virtual void unlinkFromDocument(class LLTextEditor* editor); - virtual void linkToDocument(class LLTextEditor* editor); - - virtual void setHasMouseHover(bool hover); - virtual const LLColor4& getColor() const; - virtual void setColor(const LLColor4 &color); - virtual const LLStyleSP getStyle() const; - virtual void setStyle(const LLStyleSP &style); - virtual void setToken( LLKeywordToken* token ); - virtual LLKeywordToken* getToken() const; - virtual BOOL getToolTip( std::string& msg ) const; - virtual void dump() const; - - S32 getStart() const { return mStart; } - void setStart(S32 start) { mStart = start; } - S32 getEnd() const { return mEnd; } - void setEnd( S32 end ) { mEnd = end; } - -protected: - S32 mStart; - S32 mEnd; -}; - -class LLNormalTextSegment : public LLTextSegment -{ -public: - LLNormalTextSegment( const LLStyleSP& style, S32 start, S32 end, LLTextEditor& editor ); - LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextEditor& editor, BOOL is_visible = TRUE); - - /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const; - /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; - /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; - /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); - /*virtual*/ S32 getMaxHeight() const; - /*virtual*/ bool canEdit() const { return true; } - /*virtual*/ void setHasMouseHover(bool hover) { mHasMouseHover = hover; } - /*virtual*/ const LLColor4& getColor() const { return mStyle->getColor(); } - /*virtual*/ void setColor(const LLColor4 &color) { mStyle->setColor(color); } - /*virtual*/ const LLStyleSP getStyle() const { return mStyle; } - /*virtual*/ void setStyle(const LLStyleSP &style) { mStyle = style; } - /*virtual*/ void setToken( LLKeywordToken* token ) { mToken = token; } - /*virtual*/ LLKeywordToken* getToken() const { return mToken; } - /*virtual*/ BOOL getToolTip( std::string& msg ) const; - /*virtual*/ void dump() const; - -protected: - F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, F32 x, F32 y); - - class LLTextEditor& mEditor; - LLStyleSP mStyle; - S32 mMaxHeight; - LLKeywordToken* mToken; - bool mHasMouseHover; -}; - -typedef LLPointer<LLTextSegment> LLTextSegmentPtr; - class LLInlineViewSegment : public LLTextSegment { public: @@ -132,24 +63,22 @@ public: ~LLInlineViewSegment(); /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const; /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; - /*virtual*/ void updateLayout(const class LLTextEditor& editor); + /*virtual*/ void updateLayout(const class LLTextBase& editor); /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect); /*virtuaL*/ S32 getMaxHeight() const; /*virtual*/ bool canEdit() const { return false; } - /*virtual*/ void unlinkFromDocument(class LLTextEditor* editor); - /*virtual*/ void linkToDocument(class LLTextEditor* editor); + /*virtual*/ void unlinkFromDocument(class LLTextBase* editor); + /*virtual*/ void linkToDocument(class LLTextBase* editor); private: LLView* mView; }; -class LLIndexSegment : public LLTextSegment -{ -public: - LLIndexSegment(S32 pos) : LLTextSegment(pos, pos) {} -}; - -class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor +class LLTextEditor : + public LLTextBase, + public LLUICtrl, + private LLEditMenuHandler, + protected LLPreeditor { public: struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> @@ -208,11 +137,8 @@ public: } }; - typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t; - virtual ~LLTextEditor(); - void setParseHTML(BOOL parsing) {mParseHTML=parsing;} void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} // mousehandler overrides @@ -277,6 +203,7 @@ public: BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); void replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive); BOOL hasSelection() const { return (mSelectionStart !=mSelectionEnd); } + void replaceUrlLabel(const std::string &url, const std::string &label); // Undo/redo stack void blockUndo(); @@ -285,7 +212,6 @@ public: virtual void makePristine(); BOOL isPristine() const; BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } - BOOL getWordWrap() { return mWordWrap; } S32 getLength() const { return getWText().length(); } void setReadOnly(bool read_only) { mReadOnly = read_only; } bool getReadOnly() { return mReadOnly; } @@ -352,13 +278,11 @@ public: const LLUUID& getSourceID() const { return mSourceID; } // Callbacks - static void setURLCallbacks(void (*callback1) (const std::string& url), - bool (*callback2) (const std::string& url), - bool (*callback3) (const std::string& url) ) - { sURLcallback = callback1; sSecondlifeURLcallback = callback2; sSecondlifeURLcallbackRightClick = callback3;} - std::string getText() const; + // Callback for when a Url has been resolved by the server + void onUrlLabelUpdated(const std::string &url, const std::string &label); + // Getters LLWString getWText() const; llwchar getWChar(S32 pos) const { return getWText()[pos]; } @@ -382,8 +306,6 @@ protected: void startOfDoc(); void endOfDoc(); - void getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const; - void getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp ) ; void drawPreeditMarker(); void needsReflow() { mReflowNeeded = TRUE; } @@ -399,16 +321,12 @@ protected: void removeCharOrTab(); void setCursorAtLocalPos(S32 x, S32 y, bool round, bool keep_cursor_offset = false); - S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const; + /*virtual*/ S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const; void indentSelectedLines( S32 spaces ); S32 indentLine( S32 pos, S32 spaces ); void unindentLineBeforeCloseBrace(); - LLTextSegmentPtr getSegmentAtLocalPos(S32 x, S32 y); - segment_set_t::iterator getSegIterContaining(S32 index); - segment_set_t::const_iterator getSegIterContaining(S32 index) const; - void reportBadKeystroke() { make_ui_sound("UISndBadKeystroke"); } BOOL handleNavigationKey(const KEY key, const MASK mask); @@ -438,15 +356,9 @@ protected: void findEmbeddedItemSegments(S32 start, S32 end); void insertSegment(LLTextSegmentPtr segment_to_insert); - - virtual BOOL handleMouseUpOverSegment(S32 x, S32 y, MASK mask); - virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } - S32 findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const; - BOOL findHTML(const std::string &line, S32 *begin, S32 *end) const; - // Abstract inner base class representing an undoable editor command. // Concrete sub-classes can be defined for operations such as insert, remove, etc. // Used as arguments to the execute() method below. @@ -538,13 +450,8 @@ protected: S32 mLastSelectionX; S32 mLastSelectionY; - BOOL mParseHTML; BOOL mParseHighlights; - std::string mHTML; - segment_set_t mSegments; - LLTextSegmentPtr mHoverSegment; - // Scrollbar data class DocumentPanel* mDocumentPanel; LLScrollContainer* mScroller; @@ -569,10 +476,10 @@ protected: LLUIColor mLinkColor; BOOL mReadOnly; - BOOL mWordWrap; BOOL mShowLineNumbers; void updateSegments(); + void updateLinkSegments(); private: @@ -584,7 +491,6 @@ private: virtual LLTextViewModel* getViewModel() const; void reflow(S32 startpos = 0); - void clearSegments(); void createDefaultSegment(); LLStyleSP getDefaultStyle(); S32 getEditableIndex(S32 index, bool increasing_direction); @@ -601,9 +507,6 @@ private: // Data // LLKeywords mKeywords; - static void (*sURLcallback) (const std::string& url); - static bool (*sSecondlifeURLcallback) (const std::string& url); - static bool (*sSecondlifeURLcallbackRightClick) (const std::string& url); // Concrete LLTextCmd sub-classes used by the LLTextEditor base class class LLTextCmdInsert; @@ -613,8 +516,6 @@ private: S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes - const LLFontGL* mDefaultFont; - class LLViewBorder* mBorder; BOOL mBaseDocIsPristine; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 7ff942268d..1ab04054ff 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -257,6 +257,13 @@ BOOL LLUICtrl::handleRightMouseUp(S32 x, S32 y, MASK mask) return handled; } +BOOL LLUICtrl::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleDoubleClick(x, y, mask); + mDoubleClickSignal(this, x, y, mask); + return handled; +} + // can't tab to children of a non-tab-stop widget BOOL LLUICtrl::canFocusChildren() const { diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 3e2e1f41a1..5011adcfe9 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -166,6 +166,7 @@ public: /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); // From LLFocusableElement /*virtual*/ void setFocus( BOOL b ); @@ -239,6 +240,8 @@ public: boost::signals2::connection setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ) { return mRightMouseDownSignal.connect(cb); } boost::signals2::connection setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ) { return mRightMouseUpSignal.connect(cb); } + boost::signals2::connection setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) { return mDoubleClickSignal.connect(cb); } + // *TODO: Deprecate; for backwards compatability only: boost::signals2::connection setCommitCallback( boost::function<void (LLUICtrl*,void*)> cb, void* data); boost::signals2::connection setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb ); @@ -273,6 +276,8 @@ protected: mouse_signal_t mMouseUpSignal; mouse_signal_t mRightMouseDownSignal; mouse_signal_t mRightMouseUpSignal; + + mouse_signal_t mDoubleClickSignal; LLViewModelPtr mViewModel; diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp new file mode 100644 index 0000000000..3b689b93c0 --- /dev/null +++ b/indra/llui/llurlaction.cpp @@ -0,0 +1,137 @@ +/** + * @file llurlaction.cpp + * @author Martin Reddy + * @brief A set of actions that can performed on Urls + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llurlaction.h" +#include "llview.h" +#include "llwindow.h" +#include "llurlregistry.h" + +// global state for the callback functions +void (*LLUrlAction::sOpenURLCallback) (const std::string& url) = NULL; +void (*LLUrlAction::sOpenURLInternalCallback) (const std::string& url) = NULL; +void (*LLUrlAction::sOpenURLExternalCallback) (const std::string& url) = NULL; +bool (*LLUrlAction::sExecuteSLURLCallback) (const std::string& url) = NULL; + + +void LLUrlAction::setOpenURLCallback(void (*cb) (const std::string& url)) +{ + sOpenURLCallback = cb; +} + +void LLUrlAction::setOpenURLInternalCallback(void (*cb) (const std::string& url)) +{ + sOpenURLInternalCallback = cb; +} + +void LLUrlAction::setOpenURLExternalCallback(void (*cb) (const std::string& url)) +{ + sOpenURLExternalCallback = cb; +} + +void LLUrlAction::setExecuteSLURLCallback(bool (*cb) (const std::string& url)) +{ + sExecuteSLURLCallback = cb; +} + +void LLUrlAction::openURL(std::string url) +{ + if (sOpenURLCallback) + { + (*sOpenURLCallback)(url); + } +} + +void LLUrlAction::openURLInternal(std::string url) +{ + if (sOpenURLInternalCallback) + { + (*sOpenURLInternalCallback)(url); + } +} + +void LLUrlAction::openURLExternal(std::string url) +{ + if (sOpenURLExternalCallback) + { + (*sOpenURLExternalCallback)(url); + } +} + +void LLUrlAction::executeSLURL(std::string url) +{ + if (sExecuteSLURLCallback) + { + (*sExecuteSLURLCallback)(url); + } +} + +void LLUrlAction::clickAction(std::string url) +{ + // Try to handle as SLURL first, then http Url + if ( (sExecuteSLURLCallback) && !(*sExecuteSLURLCallback)(url) ) + { + if (sOpenURLCallback) + { + (*sOpenURLCallback)(url); + } + } +} + +void LLUrlAction::teleportToLocation(std::string url) +{ + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + if (! match.getLocation().empty()) + { + executeSLURL("secondlife:///app/teleport/" + match.getLocation()); + } + } +} + +void LLUrlAction::copyURLToClipboard(std::string url) +{ + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url)); +} + +void LLUrlAction::copyLabelToClipboard(std::string url) +{ + LLUrlMatch match; + if (LLUrlRegistry::instance().findUrl(url, match)) + { + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); + } +} + diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h new file mode 100644 index 0000000000..6b9d565b44 --- /dev/null +++ b/indra/llui/llurlaction.h @@ -0,0 +1,93 @@ +/** + * @file llurlaction.h + * @author Martin Reddy + * @brief A set of actions that can performed on Urls + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLURLACTION_H +#define LL_LLURLACTION_H + +#include <string> + +/// +/// The LLUrlAction class provides a number of static functions that +/// let you open Urls in web browsers, execute SLURLs, and copy Urls +/// to the clipboard. Many of these functions are not available at +/// the llui level, and must be supplied via a set of callbacks. +/// +/// N.B. The action functions specifically do not use const ref +/// strings so that a url parameter can be used into a boost::bind() +/// call under situations when that input string is deallocated before +/// the callback is executed. +/// +class LLUrlAction +{ +public: + LLUrlAction(); + + /// load a Url in the user's preferred web browser + static void openURL(std::string url); + + /// load a Url in the internal Second Life web browser + static void openURLInternal(std::string url); + + /// load a Url in the operating system's default web browser + static void openURLExternal(std::string url); + + /// execute the given secondlife: SLURL + static void executeSLURL(std::string url); + + /// if the Url specifies an SL location, teleport there + static void teleportToLocation(std::string url); + + /// perform the appropriate action for left-clicking on a Url + static void clickAction(std::string url); + + /// copy the label for a Url to the clipboard + static void copyLabelToClipboard(std::string url); + + /// copy a Url to the clipboard + static void copyURLToClipboard(std::string url); + + /// specify the callbacks to enable this class's functionality + static void setOpenURLCallback(void (*cb) (const std::string& url)); + static void setOpenURLInternalCallback(void (*cb) (const std::string& url)); + static void setOpenURLExternalCallback(void (*cb) (const std::string& url)); + static void setExecuteSLURLCallback(bool (*cb) (const std::string& url)); + +private: + // callbacks for operations we can perform on Urls + static void (*sOpenURLCallback) (const std::string& url); + static void (*sOpenURLInternalCallback) (const std::string& url); + static void (*sOpenURLExternalCallback) (const std::string& url); + static bool (*sExecuteSLURLCallback) (const std::string& url); +}; + +#endif diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp new file mode 100644 index 0000000000..85f9064115 --- /dev/null +++ b/indra/llui/llurlentry.cpp @@ -0,0 +1,546 @@ +/** + * @file llurlentry.cpp + * @author Martin Reddy + * @brief Describes the Url types that can be registered in LLUrlRegistry + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llurlentry.h" +#include "lluri.h" +#include "llcachename.h" +#include "lltrans.h" + +LLUrlEntryBase::LLUrlEntryBase() +{ +} + +LLUrlEntryBase::~LLUrlEntryBase() +{ +} + +std::string LLUrlEntryBase::getUrl(const std::string &string) +{ + return escapeUrl(string); +} + +std::string LLUrlEntryBase::getIDStringFromUrl(const std::string &url) const +{ + // return the id from a SLURL in the format /app/{cmd}/{id}/about + LLURI uri(url); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + return path_array.get(2).asString(); + } + return ""; +} + +std::string LLUrlEntryBase::unescapeUrl(const std::string &url) const +{ + return LLURI::unescape(url); +} + +std::string LLUrlEntryBase::escapeUrl(const std::string &url) const +{ + static std::string no_escape_chars; + static bool initialized = false; + if (!initialized) + { + no_escape_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._~!$?&()*+,@:;=/%"; + + std::sort(no_escape_chars.begin(), no_escape_chars.end()); + initialized = true; + } + return LLURI::escape(url, no_escape_chars, true); +} + +std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url) +{ + // return the label part from [http://www.example.org Label] + const char *text = url.c_str(); + S32 start = 0; + while (! isspace(text[start])) + { + start++; + } + while (text[start] == ' ' || text[start] == '\t') + { + start++; + } + return url.substr(start, url.size()-start-1); +} + +std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) +{ + // return the url part from [http://www.example.org Label] + const char *text = string.c_str(); + S32 end = 0; + while (! isspace(text[end])) + { + end++; + } + return escapeUrl(string.substr(1, end-1)); +} + +void LLUrlEntryBase::addObserver(const std::string &id, + const std::string &url, + const LLUrlLabelCallback &cb) +{ + // add a callback to be notified when we have a label for the uuid + LLUrlEntryObserver observer; + observer.url = url; + observer.signal = new LLUrlLabelSignal(); + if (observer.signal) + { + observer.signal->connect(cb); + mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer)); + } +} + +void LLUrlEntryBase::callObservers(const std::string &id, const std::string &label) +{ + // notify all callbacks waiting on the given uuid + std::multimap<std::string, LLUrlEntryObserver>::iterator it; + for (it = mObservers.find(id); it != mObservers.end();) + { + // call the callback - give it the new label + LLUrlEntryObserver &observer = it->second; + (*observer.signal)(it->second.url, label); + // then remove the signal - we only need to call it once + delete observer.signal; + mObservers.erase(it++); + } +} + +// +// LLUrlEntryHTTP Describes generic http: and https: Urls +// +LLUrlEntryHTTP::LLUrlEntryHTTP() +{ + mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); + //mIcon = "gear.tga"; +} + +std::string LLUrlEntryHTTP::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return unescapeUrl(url); +} + +// +// LLUrlEntryHTTP Describes generic http: and https: Urls with custom label +// We use the wikipedia syntax of [http://www.example.org Text] +// +LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel() +{ + mPattern = boost::regex("\\[https?://\\S+[ \t]+[^\\]]+\\]", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); +} + +std::string LLUrlEntryHTTPLabel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return getLabelFromWikiLink(url); +} + +std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) +{ + return getUrlFromWikiLink(string); +} + +// +// LLUrlEntrySLURL Describes generic http: and https: Urls +// +LLUrlEntrySLURL::LLUrlEntrySLURL() +{ + // see http://slurl.com/about.php for details on the SLURL format + mPattern = boost::regex("http://slurl.com/secondlife/\\S+/?(\\d+)?/?(\\d+)?/?(\\d+)?/?\\S*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_slurl.xml"; + mTooltip = LLTrans::getString("TooltipSLURL"); +} + +std::string LLUrlEntrySLURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + // + // we handle SLURLs in the following formats: + // - http://slurl.com/secondlife/Place/X/Y/Z + // - http://slurl.com/secondlife/Place/X/Y + // - http://slurl.com/secondlife/Place/X + // - http://slurl.com/secondlife/Place + // + LLURI uri(url); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + if (path_parts == 5) + { + // handle slurl with (X,Y,Z) coordinates + std::string location = unescapeUrl(path_array[path_parts-4]); + std::string x = path_array[path_parts-3]; + std::string y = path_array[path_parts-2]; + std::string z = path_array[path_parts-1]; + return location + " (" + x + "," + y + "," + z + ")"; + } + else if (path_parts == 4) + { + // handle slurl with (X,Y) coordinates + std::string location = unescapeUrl(path_array[path_parts-3]); + std::string x = path_array[path_parts-2]; + std::string y = path_array[path_parts-1]; + return location + " (" + x + "," + y + ")"; + } + else if (path_parts == 3) + { + // handle slurl with (X) coordinate + std::string location = unescapeUrl(path_array[path_parts-2]); + std::string x = path_array[path_parts-1]; + return location + " (" + x + ")"; + } + else if (path_parts == 2) + { + // handle slurl with no coordinates + std::string location = unescapeUrl(path_array[path_parts-1]); + return location; + } + + return url; +} + +std::string LLUrlEntrySLURL::getLocation(const std::string &url) const +{ + // return the part of the Url after slurl.com/secondlife/ + const std::string search_string = "secondlife"; + size_t pos = url.find(search_string); + if (pos == std::string::npos) + { + return ""; + } + + pos += search_string.size() + 1; + return url.substr(pos, url.size() - pos); +} + +// +// LLUrlEntryAgent Describes a Second Life agent Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about +// +LLUrlEntryAgent::LLUrlEntryAgent() +{ + mPattern = boost::regex("secondlife:///app/agent/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_agent.xml"; + mTooltip = LLTrans::getString("TooltipAgentUrl"); +} + +void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group) +{ + // received the agent name from the server - tell our observers + callObservers(id.asString(), first + " " + last); +} + +std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + std::string id = getIDStringFromUrl(url); + if (gCacheName && ! id.empty()) + { + LLUUID uuid(id); + std::string full_name; + if (gCacheName->getFullName(uuid, full_name)) + { + return full_name; + } + else + { + gCacheName->get(uuid, FALSE, boost::bind(&LLUrlEntryAgent::onAgentNameReceived, this, _1, _2, _3, _4)); + addObserver(id, url, cb); + } + } + + return unescapeUrl(url); +} + +// +// LLUrlEntryGroup Describes a Second Life group Url, e.g., +// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about +// +LLUrlEntryGroup::LLUrlEntryGroup() +{ + mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_group.xml"; + mTooltip = LLTrans::getString("TooltipGroupUrl"); +} + +void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group) +{ + // received the group name from the server - tell our observers + callObservers(id.asString(), first); +} + +std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + std::string id = getIDStringFromUrl(url); + if (gCacheName && ! id.empty()) + { + LLUUID uuid(id); + std::string group_name; + if (gCacheName->getGroupName(uuid, group_name)) + { + return group_name; + } + else + { + gCacheName->get(uuid, TRUE, boost::bind(&LLUrlEntryGroup::onGroupNameReceived, this, _1, _2, _3, _4)); + addObserver(id, url, cb); + } + } + + return unescapeUrl(url); +} + +/// +/// LLUrlEntryEvent Describes a Second Life event Url, e.g., +/// secondlife:///app/event/700727/about +/// +LLUrlEntryEvent::LLUrlEntryEvent() +{ + mPattern = boost::regex("secondlife:///app/event/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_event.xml"; + mTooltip = LLTrans::getString("TooltipEventUrl"); +} + +std::string LLUrlEntryEvent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return unescapeUrl(url); +} + +/// +/// LLUrlEntryClassified Describes a Second Life classified Url, e.g., +/// secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about +/// +LLUrlEntryClassified::LLUrlEntryClassified() +{ + mPattern = boost::regex("secondlife:///app/classified/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_classified.xml"; + mTooltip = LLTrans::getString("TooltipClassifiedUrl"); +} + +std::string LLUrlEntryClassified::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return unescapeUrl(url); +} + +/// +/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., +/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about +/// +LLUrlEntryParcel::LLUrlEntryParcel() +{ + mPattern = boost::regex("secondlife:///app/parcel/[\\da-f-]+/about", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_parcel.xml"; + mTooltip = LLTrans::getString("TooltipParcelUrl"); +} + +std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return unescapeUrl(url); +} + +// +// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g., +// secondlife:///app/teleport/Ahern/50/50/50/ +// +LLUrlEntryTeleport::LLUrlEntryTeleport() +{ + mPattern = boost::regex("secondlife:///app/teleport/\\S+(/\\d+)?(/\\d+)?(/\\d+)?/?\\S*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_teleport.xml"; + mTooltip = LLTrans::getString("TooltipTeleportUrl"); +} + +std::string LLUrlEntryTeleport::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + // + // we handle teleport SLURLs in the following formats: + // - secondlife:///app/teleport/Place/X/Y/Z + // - secondlife:///app/teleport/Place/X/Y + // - secondlife:///app/teleport/Place/X + // - secondlife:///app/teleport/Place + // + LLURI uri(url); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + if (path_parts == 6) + { + // handle teleport url with (X,Y,Z) coordinates + std::string location = unescapeUrl(path_array[path_parts-4]); + std::string x = path_array[path_parts-3]; + std::string y = path_array[path_parts-2]; + std::string z = path_array[path_parts-1]; + return "Teleport to " + location + " (" + x + "," + y + "," + z + ")"; + } + else if (path_parts == 5) + { + // handle teleport url with (X,Y) coordinates + std::string location = unescapeUrl(path_array[path_parts-3]); + std::string x = path_array[path_parts-2]; + std::string y = path_array[path_parts-1]; + return "Teleport to " + location + " (" + x + "," + y + ")"; + } + else if (path_parts == 4) + { + // handle teleport url with (X) coordinate only + std::string location = unescapeUrl(path_array[path_parts-2]); + std::string x = path_array[path_parts-1]; + return "Teleport to " + location + " (" + x + ")"; + } + else if (path_parts == 3) + { + // handle teleport url with no coordinates + std::string location = unescapeUrl(path_array[path_parts-1]); + return "Teleport to " + location; + } + + return url; +} + +std::string LLUrlEntryTeleport::getLocation(const std::string &url) const +{ + // return the part of the Url after ///app/teleport + const std::string search_string = "teleport"; + size_t pos = url.find(search_string); + if (pos == std::string::npos) + { + return ""; + } + + pos += search_string.size() + 1; + return url.substr(pos, url.size() - pos); +} + +/// +/// LLUrlEntryObjectIM Describes a Second Life object instant msg Url, e.g., +/// secondlife:///app/objectim/<sessionid> +/// +LLUrlEntryObjectIM::LLUrlEntryObjectIM() +{ + mPattern = boost::regex("secondlife:///app/objectim/[\\da-f-]+\\??\\S*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_objectim.xml"; + mTooltip = LLTrans::getString("TooltipObjectIMUrl"); +} + +std::string LLUrlEntryObjectIM::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + LLURI uri(url); + LLSD params = uri.queryMap(); + if (params.has("name")) + { + // look for a ?name=<obj-name> param in the url + // and use that as the label if present. + std::string name = params.get("name"); + LLStringUtil::trim(name); + if (name.empty()) + { + name = LLTrans::getString("Unnamed"); + } + return name; + } + + return unescapeUrl(url); +} + +std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const +{ + LLURI uri(url); + LLSD params = uri.queryMap(); + if (params.has("slurl")) + { + return params.get("slurl"); + } + + return ""; +} + +// +// LLUrlEntrySL Describes a generic SLURL, e.g., a Url that starts +// with secondlife:// (used as a catch-all for cases not matched above) +// +LLUrlEntrySL::LLUrlEntrySL() +{ + mPattern = boost::regex("secondlife://(\\w+)?(:\\d+)?/\\S+", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_slapp.xml"; + mTooltip = LLTrans::getString("TooltipSLAPP"); +} + +std::string LLUrlEntrySL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return unescapeUrl(url); +} + +// +// LLUrlEntrySLLabel Describes a generic SLURL, e.g., a Url that starts +/// with secondlife:// with the ability to specify a custom label. +// +LLUrlEntrySLLabel::LLUrlEntrySLLabel() +{ + mPattern = boost::regex("\\[secondlife://\\S+[ \t]+[^\\]]+\\]", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_slapp.xml"; + mTooltip = LLTrans::getString("TooltipSLAPP"); +} + +std::string LLUrlEntrySLLabel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return getLabelFromWikiLink(url); +} + +std::string LLUrlEntrySLLabel::getUrl(const std::string &string) +{ + return getUrlFromWikiLink(string); +} + diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h new file mode 100644 index 0000000000..f3e76dbec0 --- /dev/null +++ b/indra/llui/llurlentry.h @@ -0,0 +1,252 @@ +/** + * @file llurlentry.h + * @author Martin Reddy + * @brief Describes the Url types that can be registered in LLUrlRegistry + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLURLENTRY_H +#define LL_LLURLENTRY_H + +#include "lluuid.h" + +#include <boost/signals2.hpp> +#include <boost/regex.hpp> +#include <string> +#include <map> + +typedef boost::signals2::signal<void (const std::string& url, + const std::string& label)> LLUrlLabelSignal; +typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback; + +/// +/// LLUrlEntryBase is the base class of all Url types registered in the +/// LLUrlRegistry. Each derived classes provides a regular expression +/// to match the Url type (e.g., http://... or secondlife://...) along +/// with an optional icon to display next to instances of the Url in +/// a text display and a XUI file to use for any context menu popup. +/// Functions are also provided to compute an appropriate label and +/// tooltip/status bar text for the Url. +/// +/// Some derived classes of LLUrlEntryBase may wish to compute an +/// appropriate label for a Url by asking the server for information. +/// You must therefore provide a callback method, so that you can be +/// notified when an updated label has been received from the server. +/// This label should then be used to replace any previous label +/// that you received from getLabel() for the Url in question. +/// +class LLUrlEntryBase +{ +public: + LLUrlEntryBase(); + virtual ~LLUrlEntryBase(); + + /// Return the regex pattern that matches this Url + boost::regex getPattern() const { return mPattern; } + + /// Return the url from a string that matched the regex + virtual std::string getUrl(const std::string &string); + + /// Given a matched Url, return a label for the Url + virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; } + + /// Return an icon that can be displayed next to Urls of this type + const std::string &getIcon() const { return mIcon; } + + /// Given a matched Url, return a tooltip string for the hyperlink + std::string getTooltip() const { return mTooltip; } + + /// Return the name of a XUI file containing the context menu items + const std::string getMenuName() const { return mMenuName; } + + /// Return the name of a SL location described by this Url, if any + virtual std::string getLocation(const std::string &url) const { return ""; } + +protected: + std::string getIDStringFromUrl(const std::string &url) const; + std::string escapeUrl(const std::string &url) const; + std::string unescapeUrl(const std::string &url) const; + std::string getLabelFromWikiLink(const std::string &url); + std::string getUrlFromWikiLink(const std::string &string); + void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb); + void callObservers(const std::string &id, const std::string &label); + + typedef struct { + std::string url; + LLUrlLabelSignal *signal; + } LLUrlEntryObserver; + + boost::regex mPattern; + std::string mIcon; + std::string mMenuName; + std::string mTooltip; + std::multimap<std::string, LLUrlEntryObserver> mObservers; +}; + +/// +/// LLUrlEntryHTTP Describes generic http: and https: Urls +/// +class LLUrlEntryHTTP : public LLUrlEntryBase +{ +public: + LLUrlEntryHTTP(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +}; + +/// +/// LLUrlEntryHTTPLabel Describes generic http: and https: Urls with custom labels +/// +class LLUrlEntryHTTPLabel : public LLUrlEntryBase +{ +public: + LLUrlEntryHTTPLabel(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string); +}; + +/// +/// LLUrlEntrySLURL Describes http://slurl.com/... Urls +/// +class LLUrlEntrySLURL : public LLUrlEntryBase +{ +public: + LLUrlEntrySLURL(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; +}; + +/// +/// LLUrlEntryAgent Describes a Second Life agent Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about +/// +class LLUrlEntryAgent : public LLUrlEntryBase +{ +public: + LLUrlEntryAgent(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +private: + void onAgentNameReceived(const LLUUID& id, const std::string& first, + const std::string& last, BOOL is_group); +}; + +/// +/// LLUrlEntryGroup Describes a Second Life group Url, e.g., +/// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about +/// +class LLUrlEntryGroup : public LLUrlEntryBase +{ +public: + LLUrlEntryGroup(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +private: + void onGroupNameReceived(const LLUUID& id, const std::string& first, + const std::string& last, BOOL is_group); +}; + +/// +/// LLUrlEntryEvent Describes a Second Life event Url, e.g., +/// secondlife:///app/event/700727/about +/// +class LLUrlEntryEvent : public LLUrlEntryBase +{ +public: + LLUrlEntryEvent(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +}; + +/// +/// LLUrlEntryClassified Describes a Second Life classified Url, e.g., +/// secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about +/// +class LLUrlEntryClassified : public LLUrlEntryBase +{ +public: + LLUrlEntryClassified(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +}; + +/// +/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., +/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about +/// +class LLUrlEntryParcel : public LLUrlEntryBase +{ +public: + LLUrlEntryParcel(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +}; + +/// +/// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g., +/// secondlife:///app/teleport/Ahern/50/50/50/ +/// +class LLUrlEntryTeleport : public LLUrlEntryBase +{ +public: + LLUrlEntryTeleport(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; +}; + +/// +/// LLUrlEntryObjectIM Describes a Second Life object instant msg Url, e.g., +/// secondlife:///app/objectim/<sessionid>?name=Foo +/// +class LLUrlEntryObjectIM : public LLUrlEntryBase +{ +public: + LLUrlEntryObjectIM(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; +}; + +/// +/// LLUrlEntrySL Describes a generic SLURL, e.g., a Url that starts +/// with secondlife:// (used as a catch-all for cases not matched above) +/// +class LLUrlEntrySL : public LLUrlEntryBase +{ +public: + LLUrlEntrySL(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +}; + +/// +/// LLUrlEntrySLLabel Describes a generic SLURL, e.g., a Url that starts +/// with secondlife:// with the ability to specify a custom label. +/// +class LLUrlEntrySLLabel : public LLUrlEntryBase +{ +public: + LLUrlEntrySLLabel(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getUrl(const std::string &string); +}; + +#endif diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp new file mode 100644 index 0000000000..7eec4c4a65 --- /dev/null +++ b/indra/llui/llurlmatch.cpp @@ -0,0 +1,61 @@ +/** + * @file llurlmatch.cpp + * @author Martin Reddy + * @brief Specifies a matched Url in a string, as returned by LLUrlRegistry + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llurlmatch.h" + +LLUrlMatch::LLUrlMatch() : + mStart(0), + mEnd(0), + mUrl(""), + mLabel(""), + mTooltip(""), + mIcon(""), + mMenuName("") +{ +} + +void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, + const std::string &label, const std::string &tooltip, + const std::string &icon, const std::string &menu, + const std::string &location) +{ + mStart = start; + mEnd = end; + mUrl = url; + mLabel = label; + mTooltip = tooltip; + mIcon = icon; + mMenuName = menu; + mLocation = location; +} diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h new file mode 100644 index 0000000000..0711e41443 --- /dev/null +++ b/indra/llui/llurlmatch.h @@ -0,0 +1,98 @@ +/** + * @file llurlmatch.h + * @author Martin Reddy + * @brief Specifies a matched Url in a string, as returned by LLUrlRegistry + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLURLMATCH_H +#define LL_LLURLMATCH_H + +#include "linden_common.h" + +#include <string> +#include <vector> + +/// +/// LLUrlMatch describes a single Url that was matched within a string by +/// the LLUrlRegistry::findUrl() method. It includes the actual Url that +/// was matched along with its first/last character offset in the string. +/// An alternate label is also provided for creating a hyperlink, as well +/// as tooltip/status text, an icon, and a XUI file for a context menu +/// that can be used in a popup for a Url (e.g., Open, Copy URL, etc.) +/// +class LLUrlMatch +{ +public: + LLUrlMatch(); + + /// return true if this object does not contain a valid Url match yet + bool empty() const { return mUrl.empty(); } + + /// return the offset in the string for the first character of the Url + U32 getStart() const { return mStart; } + + /// return the offset in the string for the last character of the Url + U32 getEnd() const { return mEnd; } + + /// return the Url that has been matched in the input string + const std::string &getUrl() const { return mUrl; } + + /// return a label that can be used for the display of this Url + const std::string &getLabel() const { return mLabel; } + + /// return a message that could be displayed in a tooltip or status bar + const std::string &getTooltip() const { return mTooltip; } + + /// return the filename for an icon that can be displayed next to this Url + const std::string &getIcon() const { return mIcon; } + + /// Return the name of a XUI file containing the context menu items + const std::string getMenuName() const { return mMenuName; } + + /// return the SL location that this Url describes, or "" if none. + const std::string &getLocation() const { return mLocation; } + + /// Change the contents of this match object (used by LLUrlRegistry) + void setValues(U32 start, U32 end, const std::string &url, const std::string &label, + const std::string &tooltip, const std::string &icon, + const std::string &menu, const std::string &location); + +private: + U32 mStart; + U32 mEnd; + std::string mUrl; + std::string mLabel; + std::string mTooltip; + std::string mIcon; + std::string mMenuName; + std::string mLocation; +}; + +#endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp new file mode 100644 index 0000000000..938375ad13 --- /dev/null +++ b/indra/llui/llurlregistry.cpp @@ -0,0 +1,165 @@ +/** + * @file llurlregistry.cpp + * @author Martin Reddy + * @brief Contains a set of Url types that can be matched in a string + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llurlregistry.h" + +#include <boost/regex.hpp> + +// default dummy callback that ignores any label updates from the server +void LLUrlRegistryNullCallback(const std::string &url, const std::string &label) +{ +} + +LLUrlRegistry::LLUrlRegistry() +{ + // Urls are matched in the order that they were registered + registerUrl(new LLUrlEntrySLURL()); + registerUrl(new LLUrlEntryHTTP()); + registerUrl(new LLUrlEntryHTTPLabel()); + registerUrl(new LLUrlEntryAgent()); + registerUrl(new LLUrlEntryGroup()); + registerUrl(new LLUrlEntryEvent()); + registerUrl(new LLUrlEntryClassified()); + registerUrl(new LLUrlEntryParcel()); + registerUrl(new LLUrlEntryTeleport()); + registerUrl(new LLUrlEntryObjectIM()); + registerUrl(new LLUrlEntrySL()); + registerUrl(new LLUrlEntrySLLabel()); +} + +LLUrlRegistry::~LLUrlRegistry() +{ + // free all of the LLUrlEntryBase objects we are holding + std::vector<LLUrlEntryBase *>::iterator it; + for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) + { + delete *it; + } +} + +void LLUrlRegistry::registerUrl(LLUrlEntryBase *url) +{ + if (url) + { + mUrlEntry.push_back(url); + } +} + +static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &end) +{ + boost::cmatch result; + bool found; + + // regex_search can potentially throw an exception, so check for it + try + { + found = boost::regex_search(text, result, regex); + } + catch (std::runtime_error &) + { + return false; + } + + if (! found) + { + return false; + } + + // return the first/last character offset for the matched substring + start = static_cast<U32>(result[0].first - text); + end = static_cast<U32>(result[0].second - text) - 1; + + // we allow certain punctuation to terminate a Url but not match it, + // e.g., "http://foo.com/." should just match "http://foo.com/" + if (text[end] == '.' || text[end] == ',') + { + end--; + } + // ignore a terminating ')' when Url contains no matching '(' + // see DEV-19842 for details + else if (text[end] == ')' && std::string(text+start, end-start).find('(') == std::string::npos) + { + end--; + } + + return true; +} + +bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) +{ + // test for the trivial case of no text and get out fast + if (text.empty()) + { + return false; + } + + // find the first matching regex from all url entries in the registry + U32 match_start = 0, match_end = 0; + LLUrlEntryBase *match_entry = NULL; + + std::vector<LLUrlEntryBase *>::iterator it; + for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) + { + LLUrlEntryBase *url_entry = *it; + + U32 start = 0, end = 0; + if (matchRegex(text.c_str(), url_entry->getPattern(), start, end)) + { + // does this match occur in the string before any other match + if (start < match_start || match_entry == NULL) + { + match_start = start; + match_end = end; + match_entry = url_entry; + } + } + } + + // did we find a match? if so, return its details in the match object + if (match_entry) + { + // fill in the LLUrlMatch object and return it + std::string url = text.substr(match_start, match_end - match_start + 1); + match.setValues(match_start, match_end, + match_entry->getUrl(url), + match_entry->getLabel(url, cb), + match_entry->getTooltip(), + match_entry->getIcon(), + match_entry->getMenuName(), + match_entry->getLocation(url)); + return true; + } + + return false; +} diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h new file mode 100644 index 0000000000..84b033036c --- /dev/null +++ b/indra/llui/llurlregistry.h @@ -0,0 +1,87 @@ +/** + * @file llurlregistry.h + * @author Martin Reddy + * @brief Contains a set of Url types that can be matched in a string + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLURLREGISTRY_H +#define LL_LLURLREGISTRY_H + +#include "llurlentry.h" +#include "llurlmatch.h" +#include "llsingleton.h" + +#include <string> +#include <vector> +#include <map> + +/// This default callback for findUrl() simply ignores any label updates +void LLUrlRegistryNullCallback(const std::string &url, const std::string &label); + +/// +/// LLUrlRegistry is a singleton that contains a set of Url types that +/// can be matched in string. E.g., http:// or secondlife:// Urls. +/// +/// Clients call the findUrl() method on a string to locate the first +/// occurence of a supported Urls in that string. If findUrl() returns +/// true, the LLUrlMatch object will be updated to describe the Url +/// that was matched, including a label that can be used to hyperlink +/// the Url, an icon to display next to the Url, and a XUI menu that +/// can be used as a popup context menu for that Url. +/// +/// New Url types can be added to the registry with the registerUrl +/// method. E.g., to add support for a new secondlife:///app/ Url. +/// +/// Computing the label for a Url could involve a roundtrip request +/// to the server (e.g., to find the actual agent or group name). +/// As such, you can provide a callback method that will get invoked +/// when a new label is available for one of your matched Urls. +/// +class LLUrlRegistry : public LLSingleton<LLUrlRegistry> +{ +public: + ~LLUrlRegistry(); + + /// add a new Url handler to the registry (will be freed on destruction) + void registerUrl(LLUrlEntryBase *url); + + /// get the next Url in an input string, starting at a given character offset + /// your callback is invoked if the matched Url's label changes in the future + bool findUrl(const std::string &text, LLUrlMatch &match, + const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback); + +private: + LLUrlRegistry(); + friend class LLSingleton<LLUrlRegistry>; + + std::vector<LLUrlEntryBase *> mUrlEntry; +}; + +#endif diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 4770807ac7..55d94b325f 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -2735,3 +2735,17 @@ LLView::default_widget_map_t& LLView::getDefaultWidgetMap() const } return *mDefaultWidgets; } +void LLView::notifyParent(const LLSD& info) +{ + LLView* parent = getParent(); + if(parent) + parent->notifyParent(info); +} +void LLView::notifyChildren(const LLSD& info) +{ + for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) + { + (*child_it)->notifyChildren(info); + } +} + diff --git a/indra/llui/llview.h b/indra/llui/llview.h index ecc6bf47da..1d48378081 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -549,6 +549,9 @@ public: virtual void handleReshape(const LLRect& rect, bool by_user); + virtual void notifyParent(const LLSD& info); + virtual void notifyChildren(const LLSD& info); + protected: void drawDebugRect(); void drawChild(LLView* childp, S32 x_offset = 0, S32 y_offset = 0, BOOL force_draw = FALSE); diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp new file mode 100644 index 0000000000..26d1f2e067 --- /dev/null +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -0,0 +1,64 @@ +/** + * @file llurlentry_stub.cpp + * @author Martin Reddy + * @brief Stub implementations for LLUrlEntry unit test dependencies + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, 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$ + */ + +#include "llstring.h" +#include "llfile.h" +#include "llcachename.h" +#include "lluuid.h" + +#include <string> + +// +// Stub implementation for LLCacheName +// +BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname) +{ + fullname = "Lynx Linden"; + return TRUE; +} + +BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) +{ + group = "My Group"; + return TRUE; +} + +boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback) +{ + return boost::signals2::connection(); +} + +LLCacheName* gCacheName = NULL; + +// +// Stub implementation for LLTrans +// +class LLTrans +{ +public: + static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); +}; + +std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args) +{ + return std::string(); +} diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp new file mode 100644 index 0000000000..610ee3349b --- /dev/null +++ b/indra/llui/tests/llurlentry_test.cpp @@ -0,0 +1,535 @@ +/** + * @file llurlentry_test.cpp + * @author Martin Reddy + * @brief Unit tests for LLUrlEntry objects + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, 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$ + */ + +#include "linden_common.h" +#include "../llurlentry.h" +#include "llurlentry_stub.cpp" +#include "lltut.h" + +#include <boost/regex.hpp> + +namespace tut +{ + struct LLUrlEntryData + { + }; + + typedef test_group<LLUrlEntryData> factory; + typedef factory::object object; +} + +namespace +{ + tut::factory tf("LLUrlEntry"); +} + +namespace tut +{ + void testRegex(const std::string &testname, boost::regex regex, + const char *text, const std::string &expected) + { + std::string url = ""; + boost::cmatch result; + bool found = boost::regex_search(text, result, regex); + if (found) + { + S32 start = static_cast<U32>(result[0].first - text); + S32 end = static_cast<U32>(result[0].second - text); + url = std::string(text+start, end-start); + } + ensure_equals(testname, url, expected); + } + + template<> template<> + void object::test<1>() + { + // + // test LLUrlEntryHTTP - standard http Urls + // + LLUrlEntryHTTP url; + boost::regex r = url.getPattern(); + + testRegex("no valid url", r, + "htp://slurl.com/", + ""); + + testRegex("simple http (1)", r, + "http://slurl.com/", + "http://slurl.com/"); + + testRegex("simple http (2)", r, + "http://slurl.com", + "http://slurl.com"); + + testRegex("simple http (3)", r, + "http://slurl.com/about.php", + "http://slurl.com/about.php"); + + testRegex("simple https", r, + "https://slurl.com/about.php", + "https://slurl.com/about.php"); + + testRegex("http in text (1)", r, + "XX http://slurl.com/ XX", + "http://slurl.com/"); + + testRegex("http in text (2)", r, + "XX http://slurl.com/about.php XX", + "http://slurl.com/about.php"); + + testRegex("https in text", r, + "XX https://slurl.com/about.php XX", + "https://slurl.com/about.php"); + + testRegex("two http urls", r, + "XX http://slurl.com/about.php http://secondlife.com/ XX", + "http://slurl.com/about.php"); + + testRegex("http url with port and username", r, + "XX http://nobody@slurl.com:80/about.php http://secondlife.com/ XX", + "http://nobody@slurl.com:80/about.php"); + + testRegex("http url with port, username, and query string", r, + "XX http://nobody@slurl.com:80/about.php?title=hi%20there http://secondlife.com/ XX", + "http://nobody@slurl.com:80/about.php?title=hi%20there"); + + // note: terminating commas will be removed by LLUrlRegistry:findUrl() + testRegex("http url with commas in middle and terminating", r, + "XX http://slurl.com/?title=Hi,There, XX", + "http://slurl.com/?title=Hi,There,"); + + // note: terminating periods will be removed by LLUrlRegistry:findUrl() + testRegex("http url with periods in middle and terminating", r, + "XX http://slurl.com/index.php. XX", + "http://slurl.com/index.php."); + + // DEV-19842: Closing parenthesis ")" breaks urls + testRegex("http url with brackets (1)", r, + "XX http://en.wikipedia.org/wiki/JIRA_(software) XX", + "http://en.wikipedia.org/wiki/JIRA_(software)"); + + // DEV-19842: Closing parenthesis ")" breaks urls + testRegex("http url with brackets (2)", r, + "XX http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg XX", + "http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg"); + + // DEV-10353: URLs in chat log terminated incorrectly when newline in chat + testRegex("http url with newlines", r, + "XX\nhttp://www.secondlife.com/\nXX", + "http://www.secondlife.com/"); + } + + template<> template<> + void object::test<2>() + { + // + // test LLUrlEntryHTTPLabel - wiki-style http Urls with labels + // + LLUrlEntryHTTPLabel url; + boost::regex r = url.getPattern(); + + testRegex("invalid wiki url [1]", r, + "[http://www.example.org]", + ""); + + testRegex("invalid wiki url [2]", r, + "[http://www.example.org", + ""); + + testRegex("invalid wiki url [3]", r, + "[http://www.example.org Label", + ""); + + testRegex("example.org with label (spaces)", r, + "[http://www.example.org Text]", + "[http://www.example.org Text]"); + + testRegex("example.org with label (tabs)", r, + "[http://www.example.org\t Text]", + "[http://www.example.org\t Text]"); + + testRegex("SL http URL with label", r, + "[http://www.secondlife.com/ Second Life]", + "[http://www.secondlife.com/ Second Life]"); + + testRegex("SL https URL with label", r, + "XXX [https://www.secondlife.com/ Second Life] YYY", + "[https://www.secondlife.com/ Second Life]"); + + testRegex("SL http URL with label", r, + "[http://www.secondlife.com/?test=Hi%20There Second Life]", + "[http://www.secondlife.com/?test=Hi%20There Second Life]"); + } + + template<> template<> + void object::test<3>() + { + // + // test LLUrlEntrySLURL - second life URLs + // + LLUrlEntrySLURL url; + boost::regex r = url.getPattern(); + + testRegex("no valid slurl [1]", r, + "htp://slurl.com/secondlife/Ahern/50/50/50/", + ""); + + testRegex("no valid slurl [2]", r, + "http://slurl.com/secondlife/", + ""); + + testRegex("no valid slurl [3]", r, + "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/", + ""); + + testRegex("Ahern (50,50,50) [1]", r, + "http://slurl.com/secondlife/Ahern/50/50/50/", + "http://slurl.com/secondlife/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [2]", r, + "XXX http://slurl.com/secondlife/Ahern/50/50/50/ XXX", + "http://slurl.com/secondlife/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [3]", r, + "XXX http://slurl.com/secondlife/Ahern/50/50/50 XXX", + "http://slurl.com/secondlife/Ahern/50/50/50"); + + testRegex("Ahern (50,50,50) multicase", r, + "XXX http://SLUrl.com/SecondLife/Ahern/50/50/50/ XXX", + "http://SLUrl.com/SecondLife/Ahern/50/50/50/"); + + testRegex("Ahern (50,50) [1]", r, + "XXX http://slurl.com/secondlife/Ahern/50/50/ XXX", + "http://slurl.com/secondlife/Ahern/50/50/"); + + testRegex("Ahern (50,50) [2]", r, + "XXX http://slurl.com/secondlife/Ahern/50/50 XXX", + "http://slurl.com/secondlife/Ahern/50/50"); + + testRegex("Ahern (50)", r, + "XXX http://slurl.com/secondlife/Ahern/50 XXX", + "http://slurl.com/secondlife/Ahern/50"); + + testRegex("Ahern", r, + "XXX http://slurl.com/secondlife/Ahern/ XXX", + "http://slurl.com/secondlife/Ahern/"); + + testRegex("Ahern SLURL with title", r, + "XXX http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX", + "http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); + + testRegex("Ahern SLURL with msg", r, + "XXX http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here. XXX", + "http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here."); + + // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat + testRegex("SLURL with brackets", r, + "XXX http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30 XXX", + "http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30"); + + // DEV-35459: SLURLs and teleport Links not parsed properly + testRegex("SLURL with quote", r, + "XXX http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701 XXX", + "http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701"); + } + + template<> template<> + void object::test<4>() + { + // + // test LLUrlEntryAgent - secondlife://app/agent Urls + // + LLUrlEntryAgent url; + boost::regex r = url.getPattern(); + + testRegex("Invalid Agent Url", r, + "secondlife:///app/agent/0e346d8b-4433-4d66-XXXX-fd37083abc4c/about", + ""); + + testRegex("Agent Url ", r, + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about", + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Agent Url in text", r, + "XXX secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about XXX", + "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); + + testRegex("Agent Url multicase", r, + "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About XXX", + "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About"); + } + + template<> template<> + void object::test<5>() + { + // + // test LLUrlEntryGroup - secondlife://app/group Urls + // + LLUrlEntryGroup url; + boost::regex r = url.getPattern(); + + testRegex("Invalid Group Url", r, + "secondlife:///app/group/00005ff3-4044-c79f-XXXX-fb28ae0df991/about", + ""); + + testRegex("Group Url ", r, + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about", + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); + + testRegex("Group Url in text", r, + "XXX secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about XXX", + "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); + + testRegex("Group Url multicase", r, + "XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX", + "secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About"); + } + + template<> template<> + void object::test<6>() + { + // + // test LLUrlEntryEvent - secondlife://app/event Urls + // + LLUrlEntryEvent url; + boost::regex r = url.getPattern(); + + testRegex("Invalid Event Url", r, + "secondlife:///app/event/FOO/about", + ""); + + testRegex("Event Url ", r, + "secondlife:///app/event/700727/about", + "secondlife:///app/event/700727/about"); + + testRegex("Event Url in text", r, + "XXX secondlife:///app/event/700727/about XXX", + "secondlife:///app/event/700727/about"); + + testRegex("Event Url multicase", r, + "XXX secondlife:///APP/Event/700727/about XXX", + "secondlife:///APP/Event/700727/about"); + } + + template<> template<> + void object::test<7>() + { + // + // test LLUrlEntryClassified - secondlife://app/classified Urls + // + LLUrlEntryClassified url; + boost::regex r = url.getPattern(); + + testRegex("Invalid Classified Url", r, + "secondlife:///app/classified/00128854-XXXX-5649-7ca6-5dfaa7514ab2/about", + ""); + + testRegex("Classified Url ", r, + "secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about", + "secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about"); + + testRegex("Classified Url in text", r, + "XXX secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about XXX", + "secondlife:///app/classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/about"); + + testRegex("Classified Url multicase", r, + "XXX secondlife:///APP/Classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/About XXX", + "secondlife:///APP/Classified/00128854-c36a-5649-7ca6-5dfaa7514ab2/About"); + } + + template<> template<> + void object::test<8>() + { + // + // test LLUrlEntryParcel - secondlife://app/parcel Urls + // + LLUrlEntryParcel url; + boost::regex r = url.getPattern(); + + testRegex("Invalid Classified Url", r, + "secondlife:///app/parcel/0000060e-4b39-e00b-XXXX-d98b1934e3a8/about", + ""); + + testRegex("Classified Url ", r, + "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about", + "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); + + testRegex("Classified Url in text", r, + "XXX secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about XXX", + "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); + + testRegex("Classified Url multicase", r, + "XXX secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About XXX", + "secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About"); + } + template<> template<> + void object::test<9>() + { + // + // test LLUrlEntryTeleport - secondlife://app/teleport URLs + // + LLUrlEntryTeleport url; + boost::regex r = url.getPattern(); + + testRegex("no valid teleport [1]", r, + "http://slurl.com/secondlife/Ahern/50/50/50/", + ""); + + testRegex("no valid teleport [2]", r, + "secondlife:///app/teleport/", + ""); + + testRegex("no valid teleport [3]", r, + "second-life:///app/teleport/Ahern/50/50/50/", + ""); + + testRegex("no valid teleport [3]", r, + "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/", + ""); + + testRegex("Ahern (50,50,50) [1]", r, + "secondlife:///app/teleport/Ahern/50/50/50/", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [2]", r, + "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("Ahern (50,50,50) [3]", r, + "XXX secondlife:///app/teleport/Ahern/50/50/50 XXX", + "secondlife:///app/teleport/Ahern/50/50/50"); + + testRegex("Ahern (50,50,50) multicase", r, + "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("Ahern (50,50) [1]", r, + "XXX secondlife:///app/teleport/Ahern/50/50/ XXX", + "secondlife:///app/teleport/Ahern/50/50/"); + + testRegex("Ahern (50,50) [2]", r, + "XXX secondlife:///app/teleport/Ahern/50/50 XXX", + "secondlife:///app/teleport/Ahern/50/50"); + + testRegex("Ahern (50)", r, + "XXX secondlife:///app/teleport/Ahern/50 XXX", + "secondlife:///app/teleport/Ahern/50"); + + testRegex("Ahern", r, + "XXX secondlife:///app/teleport/Ahern/ XXX", + "secondlife:///app/teleport/Ahern/"); + + testRegex("Ahern teleport with title", r, + "XXX secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX", + "secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); + + testRegex("Ahern teleport with msg", r, + "XXX secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here. XXX", + "secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here."); + + // DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat + testRegex("Teleport with brackets", r, + "XXX secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30 XXX", + "secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30"); + + // DEV-35459: SLURLs and teleport Links not parsed properly + testRegex("Teleport url with quote", r, + "XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX", + "secondlife:///app/teleport/A'ksha%20Oasis/41/166/701"); + } + + template<> template<> + void object::test<10>() + { + // + // test LLUrlEntrySL - general secondlife:// URLs + // + LLUrlEntrySL url; + boost::regex r = url.getPattern(); + + testRegex("no valid slapp [1]", r, + "http:///app/", + ""); + + testRegex("valid slapp [1]", r, + "secondlife:///app/", + "secondlife:///app/"); + + testRegex("valid slapp [2]", r, + "secondlife:///app/teleport/Ahern/50/50/50/", + "secondlife:///app/teleport/Ahern/50/50/50/"); + + testRegex("valid slapp [3]", r, + "secondlife:///app/foo", + "secondlife:///app/foo"); + + testRegex("valid slapp [4]", r, + "secondlife:///APP/foo?title=Hi%20There", + "secondlife:///APP/foo?title=Hi%20There"); + + testRegex("valid slapp [5]", r, + "secondlife://host/app/", + "secondlife://host/app/"); + + testRegex("valid slapp [6]", r, + "secondlife://host:8080/foo/bar", + "secondlife://host:8080/foo/bar"); + } + + template<> template<> + void object::test<11>() + { + // + // test LLUrlEntrySLLabel - general secondlife:// URLs with labels + // + LLUrlEntrySLLabel url; + boost::regex r = url.getPattern(); + + testRegex("invalid wiki url [1]", r, + "[secondlife:///app/]", + ""); + + testRegex("invalid wiki url [2]", r, + "[secondlife:///app/", + ""); + + testRegex("invalid wiki url [3]", r, + "[secondlife:///app/ Label", + ""); + + testRegex("agent slurl with label (spaces)", r, + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about Text]", + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about Text]"); + + testRegex("agent slurl with label (tabs)", r, + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]", + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]"); + + testRegex("agent slurl with label", r, + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]", + "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]"); + + testRegex("teleport slurl with label", r, + "XXX [secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern] YYY", + "[secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern]"); + } +} diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp new file mode 100644 index 0000000000..4dae49db90 --- /dev/null +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -0,0 +1,177 @@ +/** + * @file llurlmatch_test.cpp + * @author Martin Reddy + * @brief Unit tests for LLUrlMatch + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, 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$ + */ + +#include "../llurlmatch.h" +#include "lltut.h" + +namespace tut +{ + struct LLUrlMatchData + { + }; + + typedef test_group<LLUrlMatchData> factory; + typedef factory::object object; +} + +namespace +{ + tut::factory tf("LLUrlMatch"); +} + +namespace tut +{ + template<> template<> + void object::test<1>() + { + // + // test the empty() method + // + LLUrlMatch match; + ensure("empty()", match.empty()); + + match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", "", ""); + ensure("! empty()", ! match.empty()); + } + + template<> template<> + void object::test<2>() + { + // + // test the getStart() method + // + LLUrlMatch match; + ensure_equals("getStart() == 0", match.getStart(), 0); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure_equals("getStart() == 10", match.getStart(), 10); + } + + template<> template<> + void object::test<3>() + { + // + // test the getEnd() method + // + LLUrlMatch match; + ensure_equals("getEnd() == 0", match.getEnd(), 0); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure_equals("getEnd() == 20", match.getEnd(), 20); + } + + template<> template<> + void object::test<4>() + { + // + // test the getUrl() method + // + LLUrlMatch match; + ensure_equals("getUrl() == ''", match.getUrl(), ""); + + match.setValues(10, 20, "http://slurl.com/", "", "", "", "", ""); + ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/"); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure_equals("getUrl() == '' (2)", match.getUrl(), ""); + } + + template<> template<> + void object::test<5>() + { + // + // test the getLabel() method + // + LLUrlMatch match; + ensure_equals("getLabel() == ''", match.getLabel(), ""); + + match.setValues(10, 20, "", "Label", "", "", "", ""); + ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label"); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure_equals("getLabel() == '' (2)", match.getLabel(), ""); + } + + template<> template<> + void object::test<6>() + { + // + // test the getTooltip() method + // + LLUrlMatch match; + ensure_equals("getTooltip() == ''", match.getTooltip(), ""); + + match.setValues(10, 20, "", "", "Info", "", "", ""); + ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info"); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure_equals("getTooltip() == '' (2)", match.getTooltip(), ""); + } + + template<> template<> + void object::test<7>() + { + // + // test the getIcon() method + // + LLUrlMatch match; + ensure_equals("getIcon() == ''", match.getIcon(), ""); + + match.setValues(10, 20, "", "", "", "Icon", "", ""); + ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon"); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure_equals("getIcon() == '' (2)", match.getIcon(), ""); + } + + template<> template<> + void object::test<8>() + { + // + // test the getMenuName() method + // + LLUrlMatch match; + ensure("getMenuName() empty", match.getMenuName().empty()); + + match.setValues(10, 20, "", "", "", "Icon", "xui_file.xml", ""); + ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml"); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure("getMenuName() empty (2)", match.getMenuName().empty()); + } + + template<> template<> + void object::test<9>() + { + // + // test the getLocation() method + // + LLUrlMatch match; + ensure("getLocation() empty", match.getLocation().empty()); + + match.setValues(10, 20, "", "", "", "Icon", "xui_file.xml", "Paris"); + ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris"); + + match.setValues(10, 20, "", "", "", "", "", ""); + ensure("getLocation() empty (2)", match.getLocation().empty()); + } +} diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b5e4259f89..767f93cf45 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -66,7 +66,6 @@ include_directories( set(viewer_SOURCE_FILES llaccordionctrltab.cpp llaccordionctrl.cpp - llactiveimwindow.cpp llagent.cpp llagentaccess.cpp llagentdata.cpp @@ -181,7 +180,6 @@ set(viewer_SOURCE_FILES llfloaterlandholdings.cpp llfloatermap.cpp llfloatermemleak.cpp - llfloatermute.cpp llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloateropenobject.cpp @@ -287,6 +285,7 @@ set(viewer_SOURCE_FILES llpanelavatar.cpp llpanelavatarrow.cpp llpanelavatartag.cpp + llpanelblockedlist.cpp llpanelclassified.cpp llpanelcontents.cpp llpaneldirbrowser.cpp @@ -349,6 +348,8 @@ set(viewer_SOURCE_FILES llremoteparcelrequest.cpp llsavedsettingsglue.cpp llscreenchannel.cpp + llsearchcombobox.cpp + llsearchhistory.cpp llselectmgr.cpp llsidetray.cpp llsidetraypanelcontainer.cpp @@ -518,7 +519,6 @@ set(viewer_HEADER_FILES ViewerInstall.cmake llaccordionctrltab.h llaccordionctrl.h - llactiveimwindow.h llagent.h llagentaccess.h llagentdata.h @@ -636,7 +636,6 @@ set(viewer_HEADER_FILES llfloaterlandholdings.h llfloatermap.h llfloatermemleak.h - llfloatermute.h llfloaternamedesc.h llfloaternotificationsconsole.h llfloateropenobject.h @@ -740,6 +739,7 @@ set(viewer_HEADER_FILES llpanelavatar.h llpanelavatarrow.h llpanelavatartag.h + llpanelblockedlist.h llpanelclassified.h llpanelcontents.h llpaneldirbrowser.h @@ -804,6 +804,8 @@ set(viewer_HEADER_FILES llrootview.h llscreenchannel.h llsavedsettingsglue.h + llsearchcombobox.h + llsearchhistory.h llselectmgr.h llsidetray.h llsidetraypanelcontainer.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2a08f62bb4..32b1443157 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -804,28 +804,6 @@ <key>Value</key> <real>1.0</real> </map> - <key>BuildBtnState</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>BuildBtnEnabled</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>BuildFeathering</key> <map> <key>Comment</key> @@ -2784,17 +2762,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>FirstPersonBtnState</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>FirstRunThisInstall</key> <map> <key>Comment</key> @@ -2966,28 +2933,6 @@ <integer>0</integer> </array> </map> - <key>FlyBtnEnabled</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>FlyBtnState</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>FlycamAbsolute</key> <map> <key>Comment</key> @@ -4600,17 +4545,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>MouselookBtnState</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>MuteAmbient</key> <map> <key>Comment</key> @@ -6552,17 +6486,6 @@ <key>Value</key> <real>1.0</real> </map> - <key>RunBtnState</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>RunMultipleThreads</key> <map> <key>Comment</key> @@ -6943,10 +6866,10 @@ <key>Value</key> <integer>0</integer> </map> - <key>ShowPGSearchAll</key> + <key>ShowCameraAndMoveControls</key> <map> <key>Comment</key> - <string>Show/Hide Navigation Bar Favorites Panel</string> + <string>Show/Hide Camera and Move controls in the bottom tray</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -6957,7 +6880,7 @@ <key>ShowNavbarFavoritesPanel</key> <map> <key>Comment</key> - <string>Show/Hide Navigation Bar Navigation Panel</string> + <string>Show/Hide Navigation Bar Favorites Panel</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -6968,6 +6891,17 @@ <key>ShowNavbarNavigationPanel</key> <map> <key>Comment</key> + <string>Show/Hide Navigation Bar Navigation Panel</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>ShowPGSearchAll</key> + <map> + <key>Comment</key> <string>Display results of search All that are flagged as PG</string> <key>Persist</key> <integer>1</integer> @@ -7386,17 +7320,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>SitBtnState</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> <key>SkinCurrent</key> <map> <key>Comment</key> @@ -7757,17 +7680,6 @@ <key>Value</key> <integer>2</integer> </map> - <key>ThirdPersonBtnState</key> - <map> - <key>Comment</key> - <string /> - <key>Persist</key> - <integer>0</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>ThrottleBandwidthKBPS</key> <map> <key>Comment</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 214065f080..08681db6cb 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -47,7 +47,6 @@ #include "llfloaterdirectory.h" #include "llfloaterland.h" -#include "llfloatermute.h" #include "llfloatersnapshot.h" #include "llfloatertools.h" #include "llfloaterworldmap.h" @@ -795,12 +794,10 @@ void LLAgent::setFlying(BOOL fly) LLViewerStats::getInstance()->incStat(LLViewerStats::ST_FLY_COUNT); } setControlFlags(AGENT_CONTROL_FLY); - gSavedSettings.setBOOL("FlyBtnState", TRUE); } else { clearControlFlags(AGENT_CONTROL_FLY); - gSavedSettings.setBOOL("FlyBtnState", FALSE); } @@ -3998,11 +3995,6 @@ void LLAgent::changeCameraToMouselook(BOOL animate) LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset); - gSavedSettings.setBOOL("FirstPersonBtnState", FALSE); - gSavedSettings.setBOOL("MouselookBtnState", TRUE); - gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE); - gSavedSettings.setBOOL("BuildBtnState", FALSE); - if (mAvatarObject.notNull()) { mAvatarObject->stopMotion( ANIM_AGENT_BODY_NOISE ); @@ -4098,11 +4090,6 @@ void LLAgent::changeCameraToFollow(BOOL animate) mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT ); } - gSavedSettings.setBOOL("FirstPersonBtnState", FALSE); - gSavedSettings.setBOOL("MouselookBtnState", FALSE); - gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE); - gSavedSettings.setBOOL("BuildBtnState", FALSE); - // unpause avatar animation mPauseRequest = NULL; @@ -4149,11 +4136,6 @@ void LLAgent::changeCameraToThirdPerson(BOOL animate) mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT ); } - gSavedSettings.setBOOL("FirstPersonBtnState", FALSE); - gSavedSettings.setBOOL("MouselookBtnState", FALSE); - gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE); - gSavedSettings.setBOOL("BuildBtnState", FALSE); - LLVector3 at_axis; // unpause avatar animation @@ -4231,11 +4213,6 @@ void LLAgent::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL camera_ani LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset); } - gSavedSettings.setBOOL("FirstPersonBtnState", FALSE); - gSavedSettings.setBOOL("MouselookBtnState", FALSE); - gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE); - gSavedSettings.setBOOL("BuildBtnState", FALSE); - if (camera_animate) { startCameraAnimation(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index de4f7ab091..800c555113 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -80,6 +80,7 @@ // Linden library includes #include "llmemory.h" +#include "llurlaction.h" // Third party library includes #include <boost/bind.hpp> @@ -685,9 +686,14 @@ bool LLAppViewer::init() LLTransUtil::parseLanguageStrings("language_settings.xml"); LLWeb::initClass(); // do this after LLUI - LLTextEditor::setURLCallbacks(&LLWeb::loadURL, - &LLURLDispatcher::dispatchFromTextEditor, - &LLURLDispatcher::dispatchFromTextEditor); + // Provide the text fields with callbacks for opening Urls + LLUrlAction::setOpenURLCallback(&LLWeb::loadURL); + LLUrlAction::setOpenURLInternalCallback(&LLWeb::loadURLInternal); + LLUrlAction::setOpenURLExternalCallback(&LLWeb::loadURLExternal); + LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); + + // Set the link color for any Urls in text fields + LLTextBase::setLinkColor( LLUIColorTable::instance().getColor("HTMLLinkColor") ); // Load translations for tooltips LLFloater::initClass(); @@ -2316,12 +2322,6 @@ void LLAppViewer::cleanupSavedSettings() { gSavedSettings.setBOOL("MouseSun", FALSE); - gSavedSettings.setBOOL("FlyBtnState", FALSE); - - gSavedSettings.setBOOL("FirstPersonBtnState", FALSE); - gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE); - gSavedSettings.setBOOL("BuildBtnState", FALSE); - gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc); diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index f557adf6a6..a121d327f7 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -62,6 +62,9 @@ LLAvatarList::LLAvatarList(const Params& p) { setCommitOnSelectionChange(TRUE); // there's no such param in LLScrollListCtrl::Params + // display a context menu appropriate for a list of avatar names + setContextMenu(LLScrollListCtrl::MENU_AVATAR); + // "volume" column { LLScrollListColumn::Params col_params; @@ -220,6 +223,16 @@ BOOL LLAvatarList::update(const std::vector<LLUUID>& all_buddies, const std::str #endif setScrollPos(pos); + updateLineHeight(); + LLRect rect = getRequiredRect(); + + LLSD params; + params["action"] = "size_changes"; + params["width"] = rect.getWidth(); + params["height"] = llmax(rect.getHeight(),20) + 5; + + getParent()->notifyParent(params); + return have_names; } diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 2403e891f6..861f23abb7 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -40,13 +40,12 @@ #include "lllayoutstack.h" #include "llnearbychatbar.h" #include "llsplitbutton.h" +#include "llsyswellwindow.h" #include "llfloatercamera.h" #include "llimpanel.h" -#include "llactiveimwindow.h" LLBottomTray::LLBottomTray(const LLSD&) : mChicletPanel(NULL), - mIMWell(NULL), mSysWell(NULL), mTalkBtn(NULL), mNearbyChatBar(NULL), @@ -58,10 +57,10 @@ LLBottomTray::LLBottomTray(const LLSD&) LLUICtrlFactory::getInstance()->buildPanel(this,"panel_bottomtray.xml"); mChicletPanel = getChild<LLChicletPanel>("chiclet_list"); - mIMWell = getChild<LLNotificationChiclet>("im_well"); mSysWell = getChild<LLNotificationChiclet>("sys_well"); mSysWell->setNotificationChicletWindow(LLFloaterReg::getInstance("syswell_window")); + mChicletPanel->setChicletClickedCallback(boost::bind(&LLBottomTray::onChicletClick,this,_1)); LLSplitButton* presets = getChild<LLSplitButton>("presets"); @@ -76,14 +75,20 @@ LLBottomTray::LLBottomTray(const LLSD&) // Necessary for focus movement among child controls setFocusRoot(TRUE); - - LLActiveIMWindow::init(mIMWell); } BOOL LLBottomTray::postBuild() { + mCommitCallbackRegistrar.add("ShowCamMoveCtrls.Action", boost::bind(&LLBottomTray::onShowCamMoveCtrlsContextMenuItemClicked, this, _2)); + mEnableCallbackRegistrar.add("ShowCamMoveCtrls.EnableMenuItem", boost::bind(&LLBottomTray::onShowCamMoveCtrlsContextMenuItemEnabled, this, _2)); + + mShowCamMoveCtrlsContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_camera_move_controls.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gMenuHolder->addChild(mShowCamMoveCtrlsContextMenu); + mNearbyChatBar = getChild<LLNearbyChatBar>("chat_bar"); mToolbarStack = getChild<LLLayoutStack>("toolbar_stack"); + mMovementPanel = getChild<LLPanel>("movement_panel"); + mCamPanel = getChild<LLPanel>("cam_panel"); return TRUE; } @@ -119,6 +124,34 @@ void* LLBottomTray::createNearbyChatBar(void* userdata) return new LLNearbyChatBar(); } +LLIMChiclet* LLBottomTray::createIMChiclet(const LLUUID& session_id) +{ + if(session_id.isNull()) + { + return NULL; + } + + LLFloaterIMPanel* im = LLIMMgr::getInstance()->findFloaterBySession(session_id); + if (!im) + { + return NULL; //should never happen + } + + switch(im->getDialogType()) + { + case IM_NOTHING_SPECIAL: + return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id); + break; + case IM_SESSION_GROUP_START: + case IM_SESSION_INVITE: + return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id); + break; + default: + return NULL; + break; + } +} + //virtual void LLBottomTray::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) { @@ -130,12 +163,18 @@ void LLBottomTray::sessionAdded(const LLUUID& session_id, const std::string& nam } else { - LLIMChiclet* chiclet = getChicletPanel()->createChiclet<LLIMChiclet>(session_id); - chiclet->setIMSessionName(name); - chiclet->setOtherParticipantId(other_participant_id); + LLIMChiclet* chiclet = createIMChiclet(session_id); + if(chiclet) + { + chiclet->setIMSessionName(name); + chiclet->setOtherParticipantId(other_participant_id); + } + else + { + llerrs << "Could not create chiclet" << llendl; + } } } - updateImChicletCount(); } //virtual @@ -145,7 +184,6 @@ void LLBottomTray::sessionRemoved(const LLUUID& session_id) { getChicletPanel()->removeChiclet(session_id); } - updateImChicletCount(); } //virtual @@ -174,8 +212,9 @@ void LLBottomTray::setVisible(BOOL visible) child_it != mToolbarStack->getChildList()->end(); child_it++) { LLView* viewp = *child_it; + std::string name = viewp->getName(); - if ("chat_bar" == viewp->getName()) + if ("chat_bar" == name || "movement_panel" == name || "cam_panel" == name) continue; else { @@ -185,7 +224,45 @@ void LLBottomTray::setVisible(BOOL visible) } } -void LLBottomTray::updateImChicletCount() { - U32 chicletCount = mChicletPanel->getChicletCount(); - mIMWell->setCounter(chicletCount); +BOOL LLBottomTray::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mShowCamMoveCtrlsContextMenu) + { + mShowCamMoveCtrlsContextMenu->buildDrawLabels(); + mShowCamMoveCtrlsContextMenu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, mShowCamMoveCtrlsContextMenu, x, y); + } + + return TRUE; +} + +bool LLBottomTray::onShowCamMoveCtrlsContextMenuItemEnabled(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == "show_camera_move_controls") + { + return gSavedSettings.getBOOL("ShowCameraAndMoveControls"); + } + + return FALSE; +} + +void LLBottomTray::onShowCamMoveCtrlsContextMenuItemClicked(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == "show_camera_move_controls") + { + BOOL state = !gSavedSettings.getBOOL("ShowCameraAndMoveControls"); + + showCameraAndMoveControls(state); + gSavedSettings.setBOOL("ShowCameraAndMoveControls", state); + } +} + +void LLBottomTray::showCameraAndMoveControls(BOOL visible) +{ + mCamPanel->setVisible(visible); + mMovementPanel->setVisible(visible); } diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h index 7f606339bc..c3c840ede0 100644 --- a/indra/newview/llbottomtray.h +++ b/indra/newview/llbottomtray.h @@ -33,6 +33,8 @@ #ifndef LL_LLBOTTOMPANEL_H #define LL_LLBOTTOMPANEL_H +#include <llmenugl.h> + #include "llpanel.h" #include "llimview.h" @@ -42,6 +44,7 @@ class LLLayoutStack; class LLNotificationChiclet; class LLTalkButton; class LLNearbyChatBar; +class LLIMChiclet; class LLBottomTray : public LLSingleton<LLBottomTray> @@ -55,7 +58,6 @@ public: BOOL postBuild(); LLChicletPanel* getChicletPanel() {return mChicletPanel;} - LLNotificationChiclet* getIMWell() {return mIMWell;} LLNotificationChiclet* getSysWell() {return mSysWell;} LLNearbyChatBar* getNearbyChatBar() {return mNearbyChatBar;} @@ -68,8 +70,11 @@ public: virtual void onFocusLost(); virtual void setVisible(BOOL visible); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + void showCameraAndMoveControls(BOOL visible); + private: - void updateImChicletCount(); protected: @@ -77,15 +82,24 @@ protected: void onChicletClick(LLUICtrl* ctrl); + bool onShowCamMoveCtrlsContextMenuItemEnabled(const LLSD& userdata); + void onShowCamMoveCtrlsContextMenuItemClicked(const LLSD& userdata); + static void* createNearbyChatBar(void* userdata); + /** + * Creates IM Chiclet based on session type (IM chat or Group chat) + */ + LLIMChiclet* createIMChiclet(const LLUUID& session_id); + LLChicletPanel* mChicletPanel; - LLNotificationChiclet* mIMWell; LLNotificationChiclet* mSysWell; LLTalkButton* mTalkBtn; LLNearbyChatBar* mNearbyChatBar; LLLayoutStack* mToolbarStack; - + LLMenuGL* mShowCamMoveCtrlsContextMenu; + LLPanel* mMovementPanel; + LLPanel* mCamPanel; }; #endif // LL_LLBOTTOMPANEL_H diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp index 9399e1f68d..e6398dd47a 100644 --- a/indra/newview/llchatmsgbox.cpp +++ b/indra/newview/llchatmsgbox.cpp @@ -1,10 +1,11 @@ /** * @file llchatmsgbox.cpp + * @author Martin Reddy * @brief chat history text box, able to show array of strings with separator * - * $LicenseInfo:firstyear=2004&license=viewergpl$ + * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2004-2009, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -30,360 +31,96 @@ * $/LicenseInfo$ */ - #include "llviewerprecompiledheaders.h" #include "llchatmsgbox.h" #include "llwindow.h" -#include "llfocusmgr.h" - -static LLDefaultChildRegistry::Register<LLChatMsgBox> r("text_chat"); -LLChatMsgBox::Params::Params() -: text_color("text_color"), - highlight_on_hover("hover", false), - border_visible("border_visible", false), - border_drop_shadow_visible("border_drop_shadow_visible", false), - bg_visible("bg_visible", false), - use_ellipses("use_ellipses"), - word_wrap("word_wrap", false), - hover_color("hover_color"), - disabled_color("disabled_color"), - background_color("background_color"), - border_color("border_color"), - line_spacing("line_spacing", 4), - block_spacing("block_spacing",10), - text("text"), - font_shadow("font_shadow", LLFontGL::NO_SHADOW) -{} -LLChatMsgBox::LLChatMsgBox(const LLChatMsgBox::Params& p) -: LLUICtrl(p), - mFontGL(p.font), - mHoverActive( p.highlight_on_hover ), - mHasHover( FALSE ), - mBackgroundVisible( p.bg_visible ), - mBorderVisible( p.border_visible ), - mShadowType( p.font_shadow ), - mBorderDropShadowVisible( p.border_drop_shadow_visible ), - mUseEllipses( p.use_ellipses ), - mVAlign( LLFontGL::TOP ), - mClickedCallback(NULL), - mTextColor(p.text_color()), - mDisabledColor(p.disabled_color()), - mBackgroundColor(p.background_color()), - mBorderColor(p.border_color()), - mHoverColor(p.hover_color()), - mHAlign(p.font_halign), - mLineSpacing(p.line_spacing), - mBlockSpasing(p.block_spacing), - mWordWrap( p.word_wrap ), - mFontStyle(LLFontGL::getStyleFromString(p.font.style)) -{ - setText( p.text() ); -} +static LLDefaultChildRegistry::Register<LLChatMsgBox> r("text_chat"); -BOOL LLChatMsgBox::handleMouseDown(S32 x, S32 y, MASK mask) +LLChatMsgBox::Params::Params() : + block_spacing("block_spacing", 10) { - BOOL handled = FALSE; - - // HACK: Only do this if there actually is a click callback, so that - // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback) - { - handled = TRUE; - - // Route future Mouse messages here preemptively. (Release on mouse up.) - gFocusMgr.setMouseCapture( this ); - - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } - } - - return handled; + line_spacing = 4; } -BOOL LLChatMsgBox::handleMouseUp(S32 x, S32 y, MASK mask) -{ - BOOL handled = FALSE; - - // We only handle the click if the click both started and ended within us - - // HACK: Only do this if there actually is a click callback, so that - // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback - && hasMouseCapture()) - { - handled = TRUE; - - // Release the mouse - gFocusMgr.setMouseCapture( NULL ); - - if (getSoundFlags() & MOUSE_UP) - { - make_ui_sound("UISndClickRelease"); - } - - // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. - // If mouseup in the widget, it's been clicked - if (mClickedCallback) - { - mClickedCallback(); - } - } - - return handled; -} +LLChatMsgBox::LLChatMsgBox(const Params& p) : + LLTextBox(p), + mBlockSpacing(p.block_spacing) +{} -BOOL LLChatMsgBox::handleHover(S32 x, S32 y, MASK mask) +void LLChatMsgBox::addText( const LLStringExplicit& text ) { - BOOL handled = LLView::handleHover(x,y,mask); - if(mHoverActive) + LLWString t = mText.getWString(); + if (! t.empty()) { - mHasHover = TRUE; // This should be set every frame during a hover. - getWindow()->setCursor(UI_CURSOR_ARROW); + t += '\n'; } - - return (handled || mHasHover); -} - -void LLChatMsgBox::addText( const LLStringExplicit& text ) -{ - boost::shared_ptr<text_block> t(new text_block()); - t->text = wrapText(text); - setLineLengths(*t); - mTextStrings.push_back(t); + t += getWrappedText(text); + LLTextBox::setText(wstring_to_utf8str(t)); + mSeparatorOffset.push_back(getLength()); } void LLChatMsgBox::setText(const LLStringExplicit& text) { - mTextStrings.clear(); - + mSeparatorOffset.clear(); + mText.clear(); addText(text); - -} - -void LLChatMsgBox::resetLineLengths() -{ - for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); - it!=mTextStrings.end();++it) - { - boost::shared_ptr<text_block> tblock = *it; - setLineLengths(*tblock); - } -} - -void LLChatMsgBox::setLineLengths(text_block& t) -{ - t.lines.clear(); - - std::string::size_type cur = 0; - std::string::size_type len = t.text.length(); - - while (cur < len) - { - std::string::size_type end = t.text.getWString().find('\n', cur); - std::string::size_type runLen; - - if (end == std::string::npos) - { - runLen = len - cur; - cur = len; - } - else - { - runLen = end - cur; - cur = end + 1; // skip the new line character - } - - t.lines.push_back( (S32)runLen ); - } } -std::string LLChatMsgBox::wrapText(const LLStringExplicit& in_text, F32 max_width) -{ - if (max_width < 0.0f) - { - max_width = (F32)getRect().getWidth(); - } - - LLWString wtext = utf8str_to_wstring(in_text); - LLWString final_wtext; - - LLWString::size_type cur = 0;; - LLWString::size_type len = wtext.size(); - while (cur < len) - { - LLWString::size_type end = wtext.find('\n', cur); - if (end == LLWString::npos) - { - end = len; - } - - LLWString::size_type runLen = end - cur; - if (runLen > 0) - { - LLWString run(wtext, cur, runLen); - LLWString::size_type useLen = - mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); - - final_wtext.append(wtext, cur, useLen); - cur += useLen; - // not enough room to add any more characters - if (useLen == 0) break; - } - - if (cur < len) - { - if (wtext[cur] == '\n') - cur += 1; - else - final_wtext += '\n'; - } - } - - std::string final_text = wstring_to_utf8str(final_wtext); - return final_text; -} - -S32 LLChatMsgBox::getTextLinesNum() -{ - S32 num_lines = 0; - for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); - it!=mTextStrings.end();++it) - { - boost::shared_ptr<text_block> tblock = *it; - num_lines+=tblock->lines.size(); - } - - if( num_lines < 1 ) - { - num_lines = 1; - } - - return num_lines; +void LLChatMsgBox::setValue(const LLSD& value ) +{ + setText(value.asString()); } S32 LLChatMsgBox::getTextPixelHeight() { + S32 num_blocks = mSeparatorOffset.size(); S32 num_lines = getTextLinesNum(); - return (S32)(num_lines * mFontGL->getLineHeight() + (num_lines-1)*mLineSpacing + mBlockSpasing*(mTextStrings.size()-1) + 2*mLineSpacing);//some extra space -} - -void LLChatMsgBox::setValue(const LLSD& value ) -{ - setText(value.asString()); + return (S32)(num_lines * mDefaultFont->getLineHeight() + \ + (num_lines-1) * mLineSpacing + \ + (num_blocks-1) * mBlockSpacing + \ + 2 * mLineSpacing); } - -void LLChatMsgBox::draw() +S32 LLChatMsgBox::getTextLinesNum() { - if (mBorderVisible) - { - gl_rect_2d_offset_local(getLocalRect(), 2, FALSE); - } - - if( mBorderDropShadowVisible ) + S32 num_lines = getLineCount(); + if (num_lines < 1) { - static LLUICachedControl<LLColor4> color_drop_shadow ("ColorDropShadow", *(new LLColor4)); - static LLUICachedControl<S32> drop_shadow_tooltip ("DropShadowTooltip", 0); - gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, - color_drop_shadow, drop_shadow_tooltip); - } - - if (mBackgroundVisible) - { - LLRect r( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - gl_rect_2d( r, mBackgroundColor.get() ); - } - - S32 text_x = 0; - switch( mHAlign ) - { - case LLFontGL::LEFT: - break; - case LLFontGL::HCENTER: - text_x = getRect().getWidth() / 2; - break; - case LLFontGL::RIGHT: - text_x = getRect().getWidth() ; - break; - } - - S32 text_y = getRect().getHeight() ; - - if ( getEnabled() ) - { - if(mHasHover) - { - drawText( text_x, text_y, mHoverColor.get() ); - } - else - { - drawText( text_x, text_y, mTextColor.get() ); - } - } - else - { - drawText( text_x, text_y, mDisabledColor.get() ); - } - - if (sDebugRects) - { - drawDebugRect(); + num_lines = 1; } - - //// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview) - //std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); - //if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights)) - //{ - // drawDebugRect(); - //} - - mHasHover = FALSE; // This is reset every frame. -} - -void LLChatMsgBox::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - // reparse line lengths - LLView::reshape(width, height, called_from_parent); - resetLineLengths(); + + return num_lines; } -void LLChatMsgBox::drawText( S32 x, S32 y, const LLColor4& color ) +void LLChatMsgBox::drawText(S32 x, S32 y, const LLWString &text, const LLColor4 &color) { + S32 start = 0; S32 width = getRect().getWidth()-10; - - for(std::vector< boost::shared_ptr<text_block> >::iterator it = mTextStrings.begin(); - it!=mTextStrings.end();++it) + // iterate through each block of text that has been added + y -= mLineSpacing; + for (std::vector<S32>::iterator it = mSeparatorOffset.begin(); true ;) { - boost::shared_ptr<text_block> tblock = *it; + // display the text for this block + S32 num_chars = *it - start; + LLWString text = mDisplayText.substr(start, num_chars); + LLTextBox::drawText(x, y, text, color); - S32 cur_pos = 0; - for (std::vector<S32>::iterator iter = tblock->lines.begin(); - iter != tblock->lines.end(); ++iter) + // exit the loop if this is the last text block + start += num_chars + 1; // skip the newline + if (++it == mSeparatorOffset.end()) { - S32 line_length = *iter; - mFontGL->render(tblock->text, cur_pos, (F32)x, (F32)y, color, - mHAlign, mVAlign, - mFontStyle, - mShadowType, - line_length, getRect().getWidth(), NULL, mUseEllipses ); - cur_pos += line_length + 1; - y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing; - - } - std::vector< boost::shared_ptr<text_block> >::iterator next = it; - ++next; - if(next == mTextStrings.end()) break; - //separator - gl_line_2d(5,y-mBlockSpasing/2,width,y-mBlockSpasing/2,LLColor4::grey); - y-=mBlockSpasing; - } + } + // output a separator line between blocks + S32 num_lines = std::count(text.begin(), text.end(), '\n') + 1; + y -= num_lines * (llfloor(mDefaultFont->getLineHeight()) + mLineSpacing); + S32 sep_y = y - mBlockSpacing/2 + mLineSpacing/2; + gl_line_2d(5, sep_y, width, sep_y, LLColor4::grey); + y -= mBlockSpacing; + } } - diff --git a/indra/newview/llchatmsgbox.h b/indra/newview/llchatmsgbox.h index 61035499c7..b81b740bdc 100644 --- a/indra/newview/llchatmsgbox.h +++ b/indra/newview/llchatmsgbox.h @@ -1,10 +1,11 @@ /** * @file llchatmsgbox.h + * @author Martin Reddy * @brief chat history text box, able to show array of strings with separator * - * $LicenseInfo:firstyear=2004&license=viewergpl$ + * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2004-2009, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -33,127 +34,45 @@ #ifndef LL_LLCHATMSGBOX_H #define LL_LLCHATMSGBOX_H - +#include "lltextbox.h" #include "lluictrl.h" #include "v4color.h" #include "llstring.h" -#include "lluistring.h" - -class LLChatMsgBox -: public LLUICtrl +/// +/// LLChatMsgBox provides a text box with support for multiple blocks +/// of text that can be added incrementally. Each block of text is +/// visual separated from the previous block (e.g., with a horizontal +/// line). +/// +class LLChatMsgBox : + public LLTextBox { -protected: - struct text_block - { - LLUIString text; - std::vector<S32> lines; - }; public: - typedef boost::function<void (void)> callback_t; - - struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> + struct Params : public LLInitParam::Block<Params, LLTextBox::Params> { - Optional<std::string> text; - - Optional<bool> highlight_on_hover, - border_visible, - border_drop_shadow_visible, - bg_visible, - use_ellipses, - word_wrap; - - Optional<LLFontGL::ShadowType> font_shadow; - - Optional<LLUIColor> text_color, - hover_color, - disabled_color, - background_color, - border_color; - - Optional<S32> line_spacing; - - Optional<S32> block_spacing; + Optional<S32> block_spacing; Params(); }; + protected: LLChatMsgBox(const Params&); friend class LLUICtrlFactory; -public: - virtual void draw(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - - void setColor( const LLColor4& c ) { mTextColor = c; } - void setDisabledColor( const LLColor4& c) { mDisabledColor = c; } - void setBackgroundColor( const LLColor4& c) { mBackgroundColor = c; } - void setBorderColor( const LLColor4& c) { mBorderColor = c; } - - void setHoverColor( const LLColor4& c ) { mHoverColor = c; } - void setHoverActive( BOOL active ) { mHoverActive = active; } - - void setText( const LLStringExplicit& text ); - void addText( const LLStringExplicit& text ); - - void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } +public: + void setText(const LLStringExplicit &text); + void addText(const LLStringExplicit &text); - void setBackgroundVisible(BOOL visible) { mBackgroundVisible = visible; } - void setBorderVisible(BOOL visible) { mBorderVisible = visible; } - void setBorderDropshadowVisible(BOOL visible){ mBorderDropShadowVisible = visible; } - void setRightAlign() { mHAlign = LLFontGL::RIGHT; } - void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } - void setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); } // mouse down and up within button - - const LLFontGL* getFont() const { return mFontGL; } - - S32 getTextPixelHeight(); - S32 getTextLinesNum(); - - virtual void setValue(const LLSD& value ); - + S32 getTextPixelHeight(); + S32 getTextLinesNum(); + /*virtual*/ void setValue(const LLSD &value); + /*virtual*/ void drawText(S32 x, S32 y, const LLWString &text, const LLColor4 &color); private: - std::string wrapText (const LLStringExplicit& in_text, F32 max_width = -1.0); - - void setLineLengths (text_block& t); - void resetLineLengths (); - void drawText (S32 x, S32 y, const LLColor4& color ); - - const LLFontGL* mFontGL; - LLUIColor mTextColor; - LLUIColor mDisabledColor; - LLUIColor mBackgroundColor; - LLUIColor mBorderColor; - LLUIColor mHoverColor; - - BOOL mHoverActive; - BOOL mHasHover; - BOOL mBackgroundVisible; - BOOL mBorderVisible; - BOOL mWordWrap; - - U8 mFontStyle; // style bit flags for font - LLFontGL::ShadowType mShadowType; - BOOL mBorderDropShadowVisible; - BOOL mUseEllipses; - - S32 mLineSpacing; - S32 mBlockSpasing; - - LLFontGL::HAlign mHAlign; - LLFontGL::VAlign mVAlign; - - callback_t mClickedCallback; - - - //same as mLineLengthList and mText in LLTextBox - std::vector< boost::shared_ptr<text_block> > mTextStrings; - + S32 mBlockSpacing; + std::vector<S32> mSeparatorOffset; }; #endif diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 6b4dfa73a4..808fcde312 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -47,13 +47,11 @@ #include "llvoicecontrolpanel.h" #include "llgroupmgr.h" -static const std::string P2P_MENU_NAME = "IMChiclet P2P Menu"; -static const std::string GROUP_MENU_NAME = "IMChiclet Group Menu"; - static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel"); static LLDefaultChildRegistry::Register<LLTalkButton> t2("chiclet_talk"); static LLDefaultChildRegistry::Register<LLNotificationChiclet> t3("chiclet_notification"); -static LLDefaultChildRegistry::Register<LLIMChiclet> t4("chiclet_im"); +static LLDefaultChildRegistry::Register<LLIMP2PChiclet> t4("chiclet_im_p2p"); +static LLDefaultChildRegistry::Register<LLIMGroupChiclet> t5("chiclet_im_group"); S32 LLNotificationChiclet::mUreadSystemNotifications = 0; S32 LLNotificationChiclet::mUreadIMNotifications = 0; @@ -119,6 +117,10 @@ boost::signals2::connection LLNotificationChiclet::setClickCallback( return mButton->setClickedCallback(cb); } +void LLNotificationChiclet::setToggleState(BOOL toggled) { + mButton->setToggleState(toggled); +} + void LLNotificationChiclet::updateUreadIMNotifications() { mUreadIMNotifications = gIMMgr->getNumberOfUnreadIM(); @@ -187,9 +189,48 @@ void LLChiclet::setValue(const LLSD& value) ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -LLIMChiclet::Params::Params() +LLIMChiclet::LLIMChiclet(const LLChiclet::Params& p) +: LLChiclet(p) +{ +} + +void LLIMChiclet::onMouseDown() +{ + LLIMFloater::toggle(getSessionId()); + setCounter(0); +} + +BOOL LLIMChiclet::handleMouseDown(S32 x, S32 y, MASK mask) +{ + onMouseDown(); + return LLChiclet::handleMouseDown(x, y, mask); +} + +void LLIMChiclet::draw() +{ + LLUICtrl::draw(); + + //if we have a docked floater, we want to position it relative to us + LLIMFloater* im_floater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", getSessionId()); + + if (im_floater && im_floater->isDocked()) + { + S32 x, y; + getParent()->localPointToScreen(getRect().getCenterX(), 0, &x, &y); + im_floater->translate(x - im_floater->getRect().getCenterX(), 10 - im_floater->getRect().mBottom); + //set this so the docked floater knows it's been positioned and can now draw + im_floater->setPositioned(true); + } + + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.0f,0.0f,0.0f,1.f), FALSE); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLIMP2PChiclet::Params::Params() : avatar_icon("avatar_icon") -, group_insignia("group_insignia") , unread_notifications("unread_notifications") , speaker("speaker") , show_speaker("show_speaker") @@ -197,13 +238,8 @@ LLIMChiclet::Params::Params() rect(LLRect(0, 25, 45, 0)); avatar_icon.name("avatar_icon"); - avatar_icon.visible(false); avatar_icon.rect(LLRect(0, 25, 25, 0)); - - //it's an icon for a group in case there is a group chat created - group_insignia.name("group_icon"); - group_insignia.visible(false); - group_insignia.rect(LLRect(0, 25, 25, 0)); + avatar_icon.mouse_opaque(false); unread_notifications.name("unread"); unread_notifications.rect(LLRect(25, 25, 45, 0)); @@ -211,6 +247,7 @@ LLIMChiclet::Params::Params() unread_notifications.font_halign(LLFontGL::HCENTER); unread_notifications.v_pad(5); unread_notifications.text_color(LLColor4::white); + unread_notifications.mouse_opaque(false); speaker.name("speaker"); speaker.rect(LLRect(45, 25, 65, 0)); @@ -218,25 +255,16 @@ LLIMChiclet::Params::Params() show_speaker = false; } -LLIMChiclet::LLIMChiclet(const Params& p) -: LLChiclet(p) -, LLGroupMgrObserver(LLUUID()) -, mAvatarCtrl(NULL) -, mGroupInsignia(NULL) +LLIMP2PChiclet::LLIMP2PChiclet(const Params& p) +: LLIMChiclet(p) +, mChicletIconCtrl(NULL) , mCounterCtrl(NULL) , mSpeakerCtrl(NULL) -, mShowSpeaker(p.show_speaker) , mPopupMenu(NULL) { LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon; - mAvatarCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params); - addChild(mAvatarCtrl); - - //Before setOtherParticipantId() we are UNAWARE which dialog type will it be - //so keeping both icons for all both p2p and group chat cases - LLIconCtrl::Params grop_icon_params = p.group_insignia; - mGroupInsignia = LLUICtrlFactory::create<LLIconCtrl>(grop_icon_params); - addChild(mGroupInsignia); + mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params); + addChild(mChicletIconCtrl); LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications; mCounterCtrl = LLUICtrlFactory::create<LLChicletNotificationCounterCtrl>(unread_params); @@ -249,16 +277,10 @@ LLIMChiclet::LLIMChiclet(const Params& p) mSpeakerCtrl = LLUICtrlFactory::create<LLChicletSpeakerCtrl>(speaker_params); addChild(mSpeakerCtrl); - setShowSpeaker(getShowSpeaker()); -} - -LLIMChiclet::~LLIMChiclet() -{ - LLGroupMgr::getInstance()->removeObserver(this); + setShowSpeaker(p.show_speaker); } - -void LLIMChiclet::setCounter(S32 counter) +void LLIMP2PChiclet::setCounter(S32 counter) { mCounterCtrl->setCounter(counter); @@ -279,15 +301,9 @@ void LLIMChiclet::setCounter(S32 counter) } } -void LLIMChiclet::onMouseDown() -{ - LLIMFloater::toggle(getSessionId()); - setCounter(0); -} - -LLRect LLIMChiclet::getRequiredRect() +LLRect LLIMP2PChiclet::getRequiredRect() { - LLRect rect(0, 0, mAvatarCtrl->getRect().getWidth(), 0); + LLRect rect(0, 0, mChicletIconCtrl->getRect().getWidth(), 0); if(getShowCounter()) { rect.mRight += mCounterCtrl->getRequiredRect().getWidth(); @@ -299,169 +315,234 @@ LLRect LLIMChiclet::getRequiredRect() return rect; } -void LLIMChiclet::setShowCounter(bool show) +void LLIMP2PChiclet::setOtherParticipantId(const LLUUID& other_participant_id) { - bool needs_resize = getShowCounter() != show; - - LLChiclet::setShowCounter(show); - mCounterCtrl->setVisible(getShowCounter()); - - if(needs_resize) - { - onChicletSizeChanged(); - } + LLIMChiclet::setOtherParticipantId(other_participant_id); + mChicletIconCtrl->setValue(getOtherParticipantId()); } - -void LLIMChiclet::setSessionId(const LLUUID& session_id) +void LLIMP2PChiclet::updateMenuItems() { - LLChiclet::setSessionId(session_id); + if(!mPopupMenu) + return; + if(getSessionId().isNull()) + return; - //for a group chat session_id = group_id - LLFloaterIMPanel* im = LLIMMgr::getInstance()->findFloaterBySession(session_id); - if (!im) return; //should never happen - - EInstantMessage type = im->getDialogType(); - if (type == IM_SESSION_INVITE || type == IM_SESSION_GROUP_START) - { - if (!gAgent.isInGroup(session_id)) return; + bool is_friend = LLAvatarActions::isFriend(getOtherParticipantId()); - if (mGroupInsignia) { - LLGroupMgr* grp_mgr = LLGroupMgr::getInstance(); - LLGroupMgrGroupData* group_data = grp_mgr->getGroupData(session_id); - if (group_data && group_data->mInsigniaID.notNull()) - { - mGroupInsignia->setVisible(TRUE); - mGroupInsignia->setValue(group_data->mInsigniaID); - } - else - { - mID = session_id; //needed for LLGroupMgrObserver - grp_mgr->addObserver(this); - grp_mgr->sendGroupPropertiesRequest(session_id); - } - } - } + mPopupMenu->getChild<LLUICtrl>("Add Friend")->setEnabled(!is_friend); + mPopupMenu->getChild<LLUICtrl>("Remove Friend")->setEnabled(is_friend); } -void LLIMChiclet::setIMSessionName(const std::string& name) +BOOL LLIMP2PChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) { - setToolTip(name); + if(!mPopupMenu) + { + createPopupMenu(); + } + + if (mPopupMenu) + { + updateMenuItems(); + mPopupMenu->arrangeAndClear(); + LLMenuGL::showPopup(this, mPopupMenu, x, y); + } + + return TRUE; } -//session id should be set before calling this -void LLIMChiclet::setOtherParticipantId(const LLUUID& other_participant_id) +void LLIMP2PChiclet::createPopupMenu() { - llassert(getSessionId().notNull()); + if(mPopupMenu) + { + llwarns << "Menu already exists" << llendl; + return; + } + if(getSessionId().isNull()) + { + return; + } - LLFloaterIMPanel*floater = gIMMgr->findFloaterBySession(getSessionId()); + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("IMChicletMenu.Action", boost::bind(&LLIMP2PChiclet::onMenuItemClicked, this, _2)); - //all alive sessions have alive floater, haven't they? - llassert(floater); + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> + ("menu_imchiclet_p2p.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +} - mOtherParticipantId = other_participant_id; +void LLIMP2PChiclet::onMenuItemClicked(const LLSD& user_data) +{ + std::string level = user_data.asString(); + LLUUID other_participant_id = getOtherParticipantId(); - if (mAvatarCtrl && floater->getDialogType() == IM_NOTHING_SPECIAL) + if("profile" == level) { - mAvatarCtrl->setVisible(TRUE); - mAvatarCtrl->setValue(other_participant_id); + LLAvatarActions::showProfile(other_participant_id); + } + else if("im" == level) + { + LLAvatarActions::startIM(other_participant_id); + } + else if("add" == level) + { + LLAvatarActions::requestFriendshipDialog(other_participant_id); } } - -void LLIMChiclet::changed(LLGroupChange gc) +void LLIMP2PChiclet::setShowSpeaker(bool show) { - LLSD group_insignia = mGroupInsignia->getValue(); - if (group_insignia.isUUID() && group_insignia.asUUID().notNull()) return; + LLIMChiclet::setShowSpeaker(show); - if (GC_PROPERTIES == gc) + bool needs_resize = getShowSpeaker() != show; + mSpeakerCtrl->setVisible(getShowSpeaker()); + if(needs_resize) { - LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(getSessionId()); - if (group_data && group_data->mInsigniaID.notNull()) - { - mGroupInsignia->setVisible(TRUE); - mGroupInsignia->setValue(group_data->mInsigniaID); - } + onChicletSizeChanged(); } } -LLUUID LLIMChiclet::getOtherParticipantId() +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLIMGroupChiclet::Params::Params() +: group_icon("group_icon") { - return mOtherParticipantId; + rect(LLRect(0, 25, 45, 0)); + + group_icon.name("group_icon"); + group_icon.rect(LLRect(0, 25, 25, 0)); + + unread_notifications.name("unread"); + unread_notifications.rect(LLRect(25, 25, 45, 0)); + unread_notifications.font(LLFontGL::getFontSansSerif()); + unread_notifications.font_halign(LLFontGL::HCENTER); + unread_notifications.v_pad(5); + unread_notifications.text_color(LLColor4::white); + + speaker.name("speaker"); + speaker.rect(LLRect(45, 25, 65, 0)); + + show_speaker = false; } -void LLIMChiclet::updateMenuItems() +LLIMGroupChiclet::LLIMGroupChiclet(const Params& p) +: LLIMChiclet(p) +, LLGroupMgrObserver(LLUUID::null) +, mChicletIconCtrl(NULL) +, mCounterCtrl(NULL) +, mSpeakerCtrl(NULL) +, mPopupMenu(NULL) { - if(!mPopupMenu) - return; - if(getSessionId().isNull()) - return; + LLChicletGroupIconCtrl::Params avatar_params = p.group_icon; + mChicletIconCtrl = LLUICtrlFactory::create<LLChicletGroupIconCtrl>(avatar_params); + addChild(mChicletIconCtrl); - if(P2P_MENU_NAME == mPopupMenu->getName()) - { - bool is_friend = LLAvatarActions::isFriend(getOtherParticipantId()); + LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications; + mCounterCtrl = LLUICtrlFactory::create<LLChicletNotificationCounterCtrl>(unread_params); + addChild(mCounterCtrl); - mPopupMenu->getChild<LLUICtrl>("Add Friend")->setEnabled(!is_friend); - mPopupMenu->getChild<LLUICtrl>("Remove Friend")->setEnabled(is_friend); - } + setCounter(getCounter()); + setShowCounter(getShowCounter()); + + LLChicletSpeakerCtrl::Params speaker_params = p.speaker; + mSpeakerCtrl = LLUICtrlFactory::create<LLChicletSpeakerCtrl>(speaker_params); + addChild(mSpeakerCtrl); + + setShowSpeaker(p.show_speaker); } -BOOL LLIMChiclet::handleMouseDown(S32 x, S32 y, MASK mask) +LLIMGroupChiclet::~LLIMGroupChiclet() { - onMouseDown(); - return LLChiclet::handleMouseDown(x, y, mask); + LLGroupMgr::getInstance()->removeObserver(this); } -void LLIMChiclet::setShowSpeaker(bool show) +void LLIMGroupChiclet::setCounter(S32 counter) { - bool needs_resize = getShowSpeaker() != show; - - mShowSpeaker = show; - mSpeakerCtrl->setVisible(getShowSpeaker()); + mCounterCtrl->setCounter(counter); - if(needs_resize) + if(getShowCounter()) { - onChicletSizeChanged(); + LLRect counter_rect = mCounterCtrl->getRect(); + LLRect required_rect = mCounterCtrl->getRequiredRect(); + bool needs_resize = required_rect.getWidth() != counter_rect.getWidth(); + + if(needs_resize) + { + counter_rect.mRight = counter_rect.mLeft + required_rect.getWidth(); + mCounterCtrl->reshape(counter_rect.getWidth(), counter_rect.getHeight()); + mCounterCtrl->setRect(counter_rect); + + onChicletSizeChanged(); + } } } -void LLIMChiclet::draw() +LLRect LLIMGroupChiclet::getRequiredRect() { - LLUICtrl::draw(); + LLRect rect(0, 0, mChicletIconCtrl->getRect().getWidth(), 0); + if(getShowCounter()) + { + rect.mRight += mCounterCtrl->getRequiredRect().getWidth(); + } + if(getShowSpeaker()) + { + rect.mRight += mSpeakerCtrl->getRect().getWidth(); + } + return rect; +} - //if we have a docked floater, we want to position it relative to us - LLIMFloater* im_floater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", getSessionId()); +void LLIMGroupChiclet::setSessionId(const LLUUID& session_id) +{ + LLChiclet::setSessionId(session_id); - if (im_floater && im_floater->isDocked()) + LLGroupMgr* grp_mgr = LLGroupMgr::getInstance(); + LLGroupMgrGroupData* group_data = grp_mgr->getGroupData(session_id); + if (group_data && group_data->mInsigniaID.notNull()) { - S32 x, y; - getParent()->localPointToScreen(getRect().getCenterX(), 0, &x, &y); - im_floater->translate(x - im_floater->getRect().getCenterX(), 10 - im_floater->getRect().mBottom); - //set this so the docked floater knows it's been positioned and can now draw - im_floater->setPositioned(true); + mChicletIconCtrl->setValue(group_data->mInsigniaID); } + else + { + if(getSessionId() != mID) + { + grp_mgr->removeObserver(this); + mID = getSessionId(); + grp_mgr->addObserver(this); + } + grp_mgr->sendGroupPropertiesRequest(session_id); + } +} - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.0f,0.0f,0.0f,1.f), FALSE); +void LLIMGroupChiclet::changed(LLGroupChange gc) +{ + if (GC_PROPERTIES == gc) + { + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(getSessionId()); + if (group_data) + { + mChicletIconCtrl->setValue(group_data->mInsigniaID); + } + } } -BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) +BOOL LLIMGroupChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) { if(!mPopupMenu) + { createPopupMenu(); - - updateMenuItems(); + } if (mPopupMenu) { mPopupMenu->arrangeAndClear(); + LLMenuGL::showPopup(this, mPopupMenu, x, y); } - - LLMenuGL::showPopup(this, mPopupMenu, x, y); return TRUE; } -void LLIMChiclet::createPopupMenu() +void LLIMGroupChiclet::createPopupMenu() { if(mPopupMenu) { @@ -469,55 +550,41 @@ void LLIMChiclet::createPopupMenu() return; } if(getSessionId().isNull()) + { return; - - LLFloaterIMPanel*floater = gIMMgr->findFloaterBySession(getSessionId()); - if(!floater) - return; + } LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("IMChicletMenu.Action", boost::bind(&LLIMChiclet::onMenuItemClicked, this, _2)); + registrar.add("IMChicletMenu.Action", boost::bind(&LLIMGroupChiclet::onMenuItemClicked, this, _2)); - switch(floater->getDialogType()) - { - case IM_SESSION_GROUP_START: - mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> - ("menu_imchiclet_group.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - break; - case IM_NOTHING_SPECIAL: - mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> - ("menu_imchiclet_p2p.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - break; - default: - llwarns << "Unexpected dialog type" << llendl; - break; - } + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> + ("menu_imchiclet_group.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); } -void LLIMChiclet::onMenuItemClicked(const LLSD& user_data) +void LLIMGroupChiclet::onMenuItemClicked(const LLSD& user_data) { std::string level = user_data.asString(); - LLUUID other_participant_id = getOtherParticipantId(); + LLUUID group_id = getSessionId(); - if("profile" == level) + if("group chat" == level) { - LLAvatarActions::showProfile(other_participant_id); + LLGroupActions::startChat(group_id); } - else if("im" == level) - { - LLAvatarActions::startIM(other_participant_id); - } - else if("add" == level) - { - LLAvatarActions::requestFriendshipDialog(other_participant_id); - } - else if("group chat" == level) + else if("info" == level) { - LLGroupActions::startChat(other_participant_id); + LLGroupActions::show(group_id); } - else if("info" == level) +} + +void LLIMGroupChiclet::setShowSpeaker(bool show) +{ + LLIMChiclet::setShowSpeaker(show); + + bool needs_resize = getShowSpeaker() != show; + mSpeakerCtrl->setVisible(getShowSpeaker()); + if(needs_resize) { - LLGroupActions::show(other_participant_id); + onChicletSizeChanged(); } } @@ -1178,6 +1245,28 @@ LLChicletAvatarIconCtrl::LLChicletAvatarIconCtrl(const Params& p) ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +LLChicletGroupIconCtrl::LLChicletGroupIconCtrl(const Params& p) +: LLIconCtrl(p) +, mDefaultIcon(p.default_icon) +{ +} + +void LLChicletGroupIconCtrl::setValue(const LLSD& value ) +{ + if(value.asUUID().isNull()) + { + LLIconCtrl::setValue(mDefaultIcon); + } + else + { + LLIconCtrl::setValue(value); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p) : LLIconCtrl(p) { diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index b1e73c9d8d..f96dfb69ec 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -95,7 +95,7 @@ private: }; /* - * Class for displaying avatar's icon. + * Class for displaying avatar's icon in P2P chiclet. */ class LLChicletAvatarIconCtrl : public LLAvatarIconCtrl { @@ -116,6 +116,36 @@ protected: friend class LLUICtrlFactory; }; +/** + * Class for displaying group's icon in Group chiclet. + */ +class LLChicletGroupIconCtrl : public LLIconCtrl +{ +public: + + struct Params : public LLInitParam::Block<Params, LLIconCtrl::Params> + { + Optional<std::string> default_icon; + + Params() + : default_icon("default_icon", "default_land_picture.j2c") + { + }; + }; + + /** + * Sets icon, if value is LLUUID::null - default icon will be set. + */ + virtual void setValue(const LLSD& value ); + +protected: + + LLChicletGroupIconCtrl(const Params& p); + friend class LLUICtrlFactory; + + std::string mDefaultIcon; +}; + /* * Class for displaying status of Voice Chat */ @@ -231,53 +261,40 @@ private: chiclet_size_changed_signal_t mChicletSizeChangedSignal; }; + /* -* Implements Instant Message chiclet. -* IMChiclet displays avatar's icon, number of unread messages(optional) +* Base class for Instant Message chiclets. +* IMChiclet displays icon, number of unread messages(optional) * and voice chat status(optional). +* Every chiclet should override LLUICtrl::getRequiredRect and return +* desired width. */ -class LLIMChiclet : public LLChiclet, LLGroupMgrObserver +class LLIMChiclet : public LLChiclet { public: - struct Params : public LLInitParam::Block<Params, LLChiclet::Params> - { - Optional<LLChicletAvatarIconCtrl::Params> avatar_icon; - - Optional<LLIconCtrl::Params> group_insignia; - - Optional<LLChicletNotificationCounterCtrl::Params> unread_notifications; - - Optional<LLChicletSpeakerCtrl::Params> speaker; - - Optional<bool> show_speaker; - - Params(); - }; - - /*virtual*/ ~LLIMChiclet(); - - virtual void setSessionId(const LLUUID& session_id); + + /*virtual*/ ~LLIMChiclet() {}; /* * Sets IM session name. This name will be displayed in chiclet tooltip. */ - virtual void setIMSessionName(const std::string& name); + virtual void setIMSessionName(const std::string& name) { setToolTip(name); } /* * Sets id of person/group user is chatting with. * Session id should be set before calling this */ - virtual void setOtherParticipantId(const LLUUID& other_participant_id); + virtual void setOtherParticipantId(const LLUUID& other_participant_id) { mOtherParticipantId = other_participant_id; } /* * Gets id of person/group user is chatting with. */ - virtual LLUUID getOtherParticipantId(); + virtual LLUUID getOtherParticipantId() { return mOtherParticipantId; } /* * Shows/hides voice chat status control. */ - virtual void setShowSpeaker(bool show); + virtual void setShowSpeaker(bool show) { mShowSpeaker = show; } /* * Returns voice chat status control visibility. @@ -285,22 +302,6 @@ public: virtual bool getShowSpeaker() {return mShowSpeaker;}; /* - * Sets number of unread messages. Will update chiclet's width if number text - * exceeds size of counter and notify it's parent about size change. - */ - /*virtual*/ void setCounter(S32); - - /* - * Returns number of unread messages. - */ - /*virtual*/ S32 getCounter() { return mCounterCtrl->getCounter(); } - - /* - * Shows/hides number of unread messages. - */ - /*virtual*/ void setShowCounter(bool show); - - /* * Draws border around chiclet. */ /*virtual*/ void draw(); @@ -313,52 +314,13 @@ public: */ void onMouseDown(); - /* - * Returns rect, required to display chiclet. - * Width is the only valid value. - */ - /*virtual*/ LLRect getRequiredRect(); - - /** comes from LLGroupMgrObserver */ - virtual void changed(LLGroupChange gc); - protected: - LLIMChiclet(const Params& p); - friend class LLUICtrlFactory; - - /* - * Creates chiclet popup menu. Will create P2P or Group IM Chat menu - * based on other participant's id. - */ - virtual void createPopupMenu(); - - /* - * Processes clicks on chiclet popup menu. - */ - virtual void onMenuItemClicked(const LLSD& user_data); - - /* - * Enables/disables menus based on relationship with other participant. - */ - virtual void updateMenuItems(); - - /* - * Displays popup menu. - */ - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + LLIMChiclet(const LLChiclet::Params& p); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); protected: - LLChicletAvatarIconCtrl* mAvatarCtrl; - - /** the icon of a group in case of group chat */ - LLIconCtrl* mGroupInsignia; - LLChicletNotificationCounterCtrl* mCounterCtrl; - LLChicletSpeakerCtrl* mSpeakerCtrl; - - LLMenuGL* mPopupMenu; bool mShowSpeaker; @@ -387,6 +349,160 @@ public: sFindChicletsSignal; }; +/** + * Implements P2P chiclet. + */ +class LLIMP2PChiclet : public LLIMChiclet +{ +public: + struct Params : public LLInitParam::Block<Params, LLChiclet::Params> + { + Optional<LLChicletAvatarIconCtrl::Params> avatar_icon; + + Optional<LLChicletNotificationCounterCtrl::Params> unread_notifications; + + Optional<LLChicletSpeakerCtrl::Params> speaker; + + Optional<bool> show_speaker; + + Params(); + }; + + void setOtherParticipantId(const LLUUID& other_participant_id); + + /*virtual*/ void setShowSpeaker(bool show); + + /* + * Sets number of unread messages. Will update chiclet's width if number text + * exceeds size of counter and notify it's parent about size change. + */ + /*virtual*/ void setCounter(S32); + + /* + * Returns number of unread messages. + */ + /*virtual*/ S32 getCounter() { return mCounterCtrl->getCounter(); } + + /* + * Returns rect, required to display chiclet. + * Width is the only valid value. + */ + /*virtual*/ LLRect getRequiredRect(); + +protected: + LLIMP2PChiclet(const Params& p); + friend class LLUICtrlFactory; + + /* + * Creates chiclet popup menu. Will create P2P or Group IM Chat menu + * based on other participant's id. + */ + virtual void createPopupMenu(); + + /* + * Processes clicks on chiclet popup menu. + */ + virtual void onMenuItemClicked(const LLSD& user_data); + + /* + * Displays popup menu. + */ + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + /* + * Enables/disables menus based on relationship with other participant. + */ + virtual void updateMenuItems(); + +private: + + LLChicletAvatarIconCtrl* mChicletIconCtrl; + LLChicletNotificationCounterCtrl* mCounterCtrl; + LLChicletSpeakerCtrl* mSpeakerCtrl; + LLMenuGL* mPopupMenu; +}; + +/** + * Implements Group chat chiclet. + */ +class LLIMGroupChiclet : public LLIMChiclet, public LLGroupMgrObserver +{ +public: + + struct Params : public LLInitParam::Block<Params, LLChiclet::Params> + { + Optional<LLChicletGroupIconCtrl::Params> group_icon; + + Optional<LLChicletNotificationCounterCtrl::Params> unread_notifications; + + Optional<LLChicletSpeakerCtrl::Params> speaker; + + Optional<bool> show_speaker; + + Params(); + }; + + /** + * Sets session id. + * Session ID for group chat is actually Group ID. + */ + /*virtual*/ void setSessionId(const LLUUID& session_id); + + /** + * Callback for LLGroupMgrObserver, we get this when group data is available or changed. + * Sets group icon. + */ + /*virtual*/ void changed(LLGroupChange gc); + + /*virtual*/ void setShowSpeaker(bool show); + + /* + * Sets number of unread messages. Will update chiclet's width if number text + * exceeds size of counter and notify it's parent about size change. + */ + /*virtual*/ void setCounter(S32); + + /* + * Returns number of unread messages. + */ + /*virtual*/ S32 getCounter() { return mCounterCtrl->getCounter(); } + + /* + * Returns rect, required to display chiclet. + * Width is the only valid value. + */ + /*virtual*/ LLRect getRequiredRect(); + + ~LLIMGroupChiclet(); + +protected: + LLIMGroupChiclet(const Params& p); + friend class LLUICtrlFactory; + + /* + * Creates chiclet popup menu. Will create P2P or Group IM Chat menu + * based on other participant's id. + */ + virtual void createPopupMenu(); + + /* + * Processes clicks on chiclet popup menu. + */ + virtual void onMenuItemClicked(const LLSD& user_data); + + /* + * Displays popup menu. + */ + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + +private: + + LLChicletGroupIconCtrl* mChicletIconCtrl; + LLChicletNotificationCounterCtrl* mCounterCtrl; + LLChicletSpeakerCtrl* mSpeakerCtrl; + LLMenuGL* mPopupMenu; +}; + /* * Implements notification chiclet. Used to display total amount of unread messages * across all IM sessions, total amount of system notifications. @@ -421,6 +537,7 @@ public: void incUreadSystemNotifications() { setCounter(++mUreadSystemNotifications + mUreadIMNotifications); } void decUreadSystemNotifications() { setCounter(--mUreadSystemNotifications + mUreadIMNotifications); } void updateUreadIMNotifications(); + void setToggleState(BOOL toggled); protected: LLNotificationChiclet(const Params& p); diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 7ad60232c7..a7f0a8ff9a 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -55,6 +55,7 @@ #include "llviewerinventory.h" #include "llviewermenu.h" #include "llviewermenu.h" +#include "lltooldraganddrop.h" static LLDefaultChildRegistry::Register<LLFavoritesBarCtrl> r("favorites_bar"); @@ -73,6 +74,7 @@ public: , mLoaded(false) {} void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } + const LLUUID& getLandmarkId() const { return mLandmarkID; } const std::string& getSLURL() { @@ -130,8 +132,21 @@ public: msg = mUrlGetter.getSLURL(); return TRUE; } + + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) + { + LLFavoritesBarCtrl* fb = dynamic_cast<LLFavoritesBarCtrl*>(getParent()); + + if (fb) + { + fb->handleHover(x, y, mask); + } + + return LLButton::handleHover(x, y, mask); + } void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } + const LLUUID& getLandmarkId() const { return mUrlGetter.getLandmarkId(); } protected: LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {} @@ -141,6 +156,33 @@ private: LLSLURLGetter mUrlGetter; }; +class LLFavoritesToggleableMenu : public LLToggleableMenu +{ +public: + virtual BOOL handleHover(S32 x, S32 y, MASK mask) + { + if (fb) + { + fb->handleHover(x, y, mask); + } + + return LLToggleableMenu::handleHover(x, y, mask); + } + + void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; } + +protected: + LLFavoritesToggleableMenu(const LLToggleableMenu::Params& p): + LLToggleableMenu(p) + { + } + + friend class LLUICtrlFactory; + +private: + LLFavoritesBarCtrl* fb; +}; + /** * This class is needed to override LLMenuItemCallGL default handleToolTip function and * show SLURL as button tooltip. @@ -164,6 +206,18 @@ public: void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) + { + mMouseDownSignal(this, x, y, mask); + return LLMenuItemCallGL::handleMouseDown(x, y, mask); + } + + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) + { + mMouseUpSignal(this, x, y, mask); + return LLMenuItemCallGL::handleMouseUp(x, y, mask); + } + protected: LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {} @@ -181,6 +235,14 @@ struct LLFavoritesSort // TODO - made it customizible using gSavedSettings bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b) { + S32 sortField1 = a->getSortField(); + S32 sortField2 = b->getSortField(); + + if (!(sortField1 < 0 && sortField2 < 0)) + { + return sortField2 > sortField1; + } + time_t first_create = a->getCreationDate(); time_t second_create = b->getCreationDate(); if (first_create == second_create) @@ -239,29 +301,34 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, case DAD_LANDMARK: { // Copy the item into the favorites folder (if it's not already there). - LLInventoryItem *item = (LLInventoryItem *)cargo_data; - LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); - if (item->getParentUUID() == favorites_id) + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + + // check if we are dragging an existing item from the favorites bar + if (item && mDragItemId == item->getUUID()) { - llwarns << "Attemt to copy a favorite item into the same folder." << llendl; - break; + *accept = ACCEPT_YES_SINGLE; + + if (drop) + { + handleExistingFavoriteDragAndDrop(x, y); + } } + else + { + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + if (item->getParentUUID() == favorites_id) + { + llwarns << "Attemt to copy a favorite item into the same folder." << llendl; + break; + } - *accept = ACCEPT_YES_COPY_SINGLE; + *accept = ACCEPT_YES_COPY_SINGLE; - if (drop) - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - favorites_id, - std::string(), - LLPointer<LLInventoryCallback>(NULL)); - - llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl; + if (drop) + { + handleNewFavoriteDragAndDrop(item, favorites_id, x, y); + } } - } break; default: @@ -271,6 +338,61 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, return TRUE; } +void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y) +{ + LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(findChildByLocalCoords(x, y)); + + if (dest) + { + updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId()); + } + else + { + mItems.push_back(gInventory.getItem(mDragItemId)); + } + + saveItemsOrder(mItems); + + LLFavoritesToggleableMenu* menu = (LLFavoritesToggleableMenu*) mPopupMenuHandle.get(); + + if (menu && menu->getVisible()) + { + menu->setVisible(FALSE); + showDropDownMenu(); + } + + mDragItemId = LLUUID::null; + getWindow()->setCursor(UI_CURSOR_ARROW); +} + +void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y) +{ + LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(findChildByLocalCoords(x, y)); + + if (dest) + { + insertBeforeItem(mItems, dest->getLandmarkId(), item->getUUID()); + } + else + { + mItems.push_back(gInventory.getItem(item->getUUID())); + } + + saveItemsOrder(mItems); + + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + favorites_id, + std::string(), + LLPointer<LLInventoryCallback>(NULL)); + + getWindow()->setCursor(UI_CURSOR_ARROW); + + llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl; +} + //virtual void LLFavoritesBarCtrl::changed(U32 mask) { @@ -311,9 +433,9 @@ LLXMLNodePtr LLFavoritesBarCtrl::getButtonXMLNode() void LLFavoritesBarCtrl::updateButtons(U32 bar_width) { - LLInventoryModel::item_array_t items; + mItems.clear(); - if (!collectFavoriteItems(items)) + if (!collectFavoriteItems(mItems)) { return; } @@ -331,7 +453,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) const S32 buttonVGap = 2; - S32 count = items.count(); + S32 count = mItems.count(); const S32 buttonHPad = LLUI::sSettingGroups["config"]->getS32("ButtonHPad"); const S32 chevron_button_width = mFont->getWidth(">>") + buttonHPad * 2; @@ -369,7 +491,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) S32 i; for (i = 0; i < mFirstDropDownItem; ++i) { - if (mItemNamesCache.get(i) != items.get(i)->getName()) + if (mItemNamesCache.get(i) != mItems.get(i)->getName()) { break; } @@ -387,7 +509,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) mItemNamesCache.clear(); for (S32 i = 0; i < mFirstDropDownItem; i++) { - mItemNamesCache.put(items.get(i)->getName()); + mItemNamesCache.put(mItems.get(i)->getName()); } // Rebuild the buttons only @@ -404,7 +526,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) } } - createButtons(items, buttonXMLNode, buttonWidth, buttonHGap); + createButtons(mItems, buttonXMLNode, buttonWidth, buttonHGap); } // Chevron button @@ -467,9 +589,9 @@ void LLFavoritesBarCtrl::createButtons(const LLInventoryModel::item_array_t &ite { S32 curr_x = buttonHGap; // Adding buttons - for(S32 i = mFirstDropDownItem -1; i >= 0; i--) + for(S32 i = mFirstDropDownItem -1, j = 0; i >= 0; i--) { - LLInventoryItem* item = items.get(i); + LLViewerInventoryItem* item = items.get(j++); LLFavoriteLandmarkButton* fav_btn = LLUICtrlFactory::defaultBuilder<LLFavoriteLandmarkButton>(buttonXMLNode, this, NULL); if (NULL == fav_btn) @@ -488,6 +610,10 @@ void LLFavoritesBarCtrl::createButtons(const LLInventoryModel::item_array_t &ite fav_btn->setToolTip(item->getName()); fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); + + fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); + sendChildToBack(fav_btn); curr_x += buttonWidth + buttonHGap; @@ -521,6 +647,15 @@ BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &it std::sort(items.begin(), items.end(), LLFavoritesSort()); + if (needToSaveItemsOrder(items)) + { + S32 sortField = 0; + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + (*i)->setSortField(++sortField); + } + } + return TRUE; } @@ -528,7 +663,7 @@ void LLFavoritesBarCtrl::showDropDownMenu() { if (mPopupMenuHandle.isDead()) { - LLToggleableMenu::Params menu_p; + LLFavoritesToggleableMenu::Params menu_p; menu_p.name("favorites menu"); menu_p.can_tear_off(false); menu_p.visible(false); @@ -536,26 +671,26 @@ void LLFavoritesBarCtrl::showDropDownMenu() menu_p.max_scrollable_items = 10; menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; - LLToggleableMenu* menu = LLUICtrlFactory::create<LLToggleableMenu>(menu_p); - + LLFavoritesToggleableMenu* menu = LLUICtrlFactory::create<LLFavoritesToggleableMenu>(menu_p); + menu->initFavoritesBarPointer(this); mPopupMenuHandle = menu->getHandle(); } - LLToggleableMenu* menu = (LLToggleableMenu*)mPopupMenuHandle.get(); + LLFavoritesToggleableMenu* menu = (LLFavoritesToggleableMenu*)mPopupMenuHandle.get(); if(menu) { if (!menu->toggleVisibility()) return; - LLInventoryModel::item_array_t items; + mItems.clear(); - if (!collectFavoriteItems(items)) + if (!collectFavoriteItems(mItems)) { return; } - S32 count = items.count(); + S32 count = mItems.count(); // Check it there are changed items, since last call if (mItemNamesCache.size() == count) @@ -563,7 +698,7 @@ void LLFavoritesBarCtrl::showDropDownMenu() S32 i; for (i = mFirstDropDownItem; i < count; i++) { - if (mItemNamesCache.get(i) != items.get(i)->getName()) + if (mItemNamesCache.get(i) != mItems.get(i)->getName()) { break; } @@ -587,7 +722,7 @@ void LLFavoritesBarCtrl::showDropDownMenu() { for (S32 i = mFirstDropDownItem; i < count; i++) { - mItemNamesCache.put(items.get(i)->getName()); + mItemNamesCache.put(mItems.get(i)->getName()); } } @@ -598,17 +733,18 @@ void LLFavoritesBarCtrl::showDropDownMenu() for(S32 i = mFirstDropDownItem; i < count; i++) { - LLInventoryItem* item = items.get(i); + LLViewerInventoryItem* item = mItems.get(i); const std::string& item_name = item->getName(); - LLMenuItemCallGL::Params item_params; + LLFavoriteLandmarkMenuItem::Params item_params; item_params.name(item_name); item_params.label(item_name); item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create<LLFavoriteLandmarkMenuItem>(item_params); menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this,item->getUUID(),_1,_2,_3,_4)); - menu_item->setLandmarkID(item->getUUID()); + menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); // Check whether item name wider than menu if (menu_item->getNominalWidth() > max_width) @@ -644,13 +780,6 @@ void LLFavoritesBarCtrl::showDropDownMenu() void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id) { - LLInventoryModel::item_array_t items; - - if (!collectFavoriteItems(items)) - { - return; - } - // We only have one Inventory, gInventory. Some day this should be better abstracted. LLInvFVBridgeAction::doAction(item_id,&gInventory); } @@ -797,5 +926,135 @@ void LLFavoritesBarCtrl::pastFromClipboard() const } } +void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + mDragItemId = id; + mStartDrag = TRUE; + + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY); +} + +void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + mDragItemId = LLUUID::null; +} + +BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) +{ + if (mDragItemId != LLUUID::null && mStartDrag) + { + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY)) + { + LLToolDragAndDrop::getInstance()->beginDrag( + DAD_LANDMARK, mDragItemId, + LLToolDragAndDrop::SOURCE_LIBRARY); + + mStartDrag = FALSE; + + return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask); + } + } + + return TRUE; +} + +LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) +{ + LLUICtrl* ctrl = 0; + S32 screenX, screenY; + const child_list_t* list = getChildList(); + + localPointToScreen(x, y, &screenX, &screenY); + + // look for a child which contains the point (screenX, screenY) in it's rectangle + for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i) + { + LLRect rect; + localRectToScreen((*i)->getRect(), &rect); + + if (rect.pointInRect(screenX, screenY)) + { + ctrl = dynamic_cast<LLUICtrl*>(*i); + break; + } + } + + return ctrl; +} + +BOOL LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) +{ + BOOL result = FALSE; + + // if there is an item without sort order field set, we need to save items order + for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) + { + if ((*i)->getSortField() < 0) + { + result = TRUE; + break; + } + } + + return result; +} + +void LLFavoritesBarCtrl::saveItemsOrder(LLInventoryModel::item_array_t& items) +{ + int sortField = 0; + + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + LLViewerInventoryItem* item = *i; + + item->setSortField(++sortField); + item->setComplete(TRUE); + item->updateServer(FALSE); + + gInventory.updateItem(item); + } + + gInventory.notifyObservers(); +} + +LLInventoryModel::item_array_t::iterator LLFavoritesBarCtrl::findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) +{ + LLInventoryModel::item_array_t::iterator result = items.end(); + + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + if ((*i)->getUUID() == id) + { + result = i; + break; + } + } + + return result; +} + +void LLFavoritesBarCtrl::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId) +{ + LLViewerInventoryItem* srcItem = gInventory.getItem(srcItemId); + LLViewerInventoryItem* destItem = gInventory.getItem(destItemId); + + items.erase(findItemByUUID(items, srcItem->getUUID())); + items.insert(findItemByUUID(items, destItem->getUUID()), srcItem); +} + +void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId) +{ + LLViewerInventoryItem* beforeItem = gInventory.getItem(beforeItemId); + LLViewerInventoryItem* insertedItem = gInventory.getItem(insertedItemId); + + items.insert(findItemByUUID(items, beforeItem->getUUID()), insertedItem); +} // EOF diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 824b396add..4cd92d1a58 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -60,6 +60,8 @@ public: EAcceptance* accept, std::string& tooltip_msg); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + // LLInventoryObserver observer trigger virtual void changed(U32 mask); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); @@ -73,10 +75,12 @@ protected: void onButtonClick(LLUUID id); void onButtonRightClick(LLUUID id,LLView* button,S32 x,S32 y,MASK mask); + void onButtonMouseDown(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask); + void onButtonMouseUp(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask); + void doToSelected(const LLSD& userdata); BOOL isClipboardPasteable() const; void pastFromClipboard() const; - void showDropDownMenu(); @@ -94,8 +98,49 @@ protected: LLRect mChevronRect; std::string mChevronButtonToolTip; + +private: + /* + * Helper function to make code more readable. It handles all drag and drop + * operations of the existing favorites items on the favorites bar. + */ + void handleExistingFavoriteDragAndDrop(S32 x, S32 y); + + /* + * Helper function to make code more readable. It handles all drag and drop + * operations of the new landmark to the favorites bar. + */ + void handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y); + + // finds a control under the specified LOCAL point + LLUICtrl* findChildByLocalCoords(S32 x, S32 y); + + // checks if the current order of the favorites items must be saved + BOOL needToSaveItemsOrder(const LLInventoryModel::item_array_t& items); + + // saves current order of the favorites items + void saveItemsOrder(LLInventoryModel::item_array_t& items); + + /* + * changes favorites items order by insertion of the item identified by srcItemId + * BEFORE the item identified by destItemId. both items must exist in items array. + */ + void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId); + + /* + * inserts an item identified by insertedItemId BEFORE an item identified by beforeItemId. + * this function assumes that an item identified by insertedItemId doesn't exist in items array. + */ + void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId); + + // finds an item by it's UUID in the items array + LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id); + + BOOL mSkipUpdate; + BOOL mStartDrag; + LLUUID mDragItemId; + LLInventoryModel::item_array_t mItems; }; #endif // LL_LLFAVORITESBARCTRL_H - diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 56c5eaa70e..caa10e9452 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -99,24 +99,20 @@ BOOL LLFloaterAbout::postBuild() LLViewerTextEditor *credits_widget = getChild<LLViewerTextEditor>("credits_editor", true); - // For some reason, adding style doesn't work unless this is true. + // make sure that we handle hyperlinks in the About text support_widget->setParseHTML(TRUE); - // Text styles for release notes hyperlinks - LLStyle::Params link_style_params; - link_style_params.color.control = "HTMLLinkColor"; - link_style_params.link_href = get_viewer_release_notes_url(); - // Version string std::string version = LLTrans::getString("APP_NAME") + llformat(" %d.%d.%d (%d) %s %s (%s)\n", LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD, __DATE__, __TIME__, gSavedSettings.getString("VersionChannelName").c_str()); - support_widget->appendColoredText(version, FALSE, FALSE, LLUIColorTable::instance().getColor("TextFgReadOnlyColor")); - support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, link_style_params); std::string support; + support.append(version); + support.append("[" + get_viewer_release_notes_url() + " " + + LLTrans::getString("ReleaseNotes") + "]"); support.append("\n\n"); #if LL_MSVC @@ -131,10 +127,6 @@ BOOL LLFloaterAbout::postBuild() LLViewerRegion* region = gAgent.getRegion(); if (region) { - LLStyle::Params server_link_style_params; - server_link_style_params.color.control = "HTMLLinkColor"; - server_link_style_params.link_href = region->getCapability("ServerReleaseNotes"); - const LLVector3d &pos = gAgent.getPositionGlobal(); LLUIString pos_text = getString("you_are_at"); pos_text.setArg("[POSITION]", @@ -154,11 +146,9 @@ BOOL LLFloaterAbout::postBuild() support.append(")\n"); support.append(gLastVersionChannel); support.append("\n"); - - support_widget->appendColoredText(support, FALSE, FALSE, LLUIColorTable::instance().getColor("TextFgReadOnlyColor")); - support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, server_link_style_params); - - support = "\n\n"; + support.append("[" + LLWeb::escapeURL(region->getCapability("ServerReleaseNotes")) + + " " + LLTrans::getString("ReleaseNotes") + "]"); + support.append("\n\n"); } // *NOTE: Do not translate text like GPU, Graphics Card, etc - @@ -248,20 +238,20 @@ BOOL LLFloaterAbout::postBuild() } - static std::string get_viewer_release_notes_url() - { - std::ostringstream version; - version << LL_VERSION_MAJOR << "." - << LL_VERSION_MINOR << "." - << LL_VERSION_PATCH << "." - << LL_VERSION_BUILD; +static std::string get_viewer_release_notes_url() +{ + std::ostringstream version; + version << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; - LLSD query; - query["channel"] = gSavedSettings.getString("VersionChannelName"); - query["version"] = version.str(); + LLSD query; + query["channel"] = gSavedSettings.getString("VersionChannelName"); + query["version"] = version.str(); - std::ostringstream url; - url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query); + std::ostringstream url; + url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query); - return url.str(); - } + return LLWeb::escapeURL(url.str()); +} diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 0dee3a1e83..14fb93df61 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -47,7 +47,6 @@ #include "llconsole.h" #include "llfloateractivespeakers.h" #include "llfloaterchatterbox.h" -#include "llfloatermute.h" #include "llfloaterreg.h" #include "llfloaterscriptdebug.h" #include "llkeyboard.h" @@ -56,6 +55,7 @@ //#include "llresizehandle.h" #include "llchatbar.h" #include "llrecentpeople.h" +#include "llpanelblockedlist.h" #include "llstatusbar.h" #include "llviewertexteditor.h" #include "llviewergesture.h" // for triggering gestures @@ -280,7 +280,7 @@ void LLFloaterChat::onClickMute(void *data) LLMute mute(id); mute.setFromDisplayName(name); LLMuteList::getInstance()->add(mute); - LLFloaterReg::showInstance("mute"); + LLPanelBlockedList::showPanelAndSelect(mute.mID); } //static diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index eb73bd6d8f..0c77d88efb 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -194,6 +194,7 @@ BOOL LLPanelFriends::postBuild() mFriendsList->setMaxSelectable(MAX_FRIEND_SELECT); mFriendsList->setMaximumSelectCallback(boost::bind(&LLPanelFriends::onMaximumSelect)); mFriendsList->setCommitOnSelectionChange(TRUE); + mFriendsList->setContextMenu(LLScrollListCtrl::MENU_AVATAR); childSetCommitCallback("friend_list", onSelectName, this); getChild<LLScrollListCtrl>("friend_list")->setDoubleClickCallback(onClickIM, this); diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index 7a88612f1a..b1f40d9d1d 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -82,7 +82,12 @@ void LLFloaterGroupPicker::setPowersMask(U64 powers_mask) BOOL LLFloaterGroupPicker::postBuild() { LLScrollListCtrl* list_ctrl = getChild<LLScrollListCtrl>("group list"); - init_group_list(list_ctrl, gAgent.getGroupID(), mPowersMask); + if (list_ctrl) + { + init_group_list(list_ctrl, gAgent.getGroupID(), mPowersMask); + list_ctrl->setDoubleClickCallback(onBtnOK, this); + list_ctrl->setContextMenu(LLScrollListCtrl::MENU_GROUP); + } // Remove group "none" from list. Group "none" is added in init_group_list(). // Some UI elements use group "none", we need to manually delete it here. @@ -100,8 +105,6 @@ BOOL LLFloaterGroupPicker::postBuild() setDefaultBtn("OK"); - getChild<LLScrollListCtrl>("group list")->setDoubleClickCallback(onBtnOK, this); - childEnable("OK"); return TRUE; @@ -183,7 +186,13 @@ BOOL LLPanelGroups::postBuild() childSetTextArg("groupcount", "[COUNT]", llformat("%d",gAgent.mGroups.count())); childSetTextArg("groupcount", "[MAX]", llformat("%d",MAX_AGENT_GROUPS)); - init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID()); + LLScrollListCtrl *list = getChild<LLScrollListCtrl>("group list"); + if (list) + { + init_group_list(list, gAgent.getGroupID()); + list->setDoubleClickCallback(onBtnIM, this); + list->setContextMenu(LLScrollListCtrl::MENU_GROUP); + } childSetAction("Activate", onBtnActivate, this); @@ -199,8 +208,6 @@ BOOL LLPanelGroups::postBuild() setDefaultBtn("IM"); - getChild<LLScrollListCtrl>("group list")->setDoubleClickCallback(onBtnIM, this); - reset(); return TRUE; diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 4cd09faaaf..e5f5e8eedb 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -1061,6 +1061,7 @@ BOOL LLPanelLandObjects::postBuild() mOwnerList->sortByColumnIndex(3, FALSE); childSetCommitCallback("owner list", onCommitList, this); mOwnerList->setDoubleClickCallback(onDoubleClickOwner, this); + mOwnerList->setContextMenu(LLScrollListCtrl::MENU_AVATAR); return TRUE; } @@ -2297,11 +2298,17 @@ BOOL LLPanelLandAccess::postBuild() mListAccess = getChild<LLNameListCtrl>("AccessList"); if (mListAccess) + { mListAccess->sortByColumnIndex(0, TRUE); // ascending + mListAccess->setContextMenu(LLScrollListCtrl::MENU_AVATAR); + } mListBanned = getChild<LLNameListCtrl>("BannedList"); if (mListBanned) + { mListBanned->sortByColumnIndex(0, TRUE); // ascending + mListBanned->setContextMenu(LLScrollListCtrl::MENU_AVATAR); + } return TRUE; } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index c47c7b073c..d389cf06ec 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -61,6 +61,7 @@ #include "llnavigationbar.h" #include "llpanellogin.h" #include "llradiogroup.h" +#include "llsearchcombobox.h" #include "llsky.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" @@ -214,6 +215,11 @@ bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response // flag client texture cache for clearing next time the client runs gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); LLNotifications::instance().add("CacheWillClear"); + + LLSearchHistory::getInstance()->clearHistory(); + LLSearchHistory::getInstance()->save(); + LLSearchComboBox* search_ctrl = LLNavigationBar::getInstance()->getChild<LLSearchComboBox>("search_combo_box"); + search_ctrl->clearHistory(); } return false; diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index d05c9cb9a7..f334344279 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -725,7 +725,7 @@ void LLFloaterTools::onOpen(const LLSD& key) mTab->selectTabByName(panel); } - gMenuBarView->setItemVisible("BuildTools", TRUE); + //gMenuBarView->setItemVisible("BuildTools", TRUE); } void LLFloaterTools::onClose() @@ -755,7 +755,7 @@ void LLFloaterTools::onClose() // so manually reset tool to default (pie menu tool) LLToolMgr::getInstance()->getCurrentToolset()->selectFirstTool(); - gMenuBarView->setItemVisible("BuildTools", FALSE); + //gMenuBarView->setItemVisible("BuildTools", FALSE); } void click_popup_info(void*) diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index bef5f094e3..97b7f3e9ad 100644 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -173,6 +173,15 @@ bool LLFriendCardsManager::isCategoryInFriendFolder(const LLViewerInventoryCateg return TRUE == gInventory.isObjectDescendentOf(cat->getUUID(), findFriendFolderUUIDImpl()); } +bool LLFriendCardsManager::isAnyFriendCategory(const LLUUID& catID) const +{ + const LLUUID& friendFolderID = findFriendFolderUUIDImpl(); + if (catID == friendFolderID) + return true; + + return TRUE == gInventory.isObjectDescendentOf(catID, friendFolderID); +} + void LLFriendCardsManager::syncFriendsFolder() { //lets create "Friends" and "Friends/All" in the Inventory "Calling Cards" if they are absent @@ -305,10 +314,12 @@ void LLFriendCardsManager::findMatchedFriendCards(const LLUUID& avatarID, LLInve LLInventoryModel::cat_array_t cats; LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); - LLParticularBuddyCollector matchFunctor(avatarID); LLViewerInventoryCategory* friendFolder = gInventory.getCategory(friendFolderUUID); + if (NULL == friendFolder) + return; + LLParticularBuddyCollector matchFunctor(avatarID); LLInventoryModel::cat_array_t subFolders; subFolders.push_back(friendFolder); diff --git a/indra/newview/llfriendcard.h b/indra/newview/llfriendcard.h index 18a6d0ab69..aa391ce2c1 100644 --- a/indra/newview/llfriendcard.h +++ b/indra/newview/llfriendcard.h @@ -77,6 +77,11 @@ public: bool isCategoryInFriendFolder(const LLViewerInventoryCategory* cat) const; /** + * Checks is the specified category is a Friend folder or any its subfolder + */ + bool isAnyFriendCategory(const LLUUID& catID) const; + + /** * Synchronizes content of the Calling Card/Friends/All Global Inventory folder with Agent's Friend List */ void syncFriendsFolder(); diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 278fd5b9f6..73d3a60701 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -51,6 +51,8 @@ LLGroupList::Params::Params() LLGroupList::LLGroupList(const Params& p) : LLAvatarList(p) { + // display a context menu appropriate for a list of group names + setContextMenu(LLScrollListCtrl::MENU_GROUP); } static bool findInsensitive(std::string haystack, const std::string& needle_upper) diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 9cf3e57e22..674fff4040 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -2125,6 +2125,7 @@ BOOL LLIMFloater::postBuild() childSetCommitCallback("chat_editor", onSendMsg, this); mHistoryEditor = getChild<LLViewerTextEditor>("im_text"); + mHistoryEditor->setParseHTML(TRUE); setTitle(LLIMModel::instance().getName(mSessionID)); setDocked(true); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 5272bc2165..c1a5f21010 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1338,7 +1338,10 @@ S32 LLIMMgr::getNumberOfUnreadIM() S32 num = 0; for(it = LLIMModel::sSessionsMap.begin(); it != LLIMModel::sSessionsMap.end(); ++it) { - num += (*it).second->mNumUnread; + if((*it).first != mBeingRemovedSessionID) + { + num += (*it).second->mNumUnread; + } } return num; @@ -1460,6 +1463,9 @@ void LLIMMgr::removeSession(const LLUUID& session_id) clearPendingInvitation(session_id); clearPendingAgentListUpdates(session_id); } + + // for some purposes storing ID of a sessios that is being removed + mBeingRemovedSessionID = session_id; notifyObserverSessionRemoved(session_id); //if we don't clear session data on removing the session @@ -1467,6 +1473,9 @@ void LLIMMgr::removeSession(const LLUUID& session_id) //creating chiclets only on session created even, we need to handle chiclets creation //the same way as LLFloaterIMPanels were managed. LLIMModel::getInstance()->clearSession(session_id); + + // now this session is completely removed + mBeingRemovedSessionID.setNull(); } void LLIMMgr::inviteToSession( diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index ce6f0394dd..aed3b68471 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -264,6 +264,9 @@ private: LLSD mPendingInvitations; LLSD mPendingAgentListUpdates; + // ID of a session that is being removed: observers are already told + // that this session is being removed, but it is still present in the sessions' map + LLUUID mBeingRemovedSessionID; }; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 789e628b67..adc73111e0 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2420,8 +2420,14 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, drop); break; case DAD_CATEGORY: - accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, - drop); + if (LLFriendCardsManager::instance().isAnyFriendCategory(mUUID)) + { + accept = FALSE; + } + else + { + accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop); + } break; default: break; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index aadda3fbfd..8062da0dfe 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1112,7 +1112,7 @@ void LLInventoryModel::notifyObservers(const std::string service_name) observer->changed(mModifyMask); } - // safe way to incrament since changed may delete entries! (@!##%@!@&*!) + // safe way to increment since changed may delete entries! (@!##%@!@&*!) iter = mObservers.upper_bound(observer); } diff --git a/indra/newview/lllocationhistory.cpp b/indra/newview/lllocationhistory.cpp index c83cde9d83..d910dbf718 100644 --- a/indra/newview/lllocationhistory.cpp +++ b/indra/newview/lllocationhistory.cpp @@ -37,59 +37,41 @@ #include <iomanip> // for std::setw() #include "llui.h" - -const char LLLocationHistory::delimiter = '\t'; +#include "llsd.h" +#include "llsdserialize.h" LLLocationHistory::LLLocationHistory() : mFilename("typed_locations.txt") { } -void LLLocationHistory::addItem(const std::string & item, const std::string & tooltip) { +void LLLocationHistory::addItem(const LLLocationHistoryItem& item) { static LLUICachedControl<S32> max_items("LocationHistoryMaxSize", 100); // check if this item doesn't duplicate any existing one - std::vector<std::string>::iterator item_iter = std::find_if(mItems.begin(), mItems.end(), - boost::bind(&LLLocationHistory::equalByRegionParcel,this,_1,item)); + location_list_t::iterator item_iter = std::find(mItems.begin(), mItems.end(),item); if(item_iter != mItems.end()){ - /*replace duplicate. - * If an item's region and item's parcel are equal. - */ - mToolTips.erase(*item_iter); mItems.erase(item_iter); - } mItems.push_back(item); - mToolTips[item] = tooltip; - + // If the vector size exceeds the maximum, purge the oldest items. if ((S32)mItems.size() > max_items) { - for(std::vector<std::string>::iterator i = mItems.begin(); i != mItems.end()-max_items; ++i) { - mToolTips.erase(*i); - mItems.erase(i); + for(location_list_t::iterator i = mItems.begin(); i != mItems.end()-max_items; ++i) { + mItems.erase(i); } } } -/** - * check if the history item is equal. - * @return true - if region name and parcel is equal. +/* + * @brief Try to find item in history. + * If item has been founded, it will be places into end of history. + * @return true - item has founded */ -bool LLLocationHistory::equalByRegionParcel(const std::string& item, const std::string& newItem){ - - - S32 itemIndex = item.find('('); - S32 newItemIndex = newItem.find('('); - - std::string region_parcel = item.substr(0,itemIndex); - std::string new_region_parcel = newItem.substr(0,newItemIndex); - - return region_parcel == new_region_parcel; -} -bool LLLocationHistory::touchItem(const std::string & item) { +bool LLLocationHistory::touchItem(const LLLocationHistoryItem& item) { bool result = false; - std::vector<std::string>::iterator item_iter = std::find(mItems.begin(), mItems.end(), item); + location_list_t::iterator item_iter = std::find(mItems.begin(), mItems.end(), item); // the last used item should be the first in the history if (item_iter != mItems.end()) { @@ -104,13 +86,6 @@ bool LLLocationHistory::touchItem(const std::string & item) { void LLLocationHistory::removeItems() { mItems.clear(); - mToolTips.clear(); -} - -std::string LLLocationHistory::getToolTip(const std::string & item) const { - std::map<std::string, std::string>::const_iterator i = mToolTips.find(item); - - return i != mToolTips.end() ? i->second : ""; } bool LLLocationHistory::getMatchingItems(std::string substring, location_list_t& result) const @@ -123,7 +98,7 @@ bool LLLocationHistory::getMatchingItems(std::string substring, location_list_t& for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it) { - std::string haystack = *it; + std::string haystack = it->getLocation(); LLStringUtil::toLower(haystack); if (haystack.find(needle) != std::string::npos) @@ -139,7 +114,7 @@ void LLLocationHistory::dump() const int i = 0; for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it, ++i) { - llinfos << "#" << std::setw(2) << std::setfill('0') << i << ": " << *it << llendl; + llinfos << "#" << std::setw(2) << std::setfill('0') << i << ": " << it->getLocation() << llendl; } } @@ -158,11 +133,7 @@ void LLLocationHistory::save() const for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it) { - std::string tooltip = getToolTip(*it); - if(!tooltip.empty()) - { - file << (*it) << delimiter << tooltip << std::endl; - } + file << LLSDOStreamer<LLSDNotationFormatter>((*it).toLLSD()) << std::endl; } file.close(); @@ -186,16 +157,17 @@ void LLLocationHistory::load() // add each line in the file to the list std::string line; - + LLPointer<LLSDParser> parser = new LLSDNotationParser(); while (std::getline(file, line)) { - size_t dp = line.find(delimiter); - - if (dp != std::string::npos) { - const std::string reg_name = line.substr(0, dp); - const std::string tooltip = line.substr(dp + 1, std::string::npos); - - addItem(reg_name, tooltip); + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + llinfos<< "Parsing saved teleport history failed" << llendl; + break; } + + mItems.push_back(s_item); } file.close(); diff --git a/indra/newview/lllocationhistory.h b/indra/newview/lllocationhistory.h index 060a6b2fe8..5f9976f87a 100644 --- a/indra/newview/lllocationhistory.h +++ b/indra/newview/lllocationhistory.h @@ -40,21 +40,84 @@ #include <map> #include <boost/function.hpp> +class LLSD; + +enum ELocationType { + TYPED_REGION_SURL//region name or surl + ,LANDMARK // name of landmark + ,TELEPORT_HISTORY + }; +class LLLocationHistoryItem { + +public: + LLLocationHistoryItem(){} + LLLocationHistoryItem(std::string typed_location, + LLVector3d global_position, std::string tooltip,ELocationType type ): + mLocation(typed_location), + mGlobalPos(global_position), + mToolTip(tooltip), + mType(type) + {} + LLLocationHistoryItem(const LLLocationHistoryItem& item): + mGlobalPos(item.mGlobalPos), + mToolTip(item.mToolTip), + mLocation(item.mLocation), + mType(item.mType) + {} + LLLocationHistoryItem(const LLSD& data): + mLocation(data["location"]), + mGlobalPos(data["global_pos"]), + mToolTip(data["tooltip"]), + mType(ELocationType(data["item_type"].asInteger())) + {} + + bool operator==(const LLLocationHistoryItem& item) + { + // do not compare mGlobalPos, + // because of a rounding off , the history can contain duplicates + return mLocation == item.mLocation && (mType == item.mType); + } + bool operator!=(const LLLocationHistoryItem& item) + { + return ! (*this == item); + } + LLSD toLLSD() const + { + LLSD val; + val["location"]= mLocation; + val["global_pos"] = mGlobalPos.getValue(); + val["tooltip"] = mToolTip; + val["item_type"] = mType; + return val; + } + const std::string& getLocation() const { return mLocation; }; + const std::string& getToolTip() const { return mToolTip; }; + //static bool equalByRegionParcel(const LLLocationHistoryItem& item1, const LLLocationHistoryItem& item2); + static bool equalByLocation(const LLLocationHistoryItem& item1, const std::string& item_location) + { + return item1.getLocation() == item_location; + } + + LLVector3d mGlobalPos; // global position + std::string mToolTip;// SURL + std::string mLocation;// typed_location + ELocationType mType; +}; + class LLLocationHistory: public LLSingleton<LLLocationHistory> { LOG_CLASS(LLLocationHistory); public: - typedef std::vector<std::string> location_list_t; + typedef std::vector<LLLocationHistoryItem> location_list_t; typedef boost::function<void()> loaded_callback_t; typedef boost::signals2::signal<void()> loaded_signal_t; LLLocationHistory(); - void addItem(const std::string & item, const std::string & tooltip); - bool touchItem(const std::string & item); + void addItem(const LLLocationHistoryItem& item); + bool touchItem(const LLLocationHistoryItem& item); void removeItems(); - std::string getToolTip(const std::string & item) const; size_t getItemCount() const { return mItems.size(); } const location_list_t& getItems() const { return mItems; } bool getMatchingItems(std::string substring, location_list_t& result) const; @@ -65,10 +128,8 @@ public: void dump() const; private: - bool equalByRegionParcel(const std::string& item, const std::string& item_to_add); - const static char delimiter; - std::vector<std::string> mItems; - std::map<std::string, std::string> mToolTips; + + location_list_t mItems; std::string mFilename; /// File to store the history to. loaded_signal_t mLoadedSignal; }; diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index a8ec826e88..f54a614f62 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -48,6 +48,7 @@ #include "lllandmarkactions.h" #include "lllandmarklist.h" #include "lllocationhistory.h" +#include "llteleporthistory.h" #include "llsidetray.h" #include "llslurl.h" #include "lltrans.h" @@ -295,11 +296,19 @@ BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* if (LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen) && !msg.empty()) { if (mList->getRect().pointInRect(x, y)) { - LLLocationHistory* lh = LLLocationHistory::getInstance(); - const std::string tooltip = lh->getToolTip(msg); - - if (!tooltip.empty()) { - msg = tooltip; + S32 loc_x, loc_y; + //x,y - contain coordinates related to the location input control, but without taking the expanded list into account + //So we have to convert it again into local coordinates of mList + localPointToOtherView(x,y,&loc_x,&loc_y,mList); + + LLScrollListItem* item = mList->hitItem(loc_x,loc_y); + if (item) + { + LLSD value = item->getValue(); + if (value.has("tooltip")) + { + msg = value["tooltip"].asString(); + } } } @@ -448,18 +457,58 @@ void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) rebuildLocationHistory(filter); //Let's add landmarks to the top of the list if any - if( filter.size() !=0 ) + if(!filter.empty() ) { LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(filter, TRUE); for(U32 i=0; i < landmark_items.size(); i++) { - mList->addSimpleElement(landmark_items[i]->getName(), ADD_TOP); + LLSD value; + //TODO:: DO we need tooltip for Landmark?? + + value["item_type"] = LANDMARK; + value["AssetUUID"] = landmark_items[i]->getAssetUUID(); + add(landmark_items[i]->getName(), value); + + } + //Let's add teleport history items + LLTeleportHistory* th = LLTeleportHistory::getInstance(); + LLTeleportHistory::slurl_list_t th_items = th->getItems(); + + std::set<std::string> new_item_titles;// duplicate control + LLTeleportHistory::slurl_list_t::iterator result = std::find_if( + th_items.begin(), th_items.end(), boost::bind( + &LLLocationInputCtrl::findTeleportItemsByTitle, this, + _1, filter)); + + while (result != th_items.end()) + { + //mTitile format - region_name[, parcel_name] + //mFullTitile format - region_name[, parcel_name] (local_x,local_y, local_z) + if (new_item_titles.insert(result->mFullTitle).second) + { + LLSD value; + value["item_type"] = TELEPORT_HISTORY; + value["global_pos"] = result->mGlobalPos.getValue(); + std::string region_name = result->mTitle.substr(0, result->mTitle.find(',')); + //TODO*: add Surl to teleportitem or parse region name from title + value["tooltip"] = LLSLURL::buildSLURLfromPosGlobal(region_name, + result->mGlobalPos, false); + add(result->getTitle(), value); + } + result = std::find_if(result + 1, th_items.end(), boost::bind( + &LLLocationInputCtrl::findTeleportItemsByTitle, this, + _1, filter)); } } + sortByName(); + mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item. } - +bool LLLocationInputCtrl::findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter) +{ + return item.mTitle.find(filter) != std::string::npos; +} void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask) { if (mLocationContextMenu) @@ -519,7 +568,12 @@ void LLLocationInputCtrl::rebuildLocationHistory(std::string filter) removeall(); for (LLLocationHistory::location_list_t::const_reverse_iterator it = itemsp->rbegin(); it != itemsp->rend(); it++) { - add(*it); + LLSD value; + value["tooltip"] = it->getToolTip(); + //location history can contain only typed locations + value["item_type"] = TYPED_REGION_SURL; + value["global_pos"] = it->mGlobalPos.getValue(); + add(it->getLocation(), value); } } diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index d967df8257..3c43e1a321 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -41,6 +41,7 @@ class LLLandmark; class LLAddLandmarkObserver; class LLRemoveLandmarkObserver; class LLMenuGL; +class LLTeleportHistoryItem; /** * Location input control. @@ -103,6 +104,7 @@ private: void refresh(); void refreshLocation(); void rebuildLocationHistory(std::string filter = ""); + bool findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter); void setText(const LLStringExplicit& text); void updateAddLandmarkButton(); void updateContextMenu(); diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 1b82c2dc18..8ef6b25c50 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -61,9 +61,9 @@ LLNameListCtrl::Params::Params() LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p) : LLScrollListCtrl(p), - mAllowCallingCardDrop(p.allow_calling_card_drop), + mNameColumnIndex(p.name_column.column_index), mNameColumn(p.name_column.column_name), - mNameColumnIndex(p.name_column.column_index) + mAllowCallingCardDrop(p.allow_calling_card_drop) {} // public diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index e40568a0cb..c283b3a05f 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -45,7 +45,7 @@ #include "lllocationhistory.h" #include "lllocationinputctrl.h" #include "llteleporthistory.h" -#include "llsearcheditor.h" +#include "llsearchcombobox.h" #include "llsidetray.h" #include "llslurl.h" #include "llurlsimstring.h" @@ -82,7 +82,6 @@ public: Mandatory<EType> item_type; Params() {} - Params(EType type, std::string title); }; /*virtual*/ void draw(); @@ -104,24 +103,21 @@ private: const std::string LLTeleportHistoryMenuItem::ICON_IMG_BACKWARD("teleport_history_backward.tga"); const std::string LLTeleportHistoryMenuItem::ICON_IMG_FORWARD("teleport_history_forward.tga"); -LLTeleportHistoryMenuItem::Params::Params(EType type, std::string title) -{ - item_type(type); - font.name("SANSSERIF"); - - if (type == TYPE_CURRENT) - font.style("BOLD"); - else - title = " " + title; - - name(title); - label(title); -} - LLTeleportHistoryMenuItem::LLTeleportHistoryMenuItem(const Params& p) : LLMenuItemCallGL(p), mArrowIcon(NULL) { + // Set appearance depending on the item type. + if (p.item_type == TYPE_CURRENT) + { + setFont(LLFontGL::getFontSansSerifBold()); + } + else + { + setFont(LLFontGL::getFontSansSerif()); + setLabel(std::string(" ") + std::string(p.label)); + } + LLIconCtrl::Params icon_params; icon_params.name("icon"); icon_params.rect(LLRect(0, ICON_HEIGHT, ICON_WIDTH, 0)); @@ -183,14 +179,11 @@ LLNavigationBar::LLNavigationBar() mBtnForward(NULL), mBtnHome(NULL), mCmbLocation(NULL), - mLeSearch(NULL), + mSearchComboBox(NULL), mPurgeTPHistoryItems(false) { setIsChrome(TRUE); - mParcelMgrConnection = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback( - boost::bind(&LLNavigationBar::onTeleportFinished, this, _1)); - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_navigation_bar.xml"); // set a listener function for LoginComplete event @@ -202,8 +195,10 @@ LLNavigationBar::LLNavigationBar() LLNavigationBar::~LLNavigationBar() { - mParcelMgrConnection.disconnect(); + mTeleportFinishConnection.disconnect(); sInstance = 0; + + LLSearchHistory::getInstance()->save(); } BOOL LLNavigationBar::postBuild() @@ -213,10 +208,12 @@ BOOL LLNavigationBar::postBuild() mBtnHome = getChild<LLButton>("home_btn"); mCmbLocation= getChild<LLLocationInputCtrl>("location_combo"); - mLeSearch = getChild<LLSearchEditor>("search_input"); + mSearchComboBox = getChild<LLSearchComboBox>("search_combo_box"); + + fillSearchComboBox(); if (!mBtnBack || !mBtnForward || !mBtnHome || - !mCmbLocation || !mLeSearch) + !mCmbLocation || !mSearchComboBox) { llwarns << "Malformed navigation bar" << llendl; return FALSE; @@ -234,7 +231,7 @@ BOOL LLNavigationBar::postBuild() mCmbLocation->setSelectionCallback(boost::bind(&LLNavigationBar::onLocationSelection, this)); - mLeSearch->setCommitCallback(boost::bind(&LLNavigationBar::onSearchCommit, this)); + mSearchComboBox->setCommitCallback(boost::bind(&LLNavigationBar::onSearchCommit, this)); mDefaultNbRect = getRect(); mDefaultFpRect = getChild<LLFavoritesBarCtrl>("favorite")->getRect(); @@ -246,6 +243,25 @@ BOOL LLNavigationBar::postBuild() return TRUE; } +void LLNavigationBar::fillSearchComboBox() +{ + if(!mSearchComboBox) + { + return; + } + + LLSearchHistory::getInstance()->load(); + + LLSearchHistory::search_history_list_t search_list = + LLSearchHistory::getInstance()->getSearchHistoryList(); + LLSearchHistory::search_history_list_t::const_iterator it = search_list.begin(); + for( ; search_list.end() != it; ++it) + { + LLSearchHistory::LLSearchHistoryItem item = *it; + mSearchComboBox->add(item.search_query); + } +} + void LLNavigationBar::draw() { if(mPurgeTPHistoryItems) @@ -280,7 +296,12 @@ void LLNavigationBar::onHomeButtonClicked() void LLNavigationBar::onSearchCommit() { - invokeSearch(mLeSearch->getValue().asString()); + std::string search_query = mSearchComboBox->getValue().asString(); + if(!search_query.empty()) + { + LLSearchHistory::getInstance()->addEntry(search_query); + invokeSearch(mSearchComboBox->getValue().asString()); + } } void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) @@ -299,69 +320,107 @@ void LLNavigationBar::onLocationSelection() if (typed_location.empty()) return; + LLSD value = mCmbLocation->getSelectedValue(); + + if(value.has("item_type")) + { + + switch(value["item_type"].asInteger()) + { + case LANDMARK: + + if(value.has("AssetUUID")) + { + + gAgent.teleportViaLandmark( LLUUID(value["AssetUUID"].asString())); + return; + } + else + { + LLInventoryModel::item_array_t landmark_items = + LLLandmarkActions::fetchLandmarksByName(typed_location, + FALSE); + if (!landmark_items.empty()) + { + gAgent.teleportViaLandmark( landmark_items[0]->getAssetUUID()); + return; + } + } + break; + + case TELEPORT_HISTORY: + //in case of teleport item was selected, teleport by position too. + case TYPED_REGION_SURL: + if(value.has("global_pos")) + { + gAgent.teleportViaLocation(LLVector3d(value["global_pos"])); + return; + } + break; + + default: + break; + } + } + //Let's parse surl or region name + std::string region_name; LLVector3 local_coords(128, 128, 0); S32 x = 0, y = 0, z = 0; - // Is the typed location a SLURL? if (LLSLURL::isSLURL(typed_location)) { // Yes. Extract region name and local coordinates from it. if (LLURLSimString::parse(LLSLURL::stripProtocol(typed_location), ®ion_name, &x, &y, &z)) - local_coords.set(x, y, z); + local_coords.set(x, y, z); else return; - } - else + }else { - //If it is not slurl let's look for landmarks - LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(typed_location, FALSE); - if ( !landmark_items.empty() ) - { - gAgent.teleportViaLandmark(landmark_items[0]->getAssetUUID()); - return; - } - //No landmark match, check if it is a region name - region_name = parseLocation(typed_location, &x, &y, &z); - if (region_name != typed_location) - local_coords.set(x, y, z); - - // Treat it as region name. - // region_name = typed_location; + // assume that an user has typed the {region name} or possible {region_name, parcel} + region_name = typed_location.substr(0,typed_location.find(',')); } - + // Resolve the region name to its global coordinates. // If resolution succeeds we'll teleport. LLWorldMap::url_callback_t cb = boost::bind( &LLNavigationBar::onRegionNameResponse, this, typed_location, region_name, local_coords, _1, _2, _3, _4); + // connect the callback each time, when user enter new location to get real location of agent after teleport + mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLNavigationBar::onTeleportFinished, this, _1,typed_location)); + LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false); } -void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos) +void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location) { // Location is valid. Add it to the typed locations history. LLLocationHistory* lh = LLLocationHistory::getInstance(); + //TODO*: do we need convert surl into readable format? std::string location; /*NOTE: * We can't use gAgent.getPositionAgent() in case of local teleport to build location. * At this moment gAgent.getPositionAgent() contains previous coordinates. * according to EXT-65 agent position is being reseted on each frame. */ - LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_WITHOUT_SIM, - gAgent.getPosAgentFromGlobal(global_agent_pos)); + LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_WITHOUT_SIM, + gAgent.getPosAgentFromGlobal(global_agent_pos)); + std::string tooltip (LLSLURL::buildSLURLfromPosGlobal(gAgent.getRegion()->getName(), global_agent_pos, false)); + LLLocationHistoryItem item (location, + global_agent_pos, tooltip,TYPED_REGION_SURL);// we can add into history only TYPED location //Touch it, if it is at list already, add new location otherwise - if ( !lh->touchItem(location) ) { - std::string tooltip = LLSLURL::buildSLURLfromPosGlobal( - gAgent.getRegion()->getName(), global_agent_pos, false); - - lh->addItem(location, tooltip); + if ( !lh->touchItem(item) ) { + lh->addItem(item); } - llinfos << "Saving after on teleport finish" << llendl; - lh->save(); + lh->save(); + + if(mTeleportFinishConnection.connected()) + mTeleportFinishConnection.disconnect(); + } void LLNavigationBar::onTeleportHistoryChanged() @@ -411,9 +470,13 @@ void LLNavigationBar::rebuildTeleportHistoryMenu() else type = LLTeleportHistoryMenuItem::TYPE_CURRENT; - LLTeleportHistoryMenuItem::Params item_params(type, hist_items[i].getTitle()); + LLTeleportHistoryMenuItem::Params item_params; + item_params.label = item_params.name = hist_items[i].getTitle(); + item_params.item_type = type; item_params.on_click.function(boost::bind(&LLNavigationBar::onTeleportHistoryMenuItemClicked, this, i)); - mTeleportHistoryMenu->addChild(LLUICtrlFactory::create<LLTeleportHistoryMenuItem>(item_params)); + LLTeleportHistoryMenuItem* new_itemp = LLUICtrlFactory::create<LLTeleportHistoryMenuItem>(item_params); + //new_itemp->setFont() + mTeleportHistoryMenu->addChild(new_itemp); } } @@ -433,8 +496,8 @@ void LLNavigationBar::onRegionNameResponse( // Teleport to the location. LLVector3d region_pos = from_region_handle(region_handle); LLVector3d global_pos = region_pos + (LLVector3d) local_coords; - - llinfos << "Teleporting to: " << global_pos << llendl; + + llinfos << "Teleporting to: " << LLSLURL::buildSLURLfromPosGlobal(region_name, global_pos, false) << llendl; gAgent.teleportViaLocation(global_pos); } @@ -472,35 +535,6 @@ void LLNavigationBar::invokeSearch(std::string search_text) LLFloaterReg::showInstance("search", LLSD().insert("panel", "all").insert("id", LLSD(search_text))); } -std::string LLNavigationBar::parseLocation(const std::string & location, S32* x, S32* y, S32* z) { - /* - * This regular expression extracts numbers from the following string - * construct: "(num1, num2, num3)", where num1, num2 and num3 are decimal - * numbers. Leading and trailing spaces are also caught by the expression. - */ - const boost::regex re("\\s*\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)\\s*"); - - boost::smatch m; - if (boost::regex_search(location, m, re)) { - // string representations of parsed by regex++ numbers - std::string xstr(m[1].first, m[1].second); - std::string ystr(m[2].first, m[2].second); - std::string zstr(m[3].first, m[3].second); - - *x = atoi(xstr.c_str()); - *y = atoi(ystr.c_str()); - *z = atoi(zstr.c_str()); - //erase commas in coordinates - std::string region_parcel = boost::regex_replace(location, re, ""); - // cut region name - return region_parcel.substr(0, region_parcel.find_first_of(',')); - } - - *x = *y = *z = 0; - - return location; -} - void LLNavigationBar::clearHistoryCache() { mCmbLocation->removeall(); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 6932847854..8a65cd24fa 100644 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -41,6 +41,7 @@ class LLButton; class LLLocationInputCtrl; class LLMenuGL; class LLSearchEditor; +class LLSearchComboBox; /** * Web browser-like navigation bar. @@ -69,12 +70,6 @@ private: void rebuildTeleportHistoryMenu(); void showTeleportHistoryMenu(); void invokeSearch(std::string search_text); - - /** - * Get region name and local coordinates from typed location - */ - static std::string parseLocation(const std::string & location, S32* x, S32* y, S32* z); - // callbacks void onTeleportHistoryMenuItemClicked(const LLSD& userdata); void onTeleportHistoryChanged(); @@ -86,7 +81,7 @@ private: void onLocationSelection(); void onLocationPrearrange(const LLSD& data); void onSearchCommit(); - void onTeleportFinished(const LLVector3d& global_agent_pos); + void onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location); void onRegionNameResponse( std::string typed_location, std::string region_name, @@ -94,17 +89,19 @@ private: U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport); + void fillSearchComboBox(); + static LLNavigationBar *sInstance; LLMenuGL* mTeleportHistoryMenu; LLButton* mBtnBack; LLButton* mBtnForward; LLButton* mBtnHome; - LLSearchEditor* mLeSearch; + LLSearchComboBox* mSearchComboBox; LLLocationInputCtrl* mCmbLocation; LLRect mDefaultNbRect; LLRect mDefaultFpRect; - boost::signals2::connection mParcelMgrConnection; + boost::signals2::connection mTeleportFinishConnection; bool mPurgeTPHistoryItems; }; diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 3856a86da0..6150d5da37 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -183,9 +183,13 @@ LLColor4 nearbychat_get_text_color(const LLChat& chat) void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& color) { - std::string line = chat.mFromName; - line +=": "; - line +=chat.mText; + std::string line = chat.mText; + + //chat.mText starts with Avatar Name if entered message was "/me <action>". + // In this case output chat message should be "<Avatar Name> <action>". See EXT-656 + // See also process_chat_from_simulator() in the llviewermessage.cpp where ircstyle = TRUE; + if (CHAT_STYLE_IRC != chat.mChatStyle) + line = chat.mFromName + ": " + line; bool prepend_newline = true; if (gSavedSettings.getBOOL("ChatShowTimestamps")) diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 6e94b087a6..fd3519bf4b 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -372,7 +372,6 @@ void LLPanelAvatarProfile::resetControls() childSetVisible("status_me_panel", false); childSetVisible("profile_me_buttons_panel", false); childSetVisible("account_actions_panel", false); - childSetVisible("partner_edit_link", false); } void LLPanelAvatarProfile::resetData() @@ -539,7 +538,7 @@ void LLPanelAvatarProfile::fillAccountStatus(const LLAvatarData* avatar_data) childSetValue("acc_status_text", caption_text); } -void LLPanelAvatarProfile::onUrlTextboxClicked(std::string url) +void LLPanelAvatarProfile::onUrlTextboxClicked(const std::string& url) { LLWeb::loadURL(url); } @@ -595,9 +594,8 @@ BOOL LLPanelAvatarMeProfile::postBuild() childSetCommitCallback("status_combo", boost::bind(&LLPanelAvatarMeProfile::onStatusChanged, this), NULL); childSetCommitCallback("status_me_message_text", boost::bind(&LLPanelAvatarMeProfile::onStatusMessageChanged, this), NULL); - childSetActionTextbox("payment_update_link", boost::bind(&LLPanelAvatarMeProfile::onUpdateAccountTextboxClicked, this)); - childSetActionTextbox("my_account_link", boost::bind(&LLPanelAvatarMeProfile::onMyAccountTextboxClicked, this)); - childSetActionTextbox("partner_edit_link", boost::bind(&LLPanelAvatarMeProfile::onPartnerEditTextboxClicked, this)); + + childSetTextArg("partner_edit_link", "[URL]", getString("partner_edit_link_url")); resetControls(); resetData(); @@ -676,18 +674,3 @@ void LLPanelAvatarMeProfile::onStatusMessageChanged() { updateData(); } - -void LLPanelAvatarMeProfile::onUpdateAccountTextboxClicked() -{ - onUrlTextboxClicked(getString("payment_update_link_url")); -} - -void LLPanelAvatarMeProfile::onMyAccountTextboxClicked() -{ - onUrlTextboxClicked(getString("my_account_link_url")); -} - -void LLPanelAvatarMeProfile::onPartnerEditTextboxClicked() -{ - onUrlTextboxClicked(getString("partner_edit_link_url")); -} diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 51bd619901..1ed5fa4357 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -166,7 +166,7 @@ protected: */ virtual void fillAccountStatus(const LLAvatarData* avatar_data); - void onUrlTextboxClicked(std::string url); + void onUrlTextboxClicked(const std::string& url); void onHomepageTextboxClicked(); void onAddFriendButtonClick(); void onIMButtonClick(); @@ -203,9 +203,6 @@ protected: void onStatusChanged(); void onStatusMessageChanged(); - void onUpdateAccountTextboxClicked(); - void onMyAccountTextboxClicked(); - void onPartnerEditTextboxClicked(); private: diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp new file mode 100644 index 0000000000..60d0f07285 --- /dev/null +++ b/indra/newview/llpanelblockedlist.cpp @@ -0,0 +1,279 @@ +/** + * @file llpanelblockedlist.cpp + * @brief Container for blocked Residents & Objects list + * + * $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 "llfloater.h" +#include "llfloaterreg.h" +#include "llscrolllistctrl.h" + +#include "llpanelblockedlist.h" + +// project include +#include "llfloateravatarpicker.h" +#include "llsidetray.h" +#include "llsidetraypanelcontainer.h" + +static LLRegisterPanelClassWrapper<LLPanelBlockedList> t_panel_blocked_list("panel_block_list_sidetray"); + +// +// Constants +// +const std::string BLOCKED_PARAM_NAME = "blocked_to_select"; + +//----------------------------------------------------------------------------- +// LLPanelBlockedList() +//----------------------------------------------------------------------------- + +LLPanelBlockedList::LLPanelBlockedList() +: LLPanel() +{ + mCommitCallbackRegistrar.add("Block.ClickPick", boost::bind(&LLPanelBlockedList::onPickBtnClick, this)); + mCommitCallbackRegistrar.add("Block.ClickBlockByName", boost::bind(&LLPanelBlockedList::onBlockByNameClick, this)); + mCommitCallbackRegistrar.add("Block.ClickRemove", boost::bind(&LLPanelBlockedList::onRemoveBtnClick, this)); +} + +LLPanelBlockedList::~LLPanelBlockedList() +{ + LLMuteList::getInstance()->removeObserver(this); +} + +BOOL LLPanelBlockedList::postBuild() +{ + mBlockedList = getChild<LLScrollListCtrl>("blocked"); + mBlockedList->setCommitOnSelectionChange(TRUE); + + childSetCommitCallback("back", boost::bind(&LLPanelBlockedList::onBackBtnClick, this), NULL); + + LLMuteList::getInstance()->addObserver(this); + + refreshBlockedList(); + + return LLPanel::postBuild(); +} + +void LLPanelBlockedList::draw() +{ + updateButtons(); + LLPanel::draw(); +} + +void LLPanelBlockedList::onOpen(const LLSD& key) +{ + if (key.has(BLOCKED_PARAM_NAME) && key[BLOCKED_PARAM_NAME].asUUID().notNull()) + { + selectBlocked(key[BLOCKED_PARAM_NAME].asUUID()); + } +} + +void LLPanelBlockedList::selectBlocked(const LLUUID& mute_id) +{ + mBlockedList->selectByID(mute_id); +} + +void LLPanelBlockedList::showPanelAndSelect(const LLUUID& idToSelect) +{ + LLSideTray::getInstance()->showPanel("panel_block_list_sidetray", LLSD().insert(BLOCKED_PARAM_NAME, idToSelect)); +} + + +////////////////////////////////////////////////////////////////////////// +// Private Section +////////////////////////////////////////////////////////////////////////// +void LLPanelBlockedList::refreshBlockedList() +{ + mBlockedList->deleteAllItems(); + + std::vector<LLMute> mutes = LLMuteList::getInstance()->getMutes(); + std::vector<LLMute>::iterator it; + for (it = mutes.begin(); it != mutes.end(); ++it) + { + std::string display_name = it->getDisplayName(); + mBlockedList->addStringUUIDItem(display_name, it->mID, ADD_BOTTOM, TRUE); + } +} + +void LLPanelBlockedList::updateButtons() +{ + bool hasSelected = NULL != mBlockedList->getFirstSelected(); + childSetEnabled("Unblock", hasSelected); +} + + + +void LLPanelBlockedList::onBackBtnClick() +{ + LLSideTrayPanelContainer* parent = dynamic_cast<LLSideTrayPanelContainer*>(getParent()); + if(parent) + { + parent->openPreviousPanel(); + } +} + +void LLPanelBlockedList::onRemoveBtnClick() +{ + std::string name = mBlockedList->getSelectedItemLabel(); + LLUUID id = mBlockedList->getStringUUIDSelectedItem(); + LLMute mute(id); + mute.setFromDisplayName(name); + // now mute.mName has the suffix trimmed off + + S32 last_selected = mBlockedList->getFirstSelectedIndex(); + if (LLMuteList::getInstance()->remove(mute)) + { + // Above removals may rebuild this dialog. + + if (last_selected == mBlockedList->getItemCount()) + { + // we were on the last item, so select the last item again + mBlockedList->selectNthItem(last_selected - 1); + } + else + { + // else select the item after the last item previously selected + mBlockedList->selectNthItem(last_selected); + } + } +} + +void LLPanelBlockedList::onPickBtnClick() +{ + const BOOL allow_multiple = FALSE; + const BOOL close_on_select = TRUE; + /*LLFloaterAvatarPicker* picker = */LLFloaterAvatarPicker::show(callbackBlockPicked, this, allow_multiple, close_on_select); + + // *TODO: mantipov: should LLFloaterAvatarPicker be closed when panel is closed? + // old Floater dependency is not enable in panel + // addDependentFloater(picker); +} + +void LLPanelBlockedList::onBlockByNameClick() +{ + LLFloaterGetBlockedObjectName::show(&LLPanelBlockedList::callbackBlockByName); +} + +//static +void LLPanelBlockedList::callbackBlockPicked(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* user_data) +{ + if (names.empty() || ids.empty()) return; + LLMute mute(ids[0], names[0], LLMute::AGENT); + LLMuteList::getInstance()->add(mute); + showPanelAndSelect(mute.mID); +} + +//static +void LLPanelBlockedList::callbackBlockByName(const std::string& text) +{ + if (text.empty()) return; + + LLMute mute(LLUUID::null, text, LLMute::BY_NAME); + BOOL success = LLMuteList::getInstance()->add(mute); + if (!success) + { + LLNotifications::instance().add("MuteByNameFailed"); + } +} + +////////////////////////////////////////////////////////////////////////// +// LLFloaterGetBlockedObjectName +////////////////////////////////////////////////////////////////////////// + +// Constructor/Destructor +LLFloaterGetBlockedObjectName::LLFloaterGetBlockedObjectName(const LLSD& key) +: LLFloater(key) +, mGetObjectNameCallback(NULL) +{ +} + +// Destroys the object +LLFloaterGetBlockedObjectName::~LLFloaterGetBlockedObjectName() +{ + gFocusMgr.releaseFocusIfNeeded( this ); +} + +BOOL LLFloaterGetBlockedObjectName::postBuild() +{ + getChild<LLButton>("OK")-> setCommitCallback(boost::bind(&LLFloaterGetBlockedObjectName::applyBlocking, this)); + getChild<LLButton>("Cancel")-> setCommitCallback(boost::bind(&LLFloaterGetBlockedObjectName::cancelBlocking, this)); + center(); + + return LLFloater::postBuild(); +} + +BOOL LLFloaterGetBlockedObjectName::handleKeyHere(KEY key, MASK mask) +{ + if (key == KEY_RETURN && mask == MASK_NONE) + { + applyBlocking(); + return TRUE; + } + else if (key == KEY_ESCAPE && mask == MASK_NONE) + { + cancelBlocking(); + return TRUE; + } + + return LLFloater::handleKeyHere(key, mask); +} + +// static +LLFloaterGetBlockedObjectName* LLFloaterGetBlockedObjectName::show(get_object_name_callback_t callback) +{ + LLFloaterGetBlockedObjectName* floater = LLFloaterReg::showTypedInstance<LLFloaterGetBlockedObjectName>("mute_object_by_name"); + + floater->mGetObjectNameCallback = callback; + + // *TODO: mantipov: should LLFloaterGetBlockedObjectName be closed when panel is closed? + // old Floater dependency is not enable in panel + // addDependentFloater(floater); + + return floater; +} + +////////////////////////////////////////////////////////////////////////// +// Private Section +void LLFloaterGetBlockedObjectName::applyBlocking() +{ + if (mGetObjectNameCallback) + { + const std::string& text = childGetValue("object_name").asString(); + mGetObjectNameCallback(text); + } + closeFloater(); +} + +void LLFloaterGetBlockedObjectName::cancelBlocking() +{ + closeFloater(); +} + +//EOF diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h new file mode 100644 index 0000000000..52b74a184b --- /dev/null +++ b/indra/newview/llpanelblockedlist.h @@ -0,0 +1,115 @@ +/** + * @file llpanelblockedlist.h + * @brief Container for blocked Residents & Objects list + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELBLOCKEDLIST_H +#define LL_LLPANELBLOCKEDLIST_H + +#include "llpanel.h" +#include "llmutelist.h" +// #include <vector> + +// class LLButton; +// class LLLineEditor; +// class LLMessageSystem; +// class LLUUID; + class LLScrollListCtrl; + +class LLPanelBlockedList + : public LLPanel, public LLMuteListObserver +{ +public: + LLPanelBlockedList(); + ~LLPanelBlockedList(); + + virtual BOOL postBuild(); + virtual void draw(); + virtual void onOpen(const LLSD& key); + + void selectBlocked(const LLUUID& id); + + /** + * Shows current Panel in side tray and select passed blocked item. + * + * @param idToSelect - LLUUID of blocked Resident or Object to be selected. + * If it is LLUUID::null, nothing will be selected. + */ + static void showPanelAndSelect(const LLUUID& idToSelect); + + // LLMuteListObserver callback interface implementation. + /* virtual */ void onChange() { refreshBlockedList();} + +private: + void refreshBlockedList(); + void updateButtons(); + + // UI callbacks + void onBackBtnClick(); + void onRemoveBtnClick(); + void onPickBtnClick(); + void onBlockByNameClick(); + + static void callbackBlockPicked(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* user_data); + static void callbackBlockByName(const std::string& text); + +private: + LLScrollListCtrl* mBlockedList; +}; + +//----------------------------------------------------------------------------- +// LLFloaterGetBlockedObjectName() +//----------------------------------------------------------------------------- +// Class for handling mute object by name floater. +class LLFloaterGetBlockedObjectName : public LLFloater +{ + friend class LLFloaterReg; +public: + typedef boost::function<void (const std::string&)> get_object_name_callback_t; + + virtual BOOL postBuild(); + + virtual BOOL handleKeyHere(KEY key, MASK mask); + + static LLFloaterGetBlockedObjectName* show(get_object_name_callback_t callback); + +private: + LLFloaterGetBlockedObjectName(const LLSD& key); + virtual ~LLFloaterGetBlockedObjectName(); + + // UI Callbacks + void applyBlocking(); + void cancelBlocking(); + + get_object_name_callback_t mGetObjectNameCallback; +}; + + +#endif // LL_LLPANELBLOCKEDLIST_H diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 4cbb018ce9..d1ce6b14ed 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -298,6 +298,8 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id) if(button_create) button_create->setVisible(is_null_group_id); + getChild<LLUICtrl>("prepend_founded_by")->setVisible(!is_null_group_id); + LLAccordionCtrlTab* tab_general = findChild<LLAccordionCtrlTab>("group_general_tab"); LLAccordionCtrlTab* tab_roles = findChild<LLAccordionCtrlTab>("group_roles_tab"); LLAccordionCtrlTab* tab_notices = findChild<LLAccordionCtrlTab>("group_notices_tab"); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 73ea990b3f..f3893a104c 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -113,6 +113,7 @@ BOOL LLPanelGroupGeneral::postBuild() if (mListVisibleMembers) { mListVisibleMembers->setDoubleClickCallback(openProfile, this); + mListVisibleMembers->setContextMenu(LLScrollListCtrl::MENU_AVATAR); } // Options @@ -769,11 +770,6 @@ void LLPanelGroupGeneral::updateMembers() } // Owners show up in bold. std::string style = "NORMAL"; - if ( member->isOwner() ) - { - style = "BOLD"; - } - sd_timer.reset(); LLSD row; row["id"] = member->getID(); @@ -793,7 +789,14 @@ void LLPanelGroupGeneral::updateMembers() sSDTime += sd_timer.getElapsedTimeF32(); element_timer.reset(); - mListVisibleMembers->addElement(row);//, ADD_SORTED); + LLScrollListItem* member_row = mListVisibleMembers->addElement(row);//, ADD_SORTED); + + if ( member->isOwner() ) + { + LLScrollListText* name_textp = dynamic_cast<LLScrollListText*>(member_row->getColumn(0)); + if (name_textp) + name_textp->setFontStyle(LLFontGL::BOLD); + } sElementTime += element_timer.getElapsedTimeF32(); } sAllTime += all_timer.getElapsedTimeF32(); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 4618b49df4..48c9c16780 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -659,6 +659,12 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, row["columns"][1]["font"]["style"] = "BOLD"; LLScrollListItem* title_row = ctrl->addElement(row, ADD_BOTTOM, action_set->mActionSetData); + + LLScrollListText* name_textp = dynamic_cast<LLScrollListText*>(title_row->getColumn(1)); + if (name_textp) + name_textp->setFontStyle(LLFontGL::BOLD); + + bool category_matches_filter = (filter) ? matchesActionSearchFilter(action_set->mActionSetData->mName) : true; @@ -837,6 +843,7 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) mMembersList->setCommitCallback(onMemberSelect, this); // Show the member's profile on double click. mMembersList->setDoubleClickCallback(onMemberDoubleClick, this); + mMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR); LLButton* button = parent->getChild<LLButton>("member_invite", recurse); if ( button ) @@ -1731,6 +1738,8 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) mRolesList->setCommitOnSelectionChange(TRUE); mRolesList->setCommitCallback(onRoleSelect, this); + mAssignedMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR); + mMemberVisibleCheck->setCommitCallback(onMemberVisibilityChange, this); mAllowedActionsList->setCommitOnSelectionChange(TRUE); @@ -2397,6 +2406,7 @@ BOOL LLPanelGroupActionsSubTab::postBuildSubTab(LLView* root) mActionList->setCommitOnSelectionChange(TRUE); mActionList->setCommitCallback(boost::bind(&LLPanelGroupActionsSubTab::handleActionSelect, this)); + mActionList->setContextMenu(LLScrollListCtrl::MENU_AVATAR); update(GC_ALL); diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 697182c8fc..42aa21c13e 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -43,12 +43,12 @@ // newview #include "llagent.h" +#include "llavataractions.h" #include "llavatarlist.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llfloateravatarpicker.h" //#include "llfloaterminiinspector.h" #include "llfriendcard.h" -#include "llavataractions.h" #include "llgroupactions.h" #include "llgrouplist.h" #include "llrecentpeople.h" @@ -133,18 +133,23 @@ public: class LLFriendListUpdater : public LLAvatarListUpdater, public LLFriendObserver { LOG_CLASS(LLFriendListUpdater); + class LLInventoryFriendCardObserver; public: + friend class LLInventoryFriendCardObserver; LLFriendListUpdater(callback_t cb) : LLAvatarListUpdater(cb, FRIEND_LIST_UPDATE_TIMEOUT) { LLAvatarTracker::instance().addObserver(this); + // For notification when SIP online status changes. LLVoiceClient::getInstance()->addObserver(this); + mInvObserver = new LLInventoryFriendCardObserver(this); } ~LLFriendListUpdater() { + delete mInvObserver; LLVoiceClient::getInstance()->removeObserver(this); LLAvatarTracker::instance().removeObserver(this); } @@ -166,6 +171,7 @@ public: mMask |= mask; } + /*virtual*/ BOOL tick() { if (updateList(mMask)) @@ -180,6 +186,75 @@ public: private: U32 mMask; + LLInventoryFriendCardObserver* mInvObserver; + + /** + * This class is intended for updating Friend List when Inventory Friend Card is added/removed. + * + * The main usage is when Inventory Friends/All content is added while synchronizing with + * friends list on startup is performed. In this case Friend Panel should be updated when + * missing Inventory Friend Card is created. + * *NOTE: updating is fired when Inventory item is added into CallingCards/Friends subfolder. + * Otherwise LLFriendObserver functionality is enough to keep Friends Panel synchronized. + */ + class LLInventoryFriendCardObserver : public LLInventoryObserver + { + LOG_CLASS(LLFriendListUpdater::LLInventoryFriendCardObserver); + + friend class LLFriendListUpdater; + + private: + LLInventoryFriendCardObserver(LLFriendListUpdater* updater) : mUpdater(updater) + { + gInventory.addObserver(this); + } + ~LLInventoryFriendCardObserver() + { + gInventory.removeObserver(this); + } + /*virtual*/ void changed(U32 mask) + { + lldebugs << "Inventory changed: " << mask << llendl; + + // *NOTE: deleting of InventoryItem is performed via moving to Trash. + // That means LLInventoryObserver::STRUCTURE is present in MASK instead of LLInventoryObserver::REMOVE + if ((CALLINGCARD_ADDED & mask) == CALLINGCARD_ADDED) + { + lldebugs << "Calling card added: count: " << gInventory.getChangedIDs().size() + << ", first Inventory ID: "<< (*gInventory.getChangedIDs().begin()) + << llendl; + + bool friendFound = false; + std::set<LLUUID> changedIDs = gInventory.getChangedIDs(); + for (std::set<LLUUID>::const_iterator it = changedIDs.begin(); it != changedIDs.end(); ++it) + { + if (isDescendentOfInventoryFriends(*it)) + { + friendFound = true; + break; + } + } + + if (friendFound) + { + lldebugs << "friend found, panel should be updated" << llendl; + mUpdater->changed(LLFriendObserver::ADD); + } + } + } + + bool isDescendentOfInventoryFriends(const LLUUID& invItemID) + { + LLViewerInventoryItem * item = gInventory.getItem(invItemID); + if (NULL == item) + return false; + + return LLFriendCardsManager::instance().isItemInAnyFriendsList(item); + } + LLFriendListUpdater* mUpdater; + + static const U32 CALLINGCARD_ADDED = LLInventoryObserver::ADD | LLInventoryObserver::CALLING_CARD; + }; }; /** @@ -438,8 +513,13 @@ bool LLPanelPeople::updateFriendList(U32 changed_mask) LLFriendCardsManager::instance().collectFriendsLists(listMap); if (listMap.size() > 0) { + lldebugs << "Friends Cards were found, count: " << listMap.begin()->second.size() << llendl; mAllFriendVec = listMap.begin()->second; } + else + { + lldebugs << "Friends Cards were not found" << llendl; + } LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); for (; buddy_it != all_buddies.end(); ++buddy_it) @@ -896,7 +976,6 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata) } } - void LLPanelPeople::onCallButtonClicked() { // *TODO: not implemented yet diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index 973afae73b..c34038c672 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -46,6 +46,7 @@ #include "llpanelprofile.h" #include "llpanelpick.h" #include "llscrollcontainer.h" +#include "lllistctrl.h" static const std::string XML_BTN_NEW = "new_btn"; static const std::string XML_BTN_DELETE = "trash_btn"; @@ -53,9 +54,10 @@ static const std::string XML_BTN_INFO = "info_btn"; static const std::string XML_BTN_TELEPORT = "teleport_btn"; static const std::string XML_BTN_SHOW_ON_MAP = "show_on_map_btn"; -static const std::string XML_PICKS_LIST = "back_panel"; +static const std::string PICK_ID("pick_id"); +static const std::string PICK_CREATOR_ID("pick_creator_id"); +static const std::string PICK_NAME("pick_name"); -#define PICK_ITEMS_BETWEEN 5 static LLRegisterPanelClassWrapper<LLPanelPicks> t_panel_picks("panel_picks"); @@ -65,9 +67,9 @@ static LLRegisterPanelClassWrapper<LLPanelPicks> t_panel_picks("panel_picks"); LLPanelPicks::LLPanelPicks() : LLPanelProfileTab(), mPopupMenu(NULL), - mSelectedPickItem(NULL), mProfilePanel(NULL), - mPickPanel(NULL) + mPickPanel(NULL), + mPicksList(NULL) { } @@ -100,22 +102,8 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) gCacheName->getName(getAvatarId(),name,second_name); childSetTextArg("pick_title", "[NAME]",name); - LLView* picks_list = getPicksList(); - - // to restore selection of the same item later - LLUUID pick_id_selected(LLUUID::null); - if (mSelectedPickItem) pick_id_selected = mSelectedPickItem->getPickId(); - - clear(); - - //*TODO move it somewhere else? - picks_list->setEnabled(FALSE); - childSetEnabled(XML_BTN_NEW, false); - childSetEnabled(XML_BTN_DELETE, false); - childSetEnabled(XML_BTN_INFO, false); - childSetEnabled(XML_BTN_TELEPORT,!avatar_picks->picks_list.empty()); - childSetEnabled(XML_BTN_SHOW_ON_MAP,!avatar_picks->picks_list.empty()); - + mPicksList->clear(); + LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); for(; avatar_picks->picks_list.end() != it; ++it) { @@ -124,109 +112,44 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) LLPickItem* picture = LLPickItem::create(); picture->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); - - picks_list->addChild(picture); - picture->setPickName(pick_name); picture->setPickId(pick_id); picture->setCreatorId(getAvatarId()); LLAvatarPropertiesProcessor::instance().addObserver(getAvatarId(), picture); picture->update(); - mPickItemList.push_back(picture); - if (pick_id_selected != LLUUID::null && - pick_id == pick_id_selected) setSelectedPickItem(picture); + + LLSD pick_value = LLSD(); + pick_value.insert(PICK_ID, pick_id); + pick_value.insert(PICK_NAME, pick_name); + pick_value.insert(PICK_CREATOR_ID, getAvatarId()); + + mPicksList->addItem(picture, pick_value); + + picture->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickItem, this, _1)); + picture->setRightMouseDownCallback(boost::bind(&LLPanelPicks::onRightMouseDownItem, this, _1, _2, _3, _4)); + picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); + picture->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); } - reshapePicksList(); LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - updateButtons(); - if (!mSelectedPickItem && mPickItemList.size()) setSelectedPickItem(mPickItemList.back()); - picks_list->setEnabled(TRUE); - } } } -void LLPanelPicks::clear() -{ - LLView* scroll = getPicksList(); - picture_list_t::const_iterator it = mPickItemList.begin(); - for(; mPickItemList.end() != it; ++it) - { - scroll->removeChild(*it); - delete *it; - } - mPickItemList.clear(); - mSelectedPickItem = NULL; -} - - LLPickItem* LLPanelPicks::getSelectedPickItem() { - return mSelectedPickItem; -} - - -void LLPanelPicks::removePickItem( LLPickItem* pick_item ) -{ - LLView* scroll = getPicksList(); - scroll->removeChild(pick_item); - mPickItemList.remove(pick_item); - if (mPickItemList.size() == 0) - { - mSelectedPickItem = NULL; - } - else - { - setSelectedPickItem(mPickItemList.back()); - } - - reshapePicksList(); -} - -void LLPanelPicks::reshapePicksList() -{ - if (!mPickItemList.size()) return; - LLView* pickList = getPicksList(); - - //We don't need to update size of the 'pick list' before reshaping pick items. Don't need to reshape the pick list - S32 height = mPickItemList.size() * (mPickItemList.front()->getRect().getHeight() + PICK_ITEMS_BETWEEN); - LLRect rc = pickList->getRect(); - rc.setLeftTopAndSize(rc.mLeft, rc.mTop, rc.getWidth(), height); - pickList->setRect(rc); + LLPanel* selected_item = mPicksList->getSelectedItem(); + if (!selected_item) return NULL; - S32 last_bottom = pickList->getRect().getHeight(); - std::list<LLPickItem*>::const_iterator pick_it, pick_first_it = mPickItemList.begin(); - for ( pick_it = pick_first_it; pick_it != mPickItemList.end(); ++pick_it) - { - LLView* const pick = *pick_it; - if(pick_it != pick_first_it) - { - last_bottom -= pick->getRect().getHeight(); - last_bottom -= PICK_ITEMS_BETWEEN; - } - reshapePickItem(pick, last_bottom,pickList->getRect().getWidth()); - } -} - -void LLPanelPicks::reshapePickItem(LLView* const pick_item, const S32 last_bottom, const S32 newWidth) -{ - LLRect rc = pick_item->getRect(); - rc.mBottom = last_bottom - rc.getHeight(); - rc.mTop = last_bottom; - pick_item->setRect(rc); - pick_item->reshape(newWidth, rc.getHeight()); -} - -LLView* LLPanelPicks::getPicksList() const -{ - return getChild<LLView>(XML_PICKS_LIST); + return dynamic_cast<LLPickItem*>(selected_item); } BOOL LLPanelPicks::postBuild() { + mPicksList = getChild<LLListCtrl>("picks_list"); + childSetAction(XML_BTN_DELETE, boost::bind(&LLPanelPicks::onClickDelete, this)); childSetAction("teleport_btn", boost::bind(&LLPanelPicks::onClickTeleport, this)); @@ -270,6 +193,10 @@ void LLPanelPicks::onOpen(const LLSD& key) { childSetVisible("pick_title", !self); childSetVisible("pick_title_agent", self); + + mPopupMenu->setItemVisible("pick_delete", TRUE); + mPopupMenu->setItemVisible("pick_edit", TRUE); + mPopupMenu->setItemVisible("pick_separator", TRUE); } LLPanelProfileTab::onOpen(key); @@ -278,11 +205,11 @@ void LLPanelPicks::onOpen(const LLSD& key) //static void LLPanelPicks::onClickDelete() { - LLPickItem* pick_item = getSelectedPickItem(); - if (!pick_item) return; + LLSD pick_value = mPicksList->getSelectedValue(); + if (pick_value.isUndefined()) return; LLSD args; - args["PICK"] = pick_item->getPickName(); + args["PICK"] = pick_value[PICK_NAME]; LLNotifications::instance().add("DeleteAvatarPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackDelete, this, _1, _2)); } @@ -290,12 +217,12 @@ bool LLPanelPicks::callbackDelete(const LLSD& notification, const LLSD& response { S32 option = LLNotification::getSelectedOption(notification, response); - LLPickItem* pick_item = getSelectedPickItem(); + LLSD pick_value = mPicksList->getSelectedValue(); if (0 == option) { - LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_item->getPickId()); - removePickItem(pick_item); + LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_value[PICK_ID]); + mPicksList->removeItemByValue(pick_value); } updateButtons(); return false; @@ -329,101 +256,45 @@ void LLPanelPicks::onClickMap() } -BOOL LLPanelPicks::handleRightMouseDown(S32 x, S32 y, MASK mask) +void LLPanelPicks::onRightMouseDownItem(LLUICtrl* item, S32 x, S32 y, MASK mask) { - if (isMouseInPick(x, y)) + if (mPopupMenu) { - if (mPopupMenu) - { - mPopupMenu->buildDrawLabels(); - mPopupMenu->updateParent(LLMenuGL::sMenuContainer); - ((LLContextMenu*)mPopupMenu)->show(x, y); - LLMenuGL::showPopup(this, mPopupMenu, x, y); - } - return TRUE; + mPopupMenu->buildDrawLabels(); + mPopupMenu->updateParent(LLMenuGL::sMenuContainer); + ((LLContextMenu*)mPopupMenu)->show(x, y); + LLMenuGL::showPopup(item, mPopupMenu, x, y); } - return LLPanel::handleRightMouseDown(x, y, mask); } -BOOL LLPanelPicks::handleMouseDown( S32 x, S32 y, MASK mask ) +void LLPanelPicks::onDoubleClickItem(LLUICtrl* item) { - isMouseInPick(x, y); - return LLPanel::handleMouseDown(x, y, mask); -} - -BOOL LLPanelPicks::handleDoubleClick(S32 x, S32 y, MASK mask) -{ - if (isMouseInPick(x, y)) - { - LLPickItem* pick_item = getSelectedPickItem(); - if (pick_item) - { - LLSD args; - args["PICK"] = pick_item->getPickName(); - LLNotifications::instance().add("TeleportToPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); - } - return TRUE; - } - return LLPanel::handleDoubleClick(x, y, mask); + LLSD pick_value = mPicksList->getSelectedValue(); + if (pick_value.isUndefined()) return; + + LLSD args; + args["PICK"] = pick_value[PICK_NAME]; + LLNotifications::instance().add("TeleportToPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); } void LLPanelPicks::updateButtons() { - int picks_num = mPickItemList.size(); - childSetEnabled(XML_BTN_INFO, picks_num > 0); + int picks_num = mPicksList->size(); + bool has_selected = mPicksList->numSelected(); + + childSetEnabled(XML_BTN_INFO, has_selected); if (getAvatarId() == gAgentID) { childSetEnabled(XML_BTN_NEW, picks_num < MAX_AVATAR_PICKS); - childSetEnabled(XML_BTN_DELETE, picks_num > 0); - - //*TODO move somewhere this calls - // we'd better set them up earlier when a panel was being constructed - mPopupMenu->setItemVisible("pick_delete", TRUE); - mPopupMenu->setItemVisible("pick_edit", TRUE); - mPopupMenu->setItemVisible("pick_separator", TRUE); - } - - //*TODO update buttons like Show on Map, Teleport etc. - -} - -void LLPanelPicks::setSelectedPickItem(LLPickItem* item) -{ - if (!item) return; - if (mSelectedPickItem == item) return; - if (mSelectedPickItem && mSelectedPickItem->isBackgroundVisible()) - { - mSelectedPickItem->setBackgroundVisible(FALSE); + childSetEnabled(XML_BTN_DELETE, has_selected); } - item->setBackgroundVisible(TRUE); - mSelectedPickItem = item; -} -BOOL LLPanelPicks::isMouseInPick( S32 x, S32 y ) -{ - S32 x_l = x; - S32 y_l = y; - - if(!getChild<LLUICtrl>("profile_scroll")->getRect().pointInRect(x, y)) - { - return FALSE; - } - - picture_list_t::const_iterator it = mPickItemList.begin(); - for(; mPickItemList.end() != it; ++it) - { - localPointToOtherView(x, y, &x_l, &y_l, (*it)); - if ((*it)->pointInView(x_l, y_l)) - { - setSelectedPickItem(*it); - return TRUE; - } - } - return FALSE; + childSetEnabled(XML_BTN_INFO, has_selected); + childSetEnabled(XML_BTN_TELEPORT, has_selected); + childSetEnabled(XML_BTN_SHOW_ON_MAP, has_selected); } - void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel) { mProfilePanel = profile_panel; @@ -449,12 +320,12 @@ void LLPanelPicks::onClickNew() void LLPanelPicks::onClickInfo() { - LLPickItem* pick = getSelectedPickItem(); - if (!pick) return; + LLSD selected_value = mPicksList->getSelectedValue(); + if (selected_value.isUndefined()) return; buildPickPanel(); mPickPanel->reset(); - mPickPanel->init(pick->getCreatorId(), pick->getPickId()); + mPickPanel->init(selected_value[PICK_CREATOR_ID], selected_value[PICK_ID]); getProfilePanel()->togglePanel(mPickPanel); } @@ -466,12 +337,12 @@ void LLPanelPicks::onClickBack() void LLPanelPicks::onClickMenuEdit() { //*TODO, refactor - most of that is similar to onClickInfo - LLPickItem* pick = getSelectedPickItem(); - if (!pick) return; + LLSD selected_value = mPicksList->getSelectedValue(); + if (selected_value.isUndefined()) return; buildPickPanel(); mPickPanel->reset(); - mPickPanel->init(pick->getCreatorId(), pick->getPickId()); + mPickPanel->init(selected_value[PICK_CREATOR_ID], selected_value[PICK_ID]); mPickPanel->setEditMode(TRUE); getProfilePanel()->togglePanel(mPickPanel); } @@ -601,3 +472,17 @@ void LLPanelPicks::onClose() getProfilePanel()->togglePanel(mPickPanel); } } + +BOOL LLPickItem::postBuild() +{ + setMouseEnterCallback(boost::bind(&LLPanelPick::childSetVisible, this, "hovered_icon", true)); + setMouseLeaveCallback(boost::bind(&LLPanelPick::childSetVisible, this, "hovered_icon", false)); + return TRUE; +} + +void LLPickItem::setValue(const LLSD& value) +{ + if (!value.isMap()) return;; + if (!value.has("selected")) return; + childSetVisible("selected_icon", value["selected"]); +} diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index da7bc32ab1..97e8e607c8 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -48,7 +48,7 @@ class LLPanelPick; class LLAgent; class LLMenuGL; class LLPickItem; - +class LLListCtrl; class LLPanelPicks : public LLPanelProfileTab @@ -67,18 +67,9 @@ public: void updateData(); - void clear(); - // returns the selected pick item LLPickItem* getSelectedPickItem(); - // removes the specified pick item - void removePickItem(LLPickItem* pick_item); - - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - //*NOTE top down approch when panel toggling is done only by // parent panels failed to work (picks related code was in me profile panel) void setProfilePanel(LLPanelProfile* profile_panel); @@ -106,25 +97,17 @@ private: bool callbackDelete(const LLSD& notification, const LLSD& response); bool callbackTeleport(const LLSD& notification, const LLSD& response); - void reshapePicksList(); - void reshapePickItem(LLView* const pick_item, const S32 last_bottom, const S32 newWidth); - LLView* getPicksList() const; void updateButtons(); - void setSelectedPickItem(LLPickItem* item); - - BOOL isMouseInPick(S32 x, S32 y); + virtual void onDoubleClickItem(LLUICtrl* item); + virtual void onRightMouseDownItem(LLUICtrl* item, S32 x, S32 y, MASK mask); LLPanelProfile* getProfilePanel(); - - typedef std::list<LLPickItem*> picture_list_t; - picture_list_t mPickItemList; - LLMenuGL* mPopupMenu; - LLPickItem* mSelectedPickItem; LLPanelProfile* mProfilePanel; LLPanelPick* mPickPanel; + LLListCtrl* mPicksList; }; class LLPickItem : public LLPanel, public LLAvatarPropertiesObserver @@ -169,6 +152,11 @@ public: ~LLPickItem(); + /*virtual*/ BOOL postBuild(); + + /** setting on/off background icon to indicate selected state */ + /*virtual*/ void setValue(const LLSD& value); + protected: LLUUID mPickID; diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index a01977c9b5..ec1c10d8c9 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -48,6 +48,8 @@ #include "llscrollcontainer.h" #include "lltextbox.h" +#include "llaccordionctrl.h" +#include "llaccordionctrltab.h" #include "llagent.h" #include "llavatarpropertiesprocessor.h" #include "llfloaterworldmap.h" @@ -80,6 +82,8 @@ LLPanelPlaceInfo::~LLPanelPlaceInfo() { LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelID, this); } + + LLViewerParcelMgr::getInstance()->removeObserver(this); } BOOL LLPanelPlaceInfo::postBuild() @@ -93,14 +97,42 @@ BOOL LLPanelPlaceInfo::postBuild() mSnapshotCtrl = getChild<LLTextureCtrl>("logo"); mSnapshotCtrl->setEnabled(FALSE); - mRegionName = getChild<LLTextBox>("region_name"); - mParcelName = getChild<LLTextBox>("parcel_name"); + mRegionName = getChild<LLTextBox>("region_title"); + mParcelName = getChild<LLTextBox>("parcel_title"); mDescEditor = getChild<LLTextEditor>("description"); - mRating = getChild<LLIconCtrl>("maturity"); - mRegionInfoDrillIn = getChild<LLButton>("region_info_drill_in"); - mMediaDrillIn = getChild<LLButton>("media_drill_in"); - mMediaDrillIn->setClickedCallback(boost::bind(&LLPanelPlaceInfo::toggleMediaPanel, this, TRUE)); + mMaturityRatingText = getChild<LLTextBox>("maturity_value"); + mParcelOwner = getChild<LLTextBox>("owner_value"); + mLastVisited = getChild<LLTextBox>("last_visited_value"); + + mRatingText = getChild<LLTextBox>("rating_value"); + mVoiceText = getChild<LLTextBox>("voice_value"); + mFlyText = getChild<LLTextBox>("fly_value"); + mPushText = getChild<LLTextBox>("push_value"); + mBuildText = getChild<LLTextBox>("build_value"); + mScriptsText = getChild<LLTextBox>("scripts_value"); + mDamageText = getChild<LLTextBox>("damage_value"); + + mRegionNameText = getChild<LLTextBox>("region_name"); + mRegionTypeText = getChild<LLTextBox>("region_type"); + mRegionRatingText = getChild<LLTextBox>("region_rating"); + mRegionOwnerText = getChild<LLTextBox>("region_owner"); + mRegionGroupText = getChild<LLTextBox>("region_group"); + + mEstateNameText = getChild<LLTextBox>("estate_name"); + mEstateRatingText = getChild<LLTextBox>("estate_rating"); + mEstateOwnerText = getChild<LLTextBox>("estate_owner"); + mCovenantText = getChild<LLTextEditor>("covenant"); + + mSalesPriceText = getChild<LLTextBox>("sales_price"); + mAreaText = getChild<LLTextBox>("area"); + mTrafficText = getChild<LLTextBox>("traffic"); + mPrimitivesText = getChild<LLTextBox>("primitives"); + mParcelScriptsText = getChild<LLTextBox>("parcel_scripts"); + mTerraformLimitsText = getChild<LLTextBox>("terraform_limits"); + mSubdivideText = getChild<LLTextEditor>("subdivide"); + mResaleText = getChild<LLTextEditor>("resale"); + mSaleToText = getChild<LLTextBox>("sale_to"); mOwner = getChild<LLTextBox>("owner"); mCreator = getChild<LLTextBox>("creator"); @@ -224,7 +256,9 @@ void LLPanelPlaceInfo::resetLocation() mLandmarkID.setNull(); mPosRegion.clearVec(); std::string not_available = getString("not_available"); - mRating->setValue(not_available); + mMaturityRatingText->setValue(not_available); + mParcelOwner->setValue(not_available); + mLastVisited->setValue(not_available); mRegionName->setText(not_available); mParcelName->setText(not_available); mDescEditor->setText(not_available); @@ -235,6 +269,35 @@ void LLPanelPlaceInfo::resetLocation() mNotesEditor->setText(LLStringUtil::null); mSnapshotCtrl->setImageAssetID(LLUUID::null); mSnapshotCtrl->setFallbackImageName("default_land_picture.j2c"); + + mRatingText->setText(not_available); + mVoiceText->setText(not_available); + mFlyText->setText(not_available); + mPushText->setText(not_available); + mBuildText->setText(not_available); + mParcelScriptsText->setText(not_available); + mDamageText->setText(not_available); + + mRegionNameText->setValue(not_available); + mRegionTypeText->setValue(not_available); + mRegionRatingText->setValue(not_available); + mRegionOwnerText->setValue(not_available); + mRegionGroupText->setValue(not_available); + + mEstateNameText->setValue(not_available); + mEstateRatingText->setValue(not_available); + mEstateOwnerText->setValue(not_available); + mCovenantText->setValue(not_available); + + mSalesPriceText->setValue(not_available); + mAreaText->setValue(not_available); + mTrafficText->setValue(not_available); + mPrimitivesText->setValue(not_available); + mParcelScriptsText->setValue(not_available); + mTerraformLimitsText->setValue(not_available); + mSubdivideText->setValue(not_available); + mResaleText->setValue(not_available); + mSaleToText->setValue(not_available); } //virtual @@ -251,12 +314,23 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) bool is_info_type_agent = type == AGENT; bool is_info_type_landmark = type == LANDMARK; + bool is_info_type_teleport_history = type == TELEPORT_HISTORY; + + getChild<LLTextBox>("maturity_label")->setVisible(!is_info_type_agent); + mMaturityRatingText->setVisible(!is_info_type_agent); + + getChild<LLTextBox>("owner_label")->setVisible(is_info_type_agent); + mParcelOwner->setVisible(is_info_type_agent); + + getChild<LLTextBox>("last_visited_label")->setVisible(is_info_type_teleport_history); + 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); - mRegionInfoDrillIn->setVisible(is_info_type_agent); - mMediaDrillIn->setVisible(is_info_type_agent); + getChild<LLAccordionCtrl>("advanced_info_accordion")->setVisible(is_info_type_agent); + + LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); switch(type) { @@ -265,6 +339,15 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) break; case AGENT: + if (parcel_mgr) + { + // If information is requested for current agent location + // start using LLViewerParcelMgr for land selection. + parcel_mgr->addObserver(this); + parcel_mgr->selectParcelAt(gAgent.getPositionGlobal()); + } + + // Fall through to PLACE case case PLACE: mCurrentTitle = getString("title_place"); @@ -274,26 +357,35 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) } break; - // Hide Media Panel if showing information about - // a landmark or a teleport history item case LANDMARK: mCurrentTitle = getString("title_landmark"); break; case TELEPORT_HISTORY: - mCurrentTitle = getString("title_place"); + mCurrentTitle = getString("title_teleport_history"); break; } + if (type != AGENT && parcel_mgr != NULL) + { + if (!parcel_mgr->selectionEmpty()) + { + parcel_mgr->deselectUnused(); + } + parcel_mgr->removeObserver(this); + } + if (type != PLACE) toggleMediaPanel(FALSE); + + mInfoType = type; } BOOL LLPanelPlaceInfo::isMediaPanelVisible() { if (!mMediaPanel) return FALSE; - + return mMediaPanel->getVisible(); } @@ -363,18 +455,17 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) // HACK: Flag 0x2 == adult region, // Flag 0x1 == mature region, otherwise assume PG std::string rating = LLViewerRegion::accessToString(SIM_ACCESS_PG); - std::string rating_icon = "icon_event.tga"; if (parcel_data.flags & 0x2) { rating = LLViewerRegion::accessToString(SIM_ACCESS_ADULT); - rating_icon = "icon_event_adult.tga"; } else if (parcel_data.flags & 0x1) { rating = LLViewerRegion::accessToString(SIM_ACCESS_MATURE); - rating_icon = "icon_event_mature.tga"; } - mRating->setValue(rating_icon); + + mMaturityRatingText->setValue(rating); + mRatingText->setValue(rating); //update for_sale banner, here we should use DFQ_FOR_SALE instead of PF_FOR_SALE //because we deal with remote parcel response format @@ -402,7 +493,7 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) mRegionName->setText(name); } - if (mCurrentTitle != getString("title_landmark")) + if (mInfoType == CREATE_LANDMARK) { mTitleEditor->setText(parcel_data.name); mNotesEditor->setText(LLStringUtil::null); @@ -443,13 +534,21 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLVector3& pos_region, void LLPanelPlaceInfo::displayAgentParcelInfo() { - mPosRegion = gAgent.getPositionAgent(); + mParcel = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection(); - LLViewerRegion* region = gAgent.getRegion(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + LLParcel* parcel = mParcel->getParcel(); + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if (!region || !parcel) return; + // send EstateCovenantInfo message + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("EstateCovenantRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); + msg->sendReliable(region->getHost()); + LLParcelData parcel_data; // HACK: Converting sim access flags to the format @@ -465,13 +564,6 @@ void LLPanelPlaceInfo::displayAgentParcelInfo() default: parcel_data.flags = 0; } - - // Adding "For Sale" flag in remote parcel response format. - if (parcel->getForSale()) - { - parcel_data.flags |= DFQ_FOR_SALE; - } - parcel_data.desc = parcel->getDesc(); parcel_data.name = parcel->getName(); parcel_data.sim_name = gAgent.getRegion()->getName(); @@ -481,9 +573,241 @@ void LLPanelPlaceInfo::displayAgentParcelInfo() parcel_data.global_y = global_pos.mdV[1]; parcel_data.global_z = global_pos.mdV[2]; - + mPosRegion = gAgent.getPositionAgent(); processParcelInfo(parcel_data); + + std::string on = getString("on"); + std::string off = getString("off"); + + // Processing parcel characteristics + if (parcel->getParcelFlagAllowVoice()) + { + mVoiceText->setText(on); + } + else + { + mVoiceText->setText(off); + } + + if (!region->getBlockFly() && parcel->getAllowFly()) + { + mFlyText->setText(on); + } + else + { + mFlyText->setText(off); + } + + if (region->getRestrictPushObject() || parcel->getRestrictPushObject()) + { + mPushText->setText(off); + } + else + { + mPushText->setText(on); + } + + if (parcel->getAllowModify()) + { + mBuildText->setText(on); + } + else + { + mBuildText->setText(off); + } + + if((region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS) || + (region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS) || + !parcel->getAllowOtherScripts()) + { + mScriptsText->setText(off); + } + else + { + mScriptsText->setText(on); + } + + if (region->getAllowDamage() || parcel->getAllowDamage()) + { + mDamageText->setText(on); + } + else + { + mDamageText->setText(off); + } + + mRegionNameText->setText(region->getName()); + mRegionTypeText->setText(region->getSimProductName()); + mRegionRatingText->setText(region->getSimAccessString()); + + // Determine parcel owner + if (parcel->isPublic()) + { + mParcelOwner->setText(getString("public")); + mRegionOwnerText->setText(getString("public")); + } + else + { + if (parcel->getIsGroupOwned()) + { + mRegionOwnerText->setText(getString("group_owned_text")); + + if(!parcel->getGroupID().isNull()) + { + // FIXME: Using parcel group as region group. + gCacheName->get(parcel->getGroupID(), TRUE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mRegionGroupText, _2, _3)); + + gCacheName->get(parcel->getGroupID(), TRUE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mParcelOwner, _2, _3)); + } + else + { + std::string owner = getString("none_text"); + mRegionGroupText->setText(owner); + mParcelOwner->setText(owner); + } + } + else + { + // Figure out the owner's name + gCacheName->get(parcel->getOwnerID(), FALSE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mParcelOwner, _2, _3)); + gCacheName->get(region->getOwner(), FALSE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mRegionOwnerText, _2, _3)); + } + + if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus()) + { + mRegionOwnerText->setText(mRegionOwnerText->getText() + getString("sale_pending_text")); + } + } + + mEstateRatingText->setText(region->getSimAccessString()); + + S32 area; + S32 claim_price; + S32 rent_price; + F32 dwell; + BOOL for_sale = parcel->getForSale(); + LLViewerParcelMgr::getInstance()->getDisplayInfo(&area, + &claim_price, + &rent_price, + &for_sale, + &dwell); + + if (for_sale) + { + // Adding "For Sale" flag in remote parcel response format. + parcel_data.flags |= DFQ_FOR_SALE; + + const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID(); + if(auth_buyer_id.notNull()) + { + gCacheName->get(auth_buyer_id, TRUE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mSaleToText, _2, _3)); + + // Show sales info to a specific person or a group he belongs to. + if (auth_buyer_id != gAgent.getID() && !gAgent.isInGroup(auth_buyer_id)) + { + for_sale = FALSE; + } + } + else + { + mSaleToText->setText(getString("anyone")); + } + + const U8* sign = (U8*)getString("price_text").c_str(); + const U8* sqm = (U8*)getString("area_text").c_str(); + + mSalesPriceText->setText(llformat("%s%d ", sign, parcel->getSalePrice())); + mAreaText->setText(llformat("%d %s", area, sqm)); + mTrafficText->setText(llformat("%.0f", dwell)); + + // Can't have more than region max tasks, regardless of parcel + // object bonus factor. + S32 primitives = llmin(llround(parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus()), + (S32)region->getMaxTasks()); + + const U8* available = (U8*)getString("available").c_str(); + const U8* allocated = (U8*)getString("allocated").c_str(); + + mPrimitivesText->setText(llformat("%d %s, %d %s", primitives, available, parcel->getPrimCount(), allocated)); + + if (parcel->getAllowOtherScripts()) + { + mParcelScriptsText->setText(getString("all_residents_text")); + } + else if (parcel->getAllowGroupScripts()) + { + mParcelScriptsText->setText(getString("group_text")); + } + else + { + mParcelScriptsText->setText(off); + } + + mTerraformLimitsText->setText(parcel->getAllowTerraform() ? on : off); + + if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES) + { + mSubdivideText->setText(getString("can_change")); + } + else + { + mSubdivideText->setText(getString("can_not_change")); + } + if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL) + { + mResaleText->setText(getString("can_not_resell")); + } + else + { + mResaleText->setText(getString("can_resell")); + } + } + + getChild<LLAccordionCtrlTab>("sales_tab")->setVisible(for_sale); +} + +// virtual +void LLPanelPlaceInfo::changed() +{ + resetLocation(); + displayAgentParcelInfo(); +} + +void LLPanelPlaceInfo::updateEstateName(const std::string& name) +{ + mEstateNameText->setText(name); +} + +void LLPanelPlaceInfo::updateEstateOwnerName(const std::string& name) +{ + mEstateOwnerText->setText(name); +} + +void LLPanelPlaceInfo::updateCovenantText(const std::string &text) +{ + mCovenantText->setText(text); +} + +void LLPanelPlaceInfo::updateLastVisitedText(const LLDate &date) +{ + if (date.isNull()) + { + mLastVisited->setText(getString("unknown")); + } + else + { + std::string timeStr = getString("acquired_date"); + LLSD substitution; + substitution["datetime"] = (S32) date.secondsSinceEpoch(); + LLStringUtil::format (timeStr, substitution); + mLastVisited->setText(timeStr); + } } void LLPanelPlaceInfo::onCommitTitleOrNote(LANDMARK_INFO_TYPE type) @@ -573,6 +897,7 @@ void LLPanelPlaceInfo::createPick(const LLVector3d& global_pos) LLAvatarPropertiesProcessor::instance().sendDataUpdate(&pick_data, APT_PICK_INFO); } +// virtual void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) { if (mMinHeight > 0 && mScrollingPanel != NULL) @@ -582,3 +907,22 @@ void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) LLView::reshape(width, height, called_from_parent); } + +// virtual +void LLPanelPlaceInfo::handleVisibilityChange (BOOL new_visibility) +{ + LLPanel::handleVisibilityChange(new_visibility); + + LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); + if (!parcel_mgr) + return; + + // Remove land selection when panel hides. + if (!new_visibility) + { + if (!parcel_mgr->selectionEmpty()) + { + parcel_mgr->deselectLand(); + } + } +} diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 77ce2c6619..60f35cd0c1 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -42,15 +42,17 @@ #include "llpanelmedia.h" #include "llremoteparcelrequest.h" +#include "llviewerparcelmgr.h" class LLButton; class LLInventoryItem; class LLLineEditor; +class LLParcelSelection; class LLTextBox; class LLTextEditor; class LLTextureCtrl; -class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver +class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver, LLParcelObserver { public: enum INFO_TYPE @@ -105,12 +107,21 @@ public: // without sending a request to the server. void displayAgentParcelInfo(); + // Called on parcel selection change by LLViewerParcelMgr. + /*virtual*/ void changed(); + + void updateEstateName(const std::string& name); + void updateEstateOwnerName(const std::string& name); + void updateCovenantText(const std::string &text); + void updateLastVisitedText(const LLDate &date); + void nameUpdatedCallback(LLTextBox* text, const std::string& first, const std::string& last); /*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 @@ -127,24 +138,56 @@ private: LLVector3 mPosRegion; std::string mCurrentTitle; S32 mMinHeight; + INFO_TYPE mInfoType; LLTextBox* mTitle; LLTextureCtrl* mSnapshotCtrl; LLTextBox* mRegionName; LLTextBox* mParcelName; LLTextEditor* mDescEditor; - LLIconCtrl* mRating; - LLButton* mRegionInfoDrillIn; - LLButton* mMediaDrillIn; + LLTextBox* mMaturityRatingText; + LLTextBox* mParcelOwner; + LLTextBox* mLastVisited; + + LLTextBox* mRatingText; + LLTextBox* mVoiceText; + LLTextBox* mFlyText; + LLTextBox* mPushText; + LLTextBox* mBuildText; + LLTextBox* mScriptsText; + LLTextBox* mDamageText; + + LLTextBox* mRegionNameText; + LLTextBox* mRegionTypeText; + LLTextBox* mRegionRatingText; + LLTextBox* mRegionOwnerText; + LLTextBox* mRegionGroupText; + + LLTextBox* mEstateNameText; + LLTextBox* mEstateRatingText; + LLTextBox* mEstateOwnerText; + LLTextEditor* mCovenantText; + + LLTextBox* mSalesPriceText; + LLTextBox* mAreaText; + LLTextBox* mTrafficText; + LLTextBox* mPrimitivesText; + LLTextBox* mParcelScriptsText; + LLTextBox* mTerraformLimitsText; + LLTextEditor* mSubdivideText; + LLTextEditor* mResaleText; + LLTextBox* mSaleToText; + LLTextBox* mOwner; LLTextBox* mCreator; LLTextBox* mCreated; LLLineEditor* mTitleEditor; LLTextEditor* mNotesEditor; - LLTextBox* mLocationEditor; LLPanel* mScrollingPanel; LLPanel* mInfoPanel; LLMediaPanel* mMediaPanel; + + LLSafeHandle<LLParcelSelection> mParcel; }; #endif // LL_LLPANELPLACEINFO_H diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 7cb9e61e72..bc740bd865 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -51,6 +51,7 @@ #include "llpanellandmarks.h" #include "llpanelteleporthistory.h" #include "llsidetray.h" +#include "llteleporthistorystorage.h" #include "lltoggleablemenu.h" #include "llviewerinventory.h" #include "llviewermenu.h" @@ -119,9 +120,6 @@ BOOL LLPanelPlaces::postBuild() //mShareBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onShareButtonClicked, this)); mOverflowBtn = getChild<LLButton>("overflow_btn"); - - // *TODO: Assign the action to an appropriate event. - //mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::toggleMediaPanel, this)); mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this)); LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; @@ -156,20 +154,17 @@ BOOL LLPanelPlaces::postBuild() LLButton* back_btn = mPlaceInfo->getChild<LLButton>("back_btn"); back_btn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this)); - // *TODO: Assign the action to an appropriate event. - mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::toggleMediaPanel, this)); - return TRUE; } void LLPanelPlaces::onOpen(const LLSD& key) { - mFilterEditor->clear(); - onFilterEdit(""); - if(mPlaceInfo == NULL || key.size() == 0) return; + mFilterEditor->clear(); + onFilterEdit(""); + mPlaceInfoType = key["type"].asString(); mPosGlobal.setZero(); togglePlaceInfoPanel(TRUE); @@ -178,8 +173,7 @@ void LLPanelPlaces::onOpen(const LLSD& key) if (mPlaceInfoType == AGENT_INFO_TYPE) { mPlaceInfo->setInfoType(LLPanelPlaceInfo::AGENT); - mPlaceInfo->displayAgentParcelInfo(); - + mPosGlobal = gAgent.getPositionGlobal(); } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) @@ -218,18 +212,17 @@ void LLPanelPlaces::onOpen(const LLSD& key) { S32 index = key["id"].asInteger(); - const LLTeleportHistory::slurl_list_t& hist_items = - LLTeleportHistory::getInstance()->getItems(); + const LLTeleportHistoryStorage::slurl_list_t& hist_items = + LLTeleportHistoryStorage::getInstance()->getItems(); mPosGlobal = hist_items[index].mGlobalPos; mPlaceInfo->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY); + mPlaceInfo->updateLastVisitedText(hist_items[index].mDate); mPlaceInfo->displayParcelInfo(get_pos_local_from_global(mPosGlobal), - hist_items[index].mRegionID, + LLUUID(), mPosGlobal); } - - } void LLPanelPlaces::setItem(LLInventoryItem* item) diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index 089a854762..057c430230 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -79,7 +79,7 @@ private: void onAgentParcelChange(); void updateVerbs(); - + void showLandmarkFoldersMenu(); LLFilterEditor* mFilterEditor; diff --git a/indra/newview/llpanelprofileview.cpp b/indra/newview/llpanelprofileview.cpp index 18184a6476..0762bbeb87 100644 --- a/indra/newview/llpanelprofileview.cpp +++ b/indra/newview/llpanelprofileview.cpp @@ -31,12 +31,16 @@ */ #include "llviewerprecompiledheaders.h" + +#include "lluserrelations.h" + #include "llpanelprofileview.h" +#include "llcallingcard.h" #include "llpanelavatar.h" #include "llpanelpicks.h" -#include "llsidetraypanelcontainer.h" #include "llpanelprofile.h" +#include "llsidetraypanelcontainer.h" static LLRegisterPanelClassWrapper<LLPanelProfileView> t_panel_target_profile("panel_profile_view"); @@ -45,6 +49,7 @@ static const std::string PANEL_PROFILE = "panel_profile"; LLPanelProfileView::LLPanelProfileView() : LLPanelProfile() +, mStatusText(NULL) { } @@ -65,6 +70,10 @@ void LLPanelProfileView::onOpen(const LLSD& key) setAvatarId(id); } + // status should only show if viewer has permission to view online/offline. EXT-453 + mStatusText->setVisible(isGrantedToSeeOnlineStatus()); + updateOnlineStatus(); + LLPanelProfile::onOpen(key); } @@ -78,6 +87,8 @@ BOOL LLPanelProfileView::postBuild() getTabContainer()[PANEL_PROFILE]->childSetVisible("online_me_status_text", FALSE); getTabContainer()[PANEL_PROFILE]->childSetVisible("status_combo", FALSE); + mStatusText = getChild<LLTextBox>("status"); + childSetCommitCallback("back",boost::bind(&LLPanelProfileView::onBackBtnClick,this),NULL); return TRUE; @@ -94,3 +105,32 @@ void LLPanelProfileView::onBackBtnClick() parent->openPreviousPanel(); } } + +bool LLPanelProfileView::isGrantedToSeeOnlineStatus() +{ + const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + if (NULL == relationship) + return false; + + // *NOTE: GRANT_ONLINE_STATUS is always set to false while changing any other status. + // When avatar disallow me to see her online status processOfflineNotification Message is received by the viewer + // see comments for ChangeUserRights template message. EXT-453. +// return relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS); + return true; +} + +void LLPanelProfileView::updateOnlineStatus() +{ + const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + if (NULL == relationship) + return; + + bool online = relationship->isOnline(); +// std::string statusName(); + + std::string status = getString(online ? "status_online" : "status_offline"); + + mStatusText->setValue(status); +} + +// EOF diff --git a/indra/newview/llpanelprofileview.h b/indra/newview/llpanelprofileview.h index 92def7b7ca..533ab94cc3 100644 --- a/indra/newview/llpanelprofileview.h +++ b/indra/newview/llpanelprofileview.h @@ -39,7 +39,7 @@ class LLPanelProfile; class LLPanelProfileTab; - +class LLTextBox; /** * Panel for displaying Avatar's profile. It consists of three sub panels - Profile, @@ -63,6 +63,11 @@ public: protected: void onBackBtnClick(); + bool isGrantedToSeeOnlineStatus(); + void updateOnlineStatus(); + +private: + LLTextBox* mStatusText; }; #endif //LL_LLPANELPROFILEVIEW_H diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 8b378c33e3..df48ee5d08 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -37,6 +37,7 @@ #include "llpanelteleporthistory.h" #include "llsidetray.h" #include "llworldmap.h" +#include "llteleporthistorystorage.h" // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper<LLTeleportHistoryPanel> t_teleport_history("panel_teleport_history"); @@ -56,7 +57,7 @@ LLTeleportHistoryPanel::~LLTeleportHistoryPanel() BOOL LLTeleportHistoryPanel::postBuild() { - mTeleportHistory = LLTeleportHistory::getInstance(); + mTeleportHistory = LLTeleportHistoryStorage::getInstance(); if (mTeleportHistory) { mTeleportHistory->setHistoryChangedCallback(boost::bind(&LLTeleportHistoryPanel::showTeleportHistory, this)); @@ -92,9 +93,7 @@ void LLTeleportHistoryPanel::onShowOnMap() S32 index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); - const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems(); - - LLVector3d global_pos = hist_items[index].mGlobalPos; + LLVector3d global_pos = mTeleportHistory->getItems()[index].mGlobalPos; if (!global_pos.isExactlyZero()) { @@ -153,7 +152,7 @@ void LLTeleportHistoryPanel::updateVerbs() if (itemp) { index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); - cur_item = mTeleportHistory->getCurrentItemIndex(); + cur_item = mTeleportHistory->getItems().size() - 1; } mTeleportBtn->setEnabled(index != cur_item); @@ -162,13 +161,11 @@ void LLTeleportHistoryPanel::updateVerbs() void LLTeleportHistoryPanel::showTeleportHistory() { - const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems(); + const LLTeleportHistoryStorage::slurl_list_t& hist_items = mTeleportHistory->getItems(); mHistoryItems->deleteAllItems(); - S32 cur_item = mTeleportHistory->getCurrentItemIndex(); - - for (LLTeleportHistory::slurl_list_t::const_iterator iter = hist_items.begin(); + for (LLTeleportHistoryStorage::slurl_list_t::const_iterator iter = hist_items.begin(); iter != hist_items.end(); ++iter) { std::string landmark_title = (*iter).mTitle; @@ -181,7 +178,6 @@ void LLTeleportHistoryPanel::showTeleportHistory() continue; S32 index = iter - hist_items.begin(); - LLSD row; row["id"] = index; @@ -201,14 +197,12 @@ void LLTeleportHistoryPanel::showTeleportHistory() index_column["value"] = index; mHistoryItems->addElement(row, ADD_TOP); - - if (cur_item == index) - { - LLScrollListItem* itemp = mHistoryItems->getItem(index); - ((LLScrollListText*)itemp->getColumn(LIST_ITEM_TITLE))->setFontStyle(LLFontGL::BOLD); - } } + // Consider last item (most recent) as current + LLScrollListItem* itemp = mHistoryItems->getItem((S32)hist_items.size() - 1); + ((LLScrollListText*)itemp->getColumn(LIST_ITEM_TITLE))->setFontStyle(LLFontGL::BOLD); + updateVerbs(); } diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h index 553385b37e..023b04c3fa 100644 --- a/indra/newview/llpanelteleporthistory.h +++ b/indra/newview/llpanelteleporthistory.h @@ -39,6 +39,8 @@ #include "llpanelplacestab.h" #include "llteleporthistory.h" +class LLTeleportHistoryStorage; + class LLTeleportHistoryPanel : public LLPanelPlacesTab { public: @@ -65,7 +67,7 @@ private: LIST_INDEX }; - LLTeleportHistory* mTeleportHistory; + LLTeleportHistoryStorage* mTeleportHistory; LLScrollListCtrl* mHistoryItems; std::string mFilterSubString; }; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index cadab71ba8..29320522d9 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -87,6 +87,7 @@ BOOL LLPreviewNotecard::postBuild() LLViewerTextEditor *ed = getChild<LLViewerTextEditor>("Notecard Editor"); if (ed) { + ed->setParseHTML(TRUE); ed->setNotecardInfo(mItemUUID, mObjectID, getKey()); ed->makePristine(); } @@ -126,7 +127,7 @@ void LLPreviewNotecard::draw() { LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor"); BOOL changed = !editor->isPristine(); - + childSetEnabled("Save", changed && getEnabled()); LLPreview::draw(); diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index f70cfc59ec..aa603c417f 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -72,7 +72,6 @@ const S32 ANIMATION_FRAMES = 1; //13; LLProgressView::LLProgressView(const LLRect &rect) : LLPanel(), mPercentDone( 0.f ), - mURLInMessage(false), mMouseDownInActiveArea( false ) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_progress.xml"); @@ -207,12 +206,7 @@ void LLProgressView::setPercent(const F32 percent) void LLProgressView::setMessage(const std::string& msg) { mMessage = msg; - mURLInMessage = (mMessage.find( "https://" ) != std::string::npos || - mMessage.find( "http://" ) != std::string::npos || - mMessage.find( "ftp://" ) != std::string::npos); - getChild<LLTextBox>("message_text")->setWrappedText(LLStringExplicit(mMessage)); - getChild<LLTextBox>("message_text")->setHoverActive(mURLInMessage); } void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label) diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h index 83574ff52a..865646c85d 100644 --- a/indra/newview/llprogressview.h +++ b/indra/newview/llprogressview.h @@ -74,7 +74,6 @@ protected: LLFrameTimer mProgressTimer; LLRect mOutlineRect; bool mMouseDownInActiveArea; - bool mURLInMessage; static LLProgressView* sInstance; }; diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 68996673be..1fbe359295 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -88,9 +88,12 @@ void LLScreenChannel::reshape(S32 width, S32 height, BOOL called_from_parent) //-------------------------------------------------------------------------- void LLScreenChannel::addToast(LLToast::Params p) { - bool store_toast = !mShowToasts && p.can_be_stored && mCanStoreToasts; + bool store_toast = false, show_toast = false; - if(!mShowToasts && !store_toast) + show_toast = mShowToasts || p.force_show; + store_toast = !show_toast && p.can_be_stored && mCanStoreToasts; + + if(!show_toast && !store_toast) { mOnRejectToast(p); return; @@ -106,7 +109,7 @@ void LLScreenChannel::addToast(LLToast::Params p) new_toast_elem.toast->setOnToastHoverCallback(boost::bind(&LLScreenChannel::onToastHover, this, _1, _2)); } - if(mShowToasts) + if(show_toast) { mToastList.push_back(new_toast_elem); showToasts(); diff --git a/indra/newview/llsearchcombobox.cpp b/indra/newview/llsearchcombobox.cpp new file mode 100644 index 0000000000..c903f40f3f --- /dev/null +++ b/indra/newview/llsearchcombobox.cpp @@ -0,0 +1,250 @@ +/** + * @file llsearchcombobox.cpp + * @brief Search Combobox implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsearchcombobox.h" + +#include "llkeyboard.h" +#include "lluictrlfactory.h" + +static LLDefaultChildRegistry::Register<LLSearchComboBox> r1("search_combo_box"); + +class LLSearchHistoryBuilder +{ +public: + LLSearchHistoryBuilder(LLSearchComboBox* combo_box, const std::string& filter); + + virtual void buildSearchHistory(); + + virtual ~LLSearchHistoryBuilder(){} + +protected: + + virtual bool filterSearchHistory(); + + LLSearchComboBox* mComboBox; + std::string mFilter; + LLSearchHistory::search_history_list_t mFilteredSearchHistory; +}; + +LLSearchComboBox::Params::Params() +: search_button("search_button") +, dropdown_button_visible("dropdown_button_visible", false) +{ +} + +LLSearchComboBox::LLSearchComboBox(const Params&p) +: LLComboBox(p) +{ + S32 btn_top = p.search_button.top_pad + p.search_button.rect.height; + S32 btn_right = p.search_button.rect.width + p.search_button.left_pad; + LLRect search_btn_rect(p.search_button.left_pad, btn_top, btn_right, p.search_button.top_pad); + + LLButton::Params button_params(p.search_button); + button_params.name(std::string("search_btn")); + button_params.rect(search_btn_rect) ; + button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP); + button_params.tab_stop(false); + button_params.click_callback.function(boost::bind(&LLSearchComboBox::onSelectionCommit, this)); + mSearchButton = LLUICtrlFactory::create<LLButton>(button_params); + mTextEntry->addChild(mSearchButton); + + setButtonVisible(p.dropdown_button_visible); + mTextEntry->setCommitCallback(boost::bind(&LLComboBox::onTextCommit, this, _2)); + mTextEntry->setKeystrokeCallback(boost::bind(&LLComboBox::onTextEntry, this, _1), NULL); + setSelectionCallback(boost::bind(&LLSearchComboBox::onSelectionCommit, this)); + setPrearrangeCallback(boost::bind(&LLSearchComboBox::onSearchPrearrange, this, _2)); +} + +void LLSearchComboBox::rebuildSearchHistory(const std::string& filter) +{ + LLSearchHistoryBuilder builder(this, filter); + builder.buildSearchHistory(); +} + +void LLSearchComboBox::onSearchPrearrange(const LLSD& data) +{ + std::string filter = data.asString(); + rebuildSearchHistory(filter); + + mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item. +} + +void LLSearchComboBox::onTextEntry(LLLineEditor* line_editor) +{ + KEY key = gKeyboard->currentKey(); + + if (line_editor->getText().empty()) + { + prearrangeList(); // resets filter + hideList(); + } + // Typing? (moving cursor should not affect showing the list) + else if (key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) + { + prearrangeList(line_editor->getText()); + if (mList->getItemCount() != 0) + { + showList(); + focusTextEntry(); + } + else + { + // Hide the list if it's empty. + hideList(); + } + } + LLComboBox::onTextEntry(line_editor); +} + +void LLSearchComboBox::focusTextEntry() +{ + // We can't use "mTextEntry->setFocus(TRUE)" instead because + // if the "select_on_focus" parameter is true it places the cursor + // at the beginning (after selecting text), thus screwing up updateSelection(). + if (mTextEntry) + { + gFocusMgr.setKeyboardFocus(mTextEntry); + } +} + +void LLSearchComboBox::hideList() +{ + LLComboBox::hideList(); + if (mTextEntry && hasFocus()) + focusTextEntry(); +} + +LLSearchComboBox::~LLSearchComboBox() +{ +} + +void LLSearchComboBox::onSelectionCommit() +{ + std::string search_query = getSimple(); + LLStringUtil::trim(search_query); + if(search_query.empty()) + { + mTextEntry->setText(search_query); + setControlValue(search_query); + + return; + } + + remove(search_query); + add(search_query, ADD_TOP); + mTextEntry->setText(search_query); + setControlValue(search_query); + + LLUICtrl::onCommit(); +} + +BOOL LLSearchComboBox::remove(const std::string& name) +{ + BOOL found = mList->selectItemByLabel(name, FALSE); + + if (found) + { + LLScrollListItem* item = mList->getFirstSelected(); + if (item) + { + LLComboBox::remove(mList->getItemIndex(item)); + } + } + + return found; +} + +void LLSearchComboBox::clearHistory() +{ + removeall(); + setTextEntry(LLStringUtil::null); +} + +LLSearchHistoryBuilder::LLSearchHistoryBuilder(LLSearchComboBox* combo_box, const std::string& filter) +: mComboBox(combo_box) +, mFilter(filter) +{ +} + +bool LLSearchHistoryBuilder::filterSearchHistory() +{ + // *TODO: an STL algorithm would look nicer + mFilteredSearchHistory.clear(); + + std::string filter_copy = mFilter; + LLStringUtil::toLower(filter_copy); + + LLSearchHistory::search_history_list_t history = + LLSearchHistory::getInstance()->getSearchHistoryList(); + + LLSearchHistory::search_history_list_t::const_iterator it = history.begin(); + for ( ; it != history.end(); ++it) + { + std::string search_query = (*it).search_query; + LLStringUtil::toLower(search_query); + + if (search_query.find(filter_copy) != std::string::npos) + mFilteredSearchHistory.push_back(*it); + } + + return mFilteredSearchHistory.size(); +} + +void LLSearchHistoryBuilder::buildSearchHistory() +{ + mFilteredSearchHistory.clear(); + + LLSearchHistory::search_history_list_t filtered_items; + LLSearchHistory::search_history_list_t* itemsp = NULL; + LLSearchHistory* sh = LLSearchHistory::getInstance(); + + if (mFilter.empty()) + { + itemsp = &sh->getSearchHistoryList(); + } + else + { + filterSearchHistory(); + itemsp = &mFilteredSearchHistory; + itemsp->sort(); + } + + mComboBox->removeall(); + + LLSearchHistory::search_history_list_t::const_iterator it = itemsp->begin(); + for ( ; it != itemsp->end(); it++) + { + LLSearchHistory::LLSearchHistoryItem item = *it; + mComboBox->add(item.search_query); + } +} diff --git a/indra/newview/llsearchcombobox.h b/indra/newview/llsearchcombobox.h new file mode 100644 index 0000000000..38f9a5a26b --- /dev/null +++ b/indra/newview/llsearchcombobox.h @@ -0,0 +1,108 @@ +/** + * @file llsearchcombobox.h + * @brief LLSearchComboBox class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSEARCHCOMBOBOX_H +#define LL_LLSEARCHCOMBOBOX_H + +#include "llcombobox.h" +#include "llsearchhistory.h" + +/** + * Search control with text box for search queries and a drop down list + * with recent queries. Supports text auto-complete and filtering of drop down list + * according to typed text. + */ +class LLSearchComboBox : public LLComboBox +{ +public: + + struct Params : public LLInitParam::Block<Params, LLComboBox::Params> + { + Optional<LLButton::Params> search_button; + Optional<bool> dropdown_button_visible; + + Params(); + }; + + /** + * Removes an entry from combo box, case insensitive + */ + BOOL remove(const std::string& name); + + /** + * Clears search history + */ + void clearHistory(); + + ~LLSearchComboBox(); + +protected: + + LLSearchComboBox(const Params&p); + friend class LLUICtrlFactory; + + /** + * Handles typing in text box + */ + void onTextEntry(LLLineEditor* line_editor); + + /** + * Hides drop down list and focuses text box + */ + void hideList(); + + /** + * Rebuilds search history, case insensitive + * If filter is an empty string - whole history will be added to combo box + * if filter is valid string - only matching entries will be added + */ + virtual void rebuildSearchHistory(const std::string& filter); + + /** + * Callback for prearrange event + */ + void onSearchPrearrange(const LLSD& data); + + /** + * Callback for text box or combo box commit + */ + void onSelectionCommit(); + + /** + * Sets focus to text box + */ + void focusTextEntry(); + + LLButton* mSearchButton; +}; + +#endif //LL_LLSEARCHCOMBOBOX_H diff --git a/indra/newview/llsearchhistory.cpp b/indra/newview/llsearchhistory.cpp new file mode 100644 index 0000000000..d45a1efa0e --- /dev/null +++ b/indra/newview/llsearchhistory.cpp @@ -0,0 +1,154 @@ +/** + * @file llsearchhistory.cpp + * @brief Search history container implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsearchhistory.h" + +#include "llfile.h" +#include "llsdserialize.h" +#include "llxmlnode.h" + +std::string LLSearchHistory::SEARCH_QUERY = "search_query"; +std::string LLSearchHistory::SEARCH_HISTORY_FILE_NAME = "search_history.txt"; + +LLSearchHistory::LLSearchHistory() +{ + +} + +bool LLSearchHistory::load() +{ + // build filename for each user + std::string resolved_filename = getHistoryFilePath(); + llifstream file(resolved_filename); + if (!file.is_open()) + { + return false; + } + + clearHistory(); + + // add each line in the file to the list + std::string line; + LLPointer<LLSDParser> parser = new LLSDNotationParser(); + while (std::getline(file, line)) + { + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + break; + } + + mSearchHistory.push_back(s_item); + } + + file.close(); + + return true; +} + +bool LLSearchHistory::save() +{ + // build filename for each user + std::string resolved_filename = getHistoryFilePath(); + // open a file for writing + llofstream file (resolved_filename); + if (!file.is_open()) + { + return false; + } + + search_history_list_t::const_iterator it = mSearchHistory.begin(); + for (; mSearchHistory.end() != it; ++it) + { + file << LLSDOStreamer<LLSDNotationFormatter>((*it).toLLSD()) << std::endl; + } + + file.close(); + return true; +} + +std::string LLSearchHistory::getHistoryFilePath() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SEARCH_HISTORY_FILE_NAME); +} + +void LLSearchHistory::addEntry(const std::string& search_query) +{ + if(search_query.empty()) + { + return; + } + + search_history_list_t::iterator it = + find(mSearchHistory.begin(), mSearchHistory.end(), search_query); + + if(mSearchHistory.end() != it) + { + mSearchHistory.erase(it); + } + + LLSearchHistoryItem item(search_query); + mSearchHistory.push_front(item); +} + +bool LLSearchHistory::LLSearchHistoryItem::operator < (const LLSearchHistory::LLSearchHistoryItem& right) +{ + S32 result = LLStringUtil::compareInsensitive(search_query, right.search_query); + + return result < 0; +} + +bool LLSearchHistory::LLSearchHistoryItem::operator > (const LLSearchHistory::LLSearchHistoryItem& right) +{ + S32 result = LLStringUtil::compareInsensitive(search_query, right.search_query); + + return result > 0; +} + +bool LLSearchHistory::LLSearchHistoryItem::operator==(const LLSearchHistory::LLSearchHistoryItem& right) +{ + return 0 == LLStringUtil::compareInsensitive(search_query, right.search_query); +} + +bool LLSearchHistory::LLSearchHistoryItem::operator==(const std::string& right) +{ + return 0 == LLStringUtil::compareInsensitive(search_query, right); +} + +LLSD LLSearchHistory::LLSearchHistoryItem::toLLSD() const +{ + LLSD ret; + ret[SEARCH_QUERY] = search_query; + return ret; +} diff --git a/indra/newview/llsearchhistory.h b/indra/newview/llsearchhistory.h new file mode 100644 index 0000000000..253ef21e9e --- /dev/null +++ b/indra/newview/llsearchhistory.h @@ -0,0 +1,138 @@ +/** + * @file llsearchhistory.h + * @brief Search history container definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSEARCHHISTORY_H +#define LL_LLSEARCHHISTORY_H + +#include "llsingleton.h" +/** + * Search history container able to save and load history from file. + * History is stored in chronological order, most recent at the beginning. + */ +class LLSearchHistory : public LLSingleton<LLSearchHistory> +{ +public: + + // Forward declaration + class LLSearchHistoryItem; + + // Search history container + typedef std::list<LLSearchHistoryItem> search_history_list_t; + + /** + * Saves search history to file + */ + bool save(); + + /** + * loads search history from file + */ + bool load(); + + /** + * Returns search history list + */ + search_history_list_t& getSearchHistoryList() { return mSearchHistory; } + + /** + * Deletes all search history queries from list. + */ + void clearHistory() { mSearchHistory.clear(); } + + /** + * Adds unique entry to front of search history list, case insensitive + * If entry is already in list, it will be deleted and added to front. + */ + void addEntry(const std::string& search_text); + + LLSearchHistory(); + + /** + * Class for storing data about single search request. + */ + class LLSearchHistoryItem + { + public: + + LLSearchHistoryItem() + {} + + LLSearchHistoryItem(const std::string& query) + : search_query(query) + {} + + LLSearchHistoryItem(const LLSD& item) + { + if(item.has(SEARCH_QUERY)) + search_query = item[SEARCH_QUERY].asString(); + } + + std::string search_query; + + /** + * Allows std::list sorting + */ + bool operator < (const LLSearchHistory::LLSearchHistoryItem& right); + + /** + * Allows std::list sorting + */ + bool operator > (const LLSearchHistory::LLSearchHistoryItem& right); + + bool operator==(const LLSearchHistoryItem& right); + + bool operator==(const std::string& right); + + /** + * Serializes search history item to LLSD + */ + LLSD toLLSD() const; + }; + +protected: + + /** + * Returns path to search history file. + */ + std::string getHistoryFilePath(); + + static std::string SEARCH_HISTORY_FILE_NAME; + static std::string SEARCH_QUERY; + +private: + + search_history_list_t mSearchHistory; +}; + +class LLSearchComboBox; + +#endif //LL_LLSEARCHHISTORY_H diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index afa8e5f072..381e63f020 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -241,6 +241,13 @@ LLSideTray::LLSideTray(Params& params) ,mMaxBarWidth(params.rect.width) { mCollapsed=params.collapsed; + + + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + + // register handler function to process data from the xml. + // panel_name should be specified via "parameter" attribute. + commit.add("SideTray.ShowPanel", boost::bind(&LLSideTray::showPanel, this, _2, LLUUID::null)); } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6c0481feaa..8fb0f201cb 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -899,6 +899,10 @@ bool idle_startup() if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) { + // Move the progress view in front of the UI immediately when login is performed + // this allows not to see main menu after Alt+Tab was pressed while login. EXT-744. + gViewerWindow->moveProgressViewToFront(); + //reset the values that could have come in from a slurl if (!gLoginHandler.getWebLoginKey().isNull()) { diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 2bbb5a2767..7ddbf0a744 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -38,31 +38,34 @@ #include "llviewercontrol.h" #include "llviewerwindow.h" +#include "llchiclet.h" //--------------------------------------------------------------------------------- -LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLFloater(LLSD()), +LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLDockableFloater(NULL, key), mChannel(NULL), mScrollContainer(NULL), mNotificationList(NULL) { + LLIMMgr::getInstance()->addSessionObserver(this); + LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLSysWellWindow::findIMChiclet, this, _1)); } //--------------------------------------------------------------------------------- BOOL LLSysWellWindow::postBuild() { mScrollContainer = getChild<LLScrollContainer>("notification_list_container"); + mTwinListPanel = getChild<LLPanel>("twin_list_panel"); mNotificationList = getChild<LLScrollingPanelList>("notification_list"); + mIMRowList = getChild<LLScrollingPanelList>("im_row_panel_list"); - gViewerWindow->setOnBottomTrayWidthChanged(boost::bind(&LLSysWellWindow::adjustWindowPosition, this)); // *TODO: won't be necessary after docking is realized mScrollContainer->setBorderVisible(FALSE); - mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); - - return TRUE; + return LLDockableFloater::postBuild(); } //--------------------------------------------------------------------------------- LLSysWellWindow::~LLSysWellWindow() { + LLIMMgr::getInstance()->removeSessionObserver(this); } //--------------------------------------------------------------------------------- @@ -75,7 +78,6 @@ void LLSysWellWindow::addItem(LLSysWellItem::Params p) LLSysWellItem* new_item = new LLSysWellItem(p); mNotificationList->addPanel(dynamic_cast<LLScrollingPanel*>(new_item)); reshapeWindow(); - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); @@ -120,11 +122,6 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id) return; reshapeWindow(); - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized - // hide chiclet window if there are no items left - S32 items_left = mNotificationList->getPanelList().size(); - if(items_left == 0) - setVisible(FALSE); } //--------------------------------------------------------------------------------- @@ -142,11 +139,20 @@ void LLSysWellWindow::onItemClose(LLSysWellItem* item) removeItemByID(id); if(mChannel) mChannel->killToastByNotificationID(id); + + // hide chiclet window if there are no items left + setVisible(!isWindowEmpty()); } //--------------------------------------------------------------------------------- void LLSysWellWindow::toggleWindow() { + if (getDockControl() == NULL) + { + setDockControl(new LLDockControl( + LLBottomTray::getInstance()->getSysWell(), this, + getDockTongue(), LLDockControl::TOP, isDocked())); + } setVisible(!getVisible()); } @@ -156,12 +162,20 @@ void LLSysWellWindow::setVisible(BOOL visible) // on Show adjust position of SysWell chiclet's window if(visible) { + if (LLBottomTray::instanceExists()) + { + LLBottomTray::getInstance()->getSysWell()->setToggleState(TRUE); + } if(mChannel) mChannel->removeAndStoreAllVisibleToasts(); - - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized } - + else + { + if (LLBottomTray::instanceExists()) + { + LLBottomTray::getInstance()->getSysWell()->setToggleState(FALSE); + } + } if(mChannel) mChannel->setShowToasts(!visible); @@ -169,45 +183,211 @@ void LLSysWellWindow::setVisible(BOOL visible) } //--------------------------------------------------------------------------------- -void LLSysWellWindow::adjustWindowPosition() // *TODO: won't be necessary after docking is realized -{ - const S32 WINDOW_MARGIN = 5; - - LLRect btm_rect = LLBottomTray::getInstance()->getRect(); - LLRect this_rect = getRect(); - setOrigin(btm_rect.mRight - this_rect.getWidth() - WINDOW_MARGIN, WINDOW_MARGIN); -} -//--------------------------------------------------------------------------------- void LLSysWellWindow::reshapeWindow() { // Get size for scrollbar and floater's header const LLUICachedControl<S32> SCROLLBAR_SIZE("UIScrollbarSize", 0); const LLUICachedControl<S32> HEADER_SIZE("UIFloaterHeaderSize", 0); - // Get item list - const LLScrollingPanelList::panel_list_t list = mNotificationList->getPanelList(); + LLRect notif_list_rect = mNotificationList->getRect(); + LLRect im_list_rect = mIMRowList->getRect(); + LLRect panel_rect = mTwinListPanel->getRect(); + + S32 notif_list_height = notif_list_rect.getHeight(); + S32 im_list_height = im_list_rect.getHeight(); - // Get height for a scrolling panel list - S32 list_height = mNotificationList->getRect().getHeight(); + S32 new_panel_height = notif_list_height + LLScrollingPanelList::GAP_BETWEEN_PANELS + im_list_height; + S32 new_window_height = new_panel_height + LLScrollingPanelList::GAP_BETWEEN_PANELS + HEADER_SIZE; - // Check that the floater doesn't exceed its parent view limits after reshape - S32 new_height = list_height + LLScrollingPanelList::GAP_BETWEEN_PANELS + HEADER_SIZE; + U32 twinListWidth = 0; - if(new_height > MAX_WINDOW_HEIGHT) + if (new_window_height > MAX_WINDOW_HEIGHT) { - reshape(MIN_WINDOW_WIDTH, MAX_WINDOW_HEIGHT, FALSE); - mNotificationList->reshape(MIN_PANELLIST_WIDTH - SCROLLBAR_SIZE, list_height, TRUE); + twinListWidth = MIN_PANELLIST_WIDTH - SCROLLBAR_SIZE; + new_window_height = MAX_WINDOW_HEIGHT; } else { - reshape(MIN_WINDOW_WIDTH, new_height, FALSE); - mNotificationList->reshape(MIN_PANELLIST_WIDTH, list_height, TRUE); + twinListWidth = MIN_PANELLIST_WIDTH; } - + + reshape(MIN_WINDOW_WIDTH, new_window_height, FALSE); + mTwinListPanel->reshape(twinListWidth, new_panel_height, TRUE); + mNotificationList->reshape(twinListWidth, notif_list_height, TRUE); + mIMRowList->reshape(twinListWidth, im_list_height, TRUE); + + // arrange panel and lists + // move panel + panel_rect.setLeftTopAndSize(1, new_panel_height, twinListWidth, new_panel_height); + mTwinListPanel->setRect(panel_rect); + // move notif list panel + notif_list_rect.setLeftTopAndSize(notif_list_rect.mLeft, new_panel_height, twinListWidth, notif_list_height); + mNotificationList->setRect(notif_list_rect); + // move IM list panel + im_list_rect.setLeftTopAndSize(im_list_rect.mLeft, notif_list_rect.mBottom - LLScrollingPanelList::GAP_BETWEEN_PANELS, twinListWidth, im_list_height); + mIMRowList->setRect(im_list_rect); + mNotificationList->updatePanels(TRUE); + mIMRowList->updatePanels(TRUE); +} + +//--------------------------------------------------------------------------------- +LLSysWellWindow::RowPanel * LLSysWellWindow::findIMRow(const LLUUID& sessionId) +{ + RowPanel * res = NULL; + const LLScrollingPanelList::panel_list_t &list = mIMRowList->getPanelList(); + if (!list.empty()) + { + for (LLScrollingPanelList::panel_list_t::const_iterator iter = list.begin(); iter != list.end(); ++iter) + { + RowPanel *panel = static_cast<RowPanel*> (*iter); + if (panel->mChiclet->getSessionId() == sessionId) + { + res = panel; + break; + } + } + } + return res; +} + +//--------------------------------------------------------------------------------- +LLChiclet* LLSysWellWindow::findIMChiclet(const LLUUID& sessionId) +{ + LLChiclet* res = NULL; + RowPanel* panel = findIMRow(sessionId); + if (panel != NULL) + { + res = panel->mChiclet; + } + + return res; } //--------------------------------------------------------------------------------- +void LLSysWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter, + const std::string& name, const LLUUID& otherParticipantId) +{ + mIMRowList->addPanel(new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId)); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::delIMRow(const LLUUID& sessionId) +{ + RowPanel *panel = findIMRow(sessionId); + if (panel != NULL) + { + mIMRowList->removePanel(panel); + } + // hide chiclet window if there are no items left + setVisible(!isWindowEmpty()); +} +//--------------------------------------------------------------------------------- +bool LLSysWellWindow::isWindowEmpty() +{ + if(mIMRowList->getPanelList().size() == 0 && LLBottomTray::getInstance()->getSysWell()->getCounter() == 0) + { + return true; + } + else + { + return false; + } +} + +//--------------------------------------------------------------------------------- +//virtual +void LLSysWellWindow::sessionAdded(const LLUUID& sessionId, + const std::string& name, const LLUUID& otherParticipantId) +{ + if (findIMRow(sessionId) == NULL) + { + S32 chicletCounter = 0; + LLIMModel::LLIMSession* session = get_if_there(LLIMModel::sSessionsMap, + sessionId, (LLIMModel::LLIMSession*) NULL); + if (session != NULL) + { + chicletCounter = session->mNumUnread; + } + addIMRow(sessionId, chicletCounter, name, otherParticipantId); + reshapeWindow(); + } +} + +//--------------------------------------------------------------------------------- +//virtual +void LLSysWellWindow::sessionRemoved(const LLUUID& sessionId) +{ + delIMRow(sessionId); + reshapeWindow(); + LLBottomTray::getInstance()->getSysWell()->updateUreadIMNotifications(); +} + +//--------------------------------------------------------------------------------- +LLSysWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId, + S32 chicletCounter, const std::string& name, const LLUUID& otherParticipantId) : + LLScrollingPanel(LLPanel::Params()), mParent(parent) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_activeim_row.xml", NULL); + + mChiclet = getChild<LLIMChiclet>("chiclet"); + mChiclet->setCounter(chicletCounter); + mChiclet->setSessionId(sessionId); + mChiclet->setIMSessionName(name); + mChiclet->setOtherParticipantId(otherParticipantId); + + LLTextBox* contactName = getChild<LLTextBox>("contact_name"); + contactName->setValue(name); + + mCloseBtn = getChild<LLButton>("hide_btn"); + mCloseBtn->setCommitCallback(boost::bind(&LLSysWellWindow::RowPanel::onClose, this)); +} + +//--------------------------------------------------------------------------------- +LLSysWellWindow::RowPanel::~RowPanel() +{ +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::RowPanel::onClose() +{ + mParent->mIMRowList->removePanel(this); + gIMMgr->removeSession(mChiclet->getSessionId()); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::RowPanel::onMouseEnter(S32 x, S32 y, MASK mask) +{ + setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemSelected")); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::RowPanel::onMouseLeave(S32 x, S32 y, MASK mask) +{ + setTransparentColor(LLUIColorTable::instance().getColor("SysWellItemUnselected")); +} + +//--------------------------------------------------------------------------------- +// virtual +BOOL LLSysWellWindow::RowPanel::handleMouseDown(S32 x, S32 y, MASK mask) +{ + // Pass the mouse down event to the chiclet (EXT-596). + if (!mChiclet->pointInView(x, y) && !mCloseBtn->getRect().pointInRect(x, y)) // prevent double call of LLIMChiclet::onMouseDown() + mChiclet->onMouseDown(); + + return LLPanel::handleMouseDown(x, y, mask); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::RowPanel::updatePanel(BOOL allow_modify) +{ + S32 parent_width = getParent()->getRect().getWidth(); + S32 panel_height = getRect().getHeight(); + + reshape(parent_width, panel_height, TRUE); +} + +//--------------------------------------------------------------------------------- diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index 7a107af0d1..ef0974b428 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -35,22 +35,27 @@ #include "llsyswellitem.h" -#include "llfloater.h" +#include "lldockablefloater.h" #include "llbutton.h" #include "llscreenchannel.h" #include "llscrollcontainer.h" +#include "llchiclet.h" +#include "llimview.h" #include "boost/shared_ptr.hpp" -class LLSysWellWindow : public LLFloater +class LLSysWellWindow : public LLDockableFloater, LLIMSessionObserver { public: LLSysWellWindow(const LLSD& key); ~LLSysWellWindow(); BOOL postBuild(); + // other interface functions + bool isWindowEmpty(); + // change attributes void setChannel(LLNotificationsUI::LLScreenChannel* channel) {mChannel = channel;} @@ -75,15 +80,46 @@ public: static const S32 MIN_PANELLIST_WIDTH = 318; private: - + class RowPanel; void reshapeWindow(); + RowPanel * findIMRow(const LLUUID& sessionId); + LLChiclet * findIMChiclet(const LLUUID& sessionId); + void addIMRow(const LLUUID& sessionId, S32 chicletCounter, const std::string& name, const LLUUID& otherParticipantId); + void delIMRow(const LLUUID& sessionId); + // LLIMSessionObserver observe triggers + virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); + virtual void sessionRemoved(const LLUUID& session_id); // pointer to a corresponding channel's instance LLNotificationsUI::LLScreenChannel* mChannel; - - LLUIImagePtr mDockTongue; + LLPanel* mTwinListPanel; LLScrollContainer* mScrollContainer; + LLScrollingPanelList* mIMRowList; LLScrollingPanelList* mNotificationList; + +private: + /** + * Scrolling row panel. + */ + class RowPanel: public LLScrollingPanel + { + public: + RowPanel(const LLSysWellWindow* parent, const LLUUID& sessionId, S32 chicletCounter, + const std::string& name, const LLUUID& otherParticipantId); + virtual ~RowPanel(); + /*virtual*/ + void updatePanel(BOOL allow_modify); + void onMouseEnter(S32 x, S32 y, MASK mask); + void onMouseLeave(S32 x, S32 y, MASK mask); + BOOL handleMouseDown(S32 x, S32 y, MASK mask); + private: + void onClose(); + public: + LLIMChiclet* mChiclet; + private: + LLButton* mCloseBtn; + const LLSysWellWindow* mParent; + }; }; #endif // LL_LLSYSWELLWINDOW_H diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp index b31edf1e5d..0bb5a727e0 100644 --- a/indra/newview/llteleporthistorystorage.cpp +++ b/indra/newview/llteleporthistorystorage.cpp @@ -37,8 +37,11 @@ #include "llsd.h" #include "llsdserialize.h" #include "lldir.h" +#include "llteleporthistory.h" +#include "llagent.h" -static LLTeleportHistoryStorage tpstorage; +// Max offset for two global positions to consider them as equal +const F64 MAX_GLOBAL_POS_OFFSET = 5.0f; LLTeleportHistoryPersistentItem::LLTeleportHistoryPersistentItem(const LLSD& val) { @@ -58,15 +61,42 @@ LLSD LLTeleportHistoryPersistentItem::toLLSD() const return val; } +struct LLSortItemsByDate +{ + bool operator()(const LLTeleportHistoryPersistentItem& a, const LLTeleportHistoryPersistentItem& b) + { + return a.mDate < b.mDate; + } +}; + LLTeleportHistoryStorage::LLTeleportHistoryStorage() : mFilename("teleport_history.txt") { + LLTeleportHistory *th = LLTeleportHistory::getInstance(); + if (th) + th->setHistoryChangedCallback(boost::bind(&LLTeleportHistoryStorage::onTeleportHistoryChange, this)); + + load(); } LLTeleportHistoryStorage::~LLTeleportHistoryStorage() { } +void LLTeleportHistoryStorage::onTeleportHistoryChange() +{ + LLTeleportHistory *th = LLTeleportHistory::getInstance(); + if (!th) + return; + + const LLTeleportHistoryItem &item = th->getItems()[th->getCurrentItemIndex()]; + + addItem(item.mTitle, item.mGlobalPos); + save(); + + mHistoryChangedSignal(); +} + void LLTeleportHistoryStorage::purgeItems() { mItems.clear(); @@ -74,12 +104,45 @@ void LLTeleportHistoryStorage::purgeItems() void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos) { - mItems.push_back(LLTeleportHistoryPersistentItem(title, global_pos)); + addItem(title, global_pos, LLDate::now()); +} + + +bool LLTeleportHistoryStorage::compareByTitleAndGlobalPos(const LLTeleportHistoryPersistentItem& a, const LLTeleportHistoryPersistentItem& b) +{ + return a.mTitle == b.mTitle && (a.mGlobalPos - b.mGlobalPos).length() < MAX_GLOBAL_POS_OFFSET; } void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos, const LLDate& date) { - mItems.push_back(LLTeleportHistoryPersistentItem(title, global_pos, date)); + + LLTeleportHistoryPersistentItem item(title, global_pos, date); + + slurl_list_t::iterator item_iter = std::find_if(mItems.begin(), mItems.end(), + boost::bind(&LLTeleportHistoryStorage::compareByTitleAndGlobalPos, this, _1, item)); + + // If there is such item already, remove it, since new item is more recent + if (item_iter != mItems.end()) + { + mItems.erase(item_iter); + } + + mItems.push_back(item); + + // Check whether sorting is needed + if (mItems.size() > 1) + { + item_iter = mItems.end(); + + item_iter--; + item_iter--; + + // If second to last item is more recent than last, then resort items + if (item_iter->mDate > item.mDate) + { + std::sort(mItems.begin(), mItems.end(), LLSortItemsByDate()); + } + } } void LLTeleportHistoryStorage::removeItem(S32 idx) @@ -145,6 +208,8 @@ void LLTeleportHistoryStorage::load() } file.close(); + + std::sort(mItems.begin(), mItems.end(), LLSortItemsByDate()); } void LLTeleportHistoryStorage::dump() const @@ -162,3 +227,30 @@ void LLTeleportHistoryStorage::dump() const } } +boost::signals2::connection LLTeleportHistoryStorage::setHistoryChangedCallback(history_callback_t cb) +{ + return mHistoryChangedSignal.connect(cb); +} + +void LLTeleportHistoryStorage::goToItem(S32 idx) + +{ + // Validate specified index. + if (idx < 0 || idx >= (S32)mItems.size()) + { + llwarns << "Invalid teleport history index (" << idx << ") specified" << llendl; + dump(); + return; + } + + if (idx == (S32)mItems.size() - 1) + { + llwarns << "Will not teleport to the same location." << llendl; + dump(); + return; + } + + // Attempt to teleport to the requested item. + gAgent.teleportViaLocation(mItems[idx].mGlobalPos); +} + diff --git a/indra/newview/llteleporthistorystorage.h b/indra/newview/llteleporthistorystorage.h index fa836c0326..f67c4e2fb9 100644 --- a/indra/newview/llteleporthistorystorage.h +++ b/indra/newview/llteleporthistorystorage.h @@ -78,7 +78,10 @@ class LLTeleportHistoryStorage: public LLSingleton<LLTeleportHistoryStorage> public: - typedef std::vector<LLTeleportHistoryPersistentItem> item_list_list_t; + typedef std::vector<LLTeleportHistoryPersistentItem> slurl_list_t; + + typedef boost::function<void()> history_callback_t; + typedef boost::signals2::signal<void()> history_signal_t; LLTeleportHistoryStorage(); ~LLTeleportHistoryStorage(); @@ -86,7 +89,7 @@ public: /** * @return history items. */ - const item_list_list_t& getItems() const { return mItems; } + const slurl_list_t& getItems() const { return mItems; } void purgeItems(); void addItem(const std::string title, const LLVector3d& global_pos); @@ -99,10 +102,34 @@ public: void dump() const; + /** + * Set a callback to be called upon history changes. + * + * Multiple callbacks can be set. + */ + boost::signals2::connection setHistoryChangedCallback(history_callback_t cb); + + /** + * Go to specific item in the history. + * + * The item is specified by its index (starting from 0). + */ + void goToItem(S32 idx); + private: - item_list_list_t mItems; - std::string mFilename; + void onTeleportHistoryChange(); + bool compareByTitleAndGlobalPos(const LLTeleportHistoryPersistentItem& a, const LLTeleportHistoryPersistentItem& b); + + slurl_list_t mItems; + std::string mFilename; + + /** + * Signal emitted when the history gets changed. + * + * Invokes callbacks set with setHistoryChangedCallback(). + */ + history_signal_t mHistoryChangedSignal; }; #endif //LL_LLTELEPORTHISTORYSTORAGE_H diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 969f3fd1cb..05e63a60c5 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -70,12 +70,16 @@ public: bool enable_hide_btn; bool is_modal; bool is_tip; + bool force_show; + bool force_store; Params() : can_fade(true), can_be_stored(true), is_modal(false), is_tip(false), enable_hide_btn(true), + force_show(false), + force_store(false), panel(NULL), timer_period(gSavedSettings.getS32("NotificationToastTime")) diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index 6f26b4077c..6f373a74bd 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -40,7 +40,7 @@ #include "lliconctrl.h" #include "llnotify.h" #include "lltextbox.h" -#include "lltexteditor.h" + #include "lluiconstants.h" #include "llui.h" #include "llviewercontrol.h" @@ -53,6 +53,8 @@ #include "llfloaterinventory.h" #include "llinventorytype.h" +const S32 LLToastGroupNotifyPanel::DEFAULT_MESSAGE_MAX_LINE_COUNT = 4; + LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification) : LLToastPanel(notification), mInventoryOffer(NULL) @@ -65,8 +67,6 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl; } - static const LLUIColor textColor = LLUIColorTable::instance().getColor("GroupNotifyTextColor"); - //group icon LLIconCtrl* pGroupIcon = getChild<LLIconCtrl>("group_icon", TRUE); pGroupIcon->setValue(groupData.mInsigniaID); @@ -78,23 +78,16 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification LLTextBox* pTitleText = getChild<LLTextBox>("title"); pTitleText->setValue(from.str()); - //message body + //message subject const std::string& subject = payload["subject"].asString(); + //message body const std::string& message = payload["message"].asString(); - LLTextEditor* pMessageText = getChild<LLTextEditor>("message"); - pMessageText->setValue(""); - pMessageText->setEnabled(FALSE); - LLStyle::Params date_style; - date_style.color = textColor; - date_style.font.name = "SANSSERIF"; - - LLStyle::Params header_style_params; - header_style_params.color = textColor; - header_style_params.font = LLFontGL::getFontSansSerifBig(); - pMessageText->appendStyledText(subject + "\n",false,false,header_style_params); + LLTextBox* pSubjectText = getChild<LLTextBox>("subject"); + pSubjectText->setValue(subject); + LLTextBox* pDateTimeText = getChild<LLTextBox>("datetime"); std::string timeStr = "["+LLTrans::getString("UTCTimeWeek")+"],[" +LLTrans::getString("UTCTimeDay")+"] [" +LLTrans::getString("UTCTimeMth")+"] [" @@ -108,25 +101,38 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification LLSD substitution; substitution["datetime"] = (S32) notice_date.secondsSinceEpoch(); LLStringUtil::format(timeStr, substitution); - LLStyle::Params date_style_params; - date_style_params.color = textColor; - date_style_params.font = LLFontGL::getFontMonospace(); - pMessageText->appendStyledText(timeStr, false, false, date_style); - pMessageText->appendColoredText(std::string("\n\n") + message, false, - false, textColor); + pDateTimeText->setValue(timeStr); + + LLTextBox* pMessageText = getChild<LLTextBox>("message"); + + //If message is empty let it be invisible and not take place at the panel + if(message.size() != 0) + { + pMessageText->setVisible(TRUE); + pMessageText->setValue(message); + } + else + { + pMessageText->setVisible(FALSE); + } //attachment BOOL hasInventory = payload["inventory_offer"].isDefined(); + + //attachment text LLTextBox * pAttachLink = getChild<LLTextBox>("attachment"); + //attachment icon + LLIconCtrl* pAttachIcon = getChild<LLIconCtrl>("attachment_icon", TRUE); + + //If attachment is empty let it be invisible and not take place at the panel pAttachLink->setVisible(hasInventory); + pAttachIcon->setVisible(hasInventory); if (hasInventory) { pAttachLink->setValue(payload["inventory_name"]); mInventoryOffer = new LLOfferInfo(payload["inventory_offer"]); childSetActionTextbox("attachment", boost::bind( &LLToastGroupNotifyPanel::onClickAttachment, this)); - //attachment icon - LLIconCtrl* pAttachIcon = getChild<LLIconCtrl>("attachment_icon", TRUE); LLUIImagePtr attachIconImg = get_item_icon(mInventoryOffer->mType, LLInventoryType::IT_TEXTURE, 0, FALSE); @@ -137,8 +143,15 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification LLButton* pOkBtn = getChild<LLButton>("btn_ok"); pOkBtn->setClickedCallback((boost::bind(&LLToastGroupNotifyPanel::onClickOk, this))); setDefaultBtn(pOkBtn); -} + S32 maxLinesCount; + std::istringstream ss( getString("message_max_lines_count") ); + if (!(ss >> maxLinesCount)) + { + maxLinesCount = DEFAULT_MESSAGE_MAX_LINE_COUNT; + } + snapToMessageHeight(pMessageText, maxLinesCount); +} // virtual LLToastGroupNotifyPanel::~LLToastGroupNotifyPanel() diff --git a/indra/newview/lltoastgroupnotifypanel.h b/indra/newview/lltoastgroupnotifypanel.h index ba98531251..e3d0ef45cb 100644 --- a/indra/newview/lltoastgroupnotifypanel.h +++ b/indra/newview/lltoastgroupnotifypanel.h @@ -68,6 +68,8 @@ protected: private: static bool isAttachmentOpenable(LLAssetType::EType); + static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT; + LLButton* mSaveInventoryBtn; LLUUID mGroupID; diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index e41181c9e1..913e46e05e 100644 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -34,9 +34,7 @@ #include "lltoastimpanel.h" #include "llimpanel.h" -const S32 LLToastIMPanel::MAX_MESSAGE_HEIGHT = 50; -const S32 LLToastIMPanel::CAPTION_HEIGHT = 30; -const S32 LLToastIMPanel::TOP_PAD = 5; +const S32 LLToastIMPanel::DEFAULT_MESSAGE_MAX_LINE_COUNT = 6; //-------------------------------------------------------------------------- LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notification), @@ -60,7 +58,13 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif mReplyBtn->setClickedCallback(boost::bind(&LLToastIMPanel::onClickReplyBtn, this)); - snapToMessageHeight(); + S32 maxLinesCount; + std::istringstream ss( getString("message_max_lines_count") ); + if (!(ss >> maxLinesCount)) + { + maxLinesCount = DEFAULT_MESSAGE_MAX_LINE_COUNT; + } + snapToMessageHeight(mMessage, maxLinesCount); } //-------------------------------------------------------------------------- @@ -69,22 +73,6 @@ LLToastIMPanel::~LLToastIMPanel() } //-------------------------------------------------------------------------- -void LLToastIMPanel::snapToMessageHeight() -{ - S32 required_text_height = mMessage->getTextPixelHeight(); - S32 text_height = llmin(required_text_height, MAX_MESSAGE_HEIGHT); - LLRect text_rect = mMessage->getRect(); - LLRect btn_rect = mReplyBtn->getRect(); - - - mMessage->reshape( text_rect.getWidth(), text_height, TRUE); - mMessage->setValue(mMessage->getText()); - - S32 panel_height = CAPTION_HEIGHT + text_height + btn_rect.getHeight() + TOP_PAD*5; - reshape( getRect().getWidth(), panel_height, TRUE); -} - -//-------------------------------------------------------------------------- void LLToastIMPanel::onClickReplyBtn() { LLIMFloater::toggle(mSessionID); diff --git a/indra/newview/lltoastimpanel.h b/indra/newview/lltoastimpanel.h index 7f5d6eca1d..11f489c12f 100644 --- a/indra/newview/lltoastimpanel.h +++ b/indra/newview/lltoastimpanel.h @@ -59,12 +59,9 @@ public: virtual ~LLToastIMPanel(); private: - static const S32 MAX_MESSAGE_HEIGHT; - static const S32 CAPTION_HEIGHT; - static const S32 TOP_PAD; + static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT; void onClickReplyBtn(); - void snapToMessageHeight(); LLUUID mSessionID; LLAvatarIconCtrl* mAvatar; diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index 28052a33be..e884d89ce4 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -49,5 +49,36 @@ std::string LLToastPanel::getTitle() return mNotification->getMessage(); } +//snap to the message height if it is visible +void LLToastPanel::snapToMessageHeight(LLTextBox* message, S32 maxLineCount) +{ + //Add message height if it is visible + if (message->getVisible()) + { + S32 heightDelta = 0; + S32 maxTextHeight = (S32)(message->getFont()->getLineHeight() * maxLineCount); + + LLRect messageRect = message->getRect(); + S32 oldTextHeight = messageRect.getHeight(); + + //Reshape the toast to give the message max height. + //This needed to calculate lines count according to specified text + heightDelta = maxTextHeight - oldTextHeight; + reshape( getRect().getWidth(), getRect().getHeight() + heightDelta); + message->setValue(message->getText()); + + //Knowing the height is set to max allowed, getTextPixelHeight returns needed text height + //Perhaps we need to pass maxLineCount as parameter to getTextPixelHeight to avoid previous reshape. + S32 requiredTextHeight = message->getTextPixelHeight(); + S32 newTextHeight = llmin(requiredTextHeight, maxTextHeight); + //Calculate last delta height deducting previous heightDelta + heightDelta = newTextHeight - oldTextHeight - heightDelta; + + //reshape the panel with new height + reshape( getRect().getWidth(), getRect().getHeight() + heightDelta); + message->setValue(message->getText()); + } + +} diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index 2258eca273..bc9888f4b4 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -34,6 +34,7 @@ #define LL_LLTOASTPANEL_H #include "llpanel.h" +#include "lltextbox.h" #include "llnotifications.h" #include <string> @@ -53,6 +54,7 @@ public: virtual const LLUUID& getID() { return mNotification->id();} protected: LLNotificationPtr mNotification; + void snapToMessageHeight(LLTextBox* message, S32 maxLineCount); }; #endif /* LL_TOASTPANEL_H */ diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp index 5478e0005a..c7c9f07504 100644 --- a/indra/newview/lltoolbar.cpp +++ b/indra/newview/lltoolbar.cpp @@ -60,6 +60,7 @@ #include "llui.h" #include "llviewermenu.h" #include "llfirstuse.h" +#include "llpanelblockedlist.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llscrolllistcell.h" @@ -69,7 +70,6 @@ #include "lltoolgrab.h" #include "llcombobox.h" #include "llfloaterchat.h" -#include "llfloatermute.h" #include "llimpanel.h" #include "lllayoutstack.h" @@ -250,41 +250,6 @@ void LLToolBar::refresh() BOOL mouselook = gAgent.cameraMouselook(); setVisible(show && !mouselook); - BOOL sitting = FALSE; - if (gAgent.getAvatarObject()) - { - sitting = gAgent.getAvatarObject()->isSitting(); - } - - if (!gAgent.canFly()) - { - gSavedSettings.setBOOL("FlyBtnEnabled", gAgent.getFlying() ? true : false); - gSavedSettings.setBOOL("FlyBtnState", false); - } - else - { - gSavedSettings.setBOOL("FlyBtnEnabled", sitting ? false : true); - } - - // Check to see if we're in build mode - bool build_enabled = LLToolMgr::getInstance()->canEdit(); - if (build_enabled) - { - gSavedSettings.setBOOL("BuildBtnEnabled", true); - bool build_mode = LLToolMgr::getInstance()->inEdit(); - // HACK: Not in mouselook and not just clicking on a scripted object - if (gAgent.cameraMouselook() || LLToolGrab::getInstance()->getHideBuildHighlight()) - { - build_mode = FALSE; - } - gSavedSettings.setBOOL("BuildBtnState", build_mode); - } - else - { - gSavedSettings.setBOOL("BuildBtnEnabled", false); - gSavedSettings.setBOOL("BuildBtnState", false); - } - if (isInVisibleChain()) { updateCommunicateList(); @@ -332,11 +297,8 @@ void LLToolBar::updateCommunicateList() communicate_button->addSeparator(ADD_TOP); communicate_button->add(getString("Redock Windows"), LLSD("redock"), ADD_TOP); communicate_button->addSeparator(ADD_TOP); - LLFloaterMute* mute_instance = LLFloaterReg::getTypedInstance<LLFloaterMute>("mute"); - if(mute_instance) - { - communicate_button->add(mute_instance->getShortTitle(), LLSD("mute list"), ADD_TOP); - } + communicate_button->add(getString("Blocked List"), LLSD("mute list"), ADD_TOP); + std::set<LLHandle<LLFloater> >::const_iterator floater_handle_it; if (gIMMgr->getIMFloaterHandles().size() > 0) @@ -414,7 +376,7 @@ void LLToolBar::onClickCommunicate(LLUICtrl* ctrl, const LLSD& user_data) } else if (selected_option.asString() == "mute list") { - LLFloaterReg::showInstance("mute"); + LLPanelBlockedList::showPanelAndSelect(LLUUID::null); } else if (selected_option.isUndefined()) // user just clicked the communicate button, treat as toggle { diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index d52e0b4b80..ded83debad 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -317,7 +317,6 @@ bool LLToolMgr::inBuildMode() // cameraMouselook() actually starts returning true. Also, appearance edit // sets build mode to true, so let's exclude that. bool b=(inEdit() - && gSavedSettings.getBOOL("BuildBtnState") && !gAgent.cameraMouselook() && mCurrentToolset != gFaceEditToolset); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index b85dc30e72..c8f2e03903 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -78,7 +78,6 @@ #include "llfloaterlandholdings.h" #include "llfloatermap.h" #include "llfloatermemleak.h" -#include "llfloatermute.h" #include "llfloaternamedesc.h" #include "llfloaternotificationsconsole.h" #include "llfloateropenobject.h" @@ -110,6 +109,7 @@ #include "llmediaremotectrl.h" #include "llmoveview.h" #include "llnearbychat.h" +#include "llpanelblockedlist.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" #include "llpreviewnotecard.h" @@ -177,8 +177,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>); - LLFloaterReg::add("mute", "floater_mute.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMute>); - LLFloaterReg::add("mute_object", "floater_mute_object.xml", &LLFloaterMute::buildFloaterMuteObjectUI); + LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>); LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>); LLFloaterReg::add("syswell_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLSysWellWindow>); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 95ab40f9bf..ec20af46a1 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -120,6 +120,41 @@ LLViewerInventoryItem::~LLViewerInventoryItem() { } +BOOL LLViewerInventoryItem::extractSortFieldAndDisplayName(S32* sortField, std::string* displayName) const +{ + using std::string; + using std::stringstream; + + const char separator = getSeparator(); + const string::size_type separatorPos = mName.find(separator, 0); + + BOOL result = FALSE; + + if (separatorPos < string::npos) + { + if (sortField) + { + /* + * The conversion from string to S32 is made this way instead of old plain + * atoi() to ensure portability. If on some other platform S32 will not be + * defined to be signed int, this conversion will still work because of + * operators overloading, but atoi() may fail. + */ + stringstream ss(mName.substr(0, separatorPos)); + ss >> *sortField; + } + + if (displayName) + { + *displayName = mName.substr(separatorPos + 1, string::npos); + } + + result = TRUE; + } + + return result; +} + void LLViewerInventoryItem::copyViewerItem(const LLViewerInventoryItem* other) { LLInventoryItem::copyItem(other); @@ -1102,7 +1137,70 @@ const std::string& LLViewerInventoryItem::getName() const return linked_category->getName(); } - return LLInventoryItem::getName(); + return getDisplayName(); +} + +const std::string& LLViewerInventoryItem::getDisplayName() const +{ + std::string result; + BOOL hasSortField = extractSortFieldAndDisplayName(0, &result); + + return mDisplayName = hasSortField ? result : LLInventoryItem::getName(); +} + +S32 LLViewerInventoryItem::getSortField() const +{ + S32 result; + BOOL hasSortField = extractSortFieldAndDisplayName(&result, 0); + + return hasSortField ? result : -1; +} + +void LLViewerInventoryItem::setSortField(S32 sortField) +{ + using std::string; + + std::stringstream ss; + ss << sortField; + + string newSortField = ss.str(); + + const char separator = getSeparator(); + const string::size_type separatorPos = mName.find(separator, 0); + + if (separatorPos < string::npos) + { + // the name of the LLViewerInventoryItem already consists of sort field and display name. + mName = newSortField + separator + mName.substr(separatorPos + 1, string::npos); + } + else + { + // there is no sort field in the name of LLViewerInventoryItem, we should add it + mName = newSortField + separator + mName; + } +} + +void LLViewerInventoryItem::rename(const std::string& n) +{ + using std::string; + + string new_name(n); + LLStringUtil::replaceNonstandardASCII(new_name, ' '); + LLStringUtil::replaceChar(new_name, '|', ' '); + LLStringUtil::trim(new_name); + LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); + + const char separator = getSeparator(); + const string::size_type separatorPos = mName.find(separator, 0); + + if (separatorPos < string::npos) + { + mName.replace(separatorPos + 1, string::npos, new_name); + } + else + { + mName = new_name; + } } const LLPermissions& LLViewerInventoryItem::getPermissions() const diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 0bfb37f7e8..c4ff30bbfc 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -55,11 +55,18 @@ public: protected: ~LLViewerInventoryItem( void ); // ref counted + BOOL extractSortFieldAndDisplayName(S32* sortField, std::string* displayName) const; + static char getSeparator() { return '@'; } + mutable std::string mDisplayName; public: virtual LLAssetType::EType getType() const; virtual const LLUUID& getAssetUUID() const; virtual const std::string& getName() const; + virtual const std::string& getDisplayName() const; + virtual S32 getSortField() const; + virtual void setSortField(S32 sortField); + virtual void rename(const std::string& new_name); virtual const LLPermissions& getPermissions() const; virtual const LLUUID& getCreatorUUID() const; virtual const std::string& getDescription() const; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 8a5928f4e9..5536951ce6 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -113,7 +113,6 @@ #include "llfloaterland.h" #include "llfloaterlandholdings.h" #include "llfloatermap.h" -#include "llfloatermute.h" #include "llfloateropenobject.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" @@ -147,6 +146,7 @@ #include "llfloaterinventory.h" #include "llkeyboard.h" #include "llpanellogin.h" +#include "llpanelblockedlist.h" #include "llmenucommands.h" #include "llmenugl.h" #include "llmimetypes.h" @@ -2896,7 +2896,7 @@ class LLObjectMute : public view_listener_t else { LLMuteList::getInstance()->add(mute); - LLFloaterReg::showInstance("mute"); + LLPanelBlockedList::showPanelAndSelect(mute.mID); } return true; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 111cdf7c12..2a2b095833 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1,4 +1,3 @@ - /** * @file llviewermessage.cpp * @brief Dumping ground for viewer-side message system callbacks. @@ -83,7 +82,6 @@ #include "llfloaterregioninfo.h" #include "llfloaterlandholdings.h" #include "llurldispatcher.h" -#include "llfloatermute.h" #include "llfloaterpostcard.h" #include "llfloaterpreference.h" #include "llfollowcam.h" @@ -138,6 +136,9 @@ #include "llkeythrottle.h" #include "llgroupactions.h" #include "llagentui.h" +#include "llsidetray.h" +#include "llpanelblockedlist.h" +#include "llpanelplaceinfo.h" #include <boost/tokenizer.hpp> #include <boost/algorithm/string/split.hpp> @@ -1000,9 +1001,7 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, LLMute mute(blocked_id, from_name, type); if (LLMuteList::getInstance()->add(mute)) { - LLFloaterReg::showInstance("mute"); - LLFloaterMute* mute_instance = LLFloaterReg::getTypedInstance<LLFloaterMute>("mute"); - if(mute_instance) mute_instance->selectMute(blocked_id); + LLPanelBlockedList::showPanelAndSelect(blocked_id); } // purge the message queue of any previously queued inventory offers from the same source. @@ -1472,6 +1471,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket); EInstantMessage dialog = (EInstantMessage)d; + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(name); + if (name.empty()) + { + name = LLTrans::getString("Unnamed"); + } + BOOL is_busy = gAgent.getBusy(); BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat); BOOL is_linden = LLMuteList::getInstance()->isLinden(name); @@ -2397,6 +2403,9 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // Look for IRC-style emotes if (ircstyle) { + // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656 + chat.mChatStyle = CHAT_STYLE_IRC; + // Do nothing, ircstyle is fixed above for chat bubbles } else @@ -5565,6 +5574,12 @@ void process_covenant_reply(LLMessageSystem* msg, void**) LLPanelLandCovenant::updateEstateName(estate_name); LLFloaterBuyLand::updateEstateName(estate_name); + LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info"); + if (panel) + { + panel->updateEstateName(estate_name); + } + // standard message, not from system std::string last_modified; if (covenant_timestamp == 0) @@ -5622,6 +5637,7 @@ void process_covenant_reply(LLMessageSystem* msg, void**) LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id); LLPanelLandCovenant::updateCovenantText(covenant_text); LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id); + panel->updateCovenantText(covenant_text); } } @@ -5642,6 +5658,12 @@ void callbackCacheEstateOwnerName(const LLUUID& id, LLPanelEstateCovenant::updateEstateOwnerName(name); LLPanelLandCovenant::updateEstateOwnerName(name); LLFloaterBuyLand::updateEstateOwnerName(name); + + LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info"); + if (panel) + { + panel->updateEstateOwnerName(name); + } } void onCovenantLoadComplete(LLVFS *vfs, @@ -5709,6 +5731,12 @@ void onCovenantLoadComplete(LLVFS *vfs, LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); LLPanelLandCovenant::updateCovenantText(covenant_text); LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); + + LLPanelPlaceInfo* panel = dynamic_cast<LLPanelPlaceInfo*>(LLSideTray::getInstance()->showPanel("panel_place_info", LLSD())); + if (panel) + { + panel->updateCovenantText(covenant_text); + } } diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index de01e79803..5bb0c9a120 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -814,38 +814,18 @@ BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLViewerTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; - - // *TODO: Add right click menus for SLURLs -// if(! handled) -// { -// const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); -// if( cur_segment ) -// { -// if(cur_segment->getStyle()->isLink()) -// { -// handled = TRUE; -// mHTML = cur_segment->getStyle()->getLinkHREF(); -// } -// } -// } -// LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); -// if(handled && menu && mParseHTML && mHTML.length() > 0) -// { -// menu->setVisible(TRUE); -// menu->arrange(); -// menu->updateParent(LLMenuGL::sMenuContainer); -// LLMenuGL::showPopup(this, menu, x, y); -// mHTML = ""; -// } -// else -// { -// if(menu && menu->getVisible()) -// { -// menu->setVisible(FALSE); -// } -// } - return handled; + // pop up a context menu for any Url under the cursor + if (handleRightMouseDownOverUrl(this, x, y)) + { + return TRUE; + } + + if (childrenHandleRightMouseDown(x, y, mask) != NULL) + { + return TRUE; + } + + return FALSE; } BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) @@ -1087,6 +1067,7 @@ llwchar LLViewerTextEditor::pasteEmbeddedItem(llwchar ext_char) void LLViewerTextEditor::onValueChange(S32 start, S32 end) { updateSegments(); + updateLinkSegments(); findEmbeddedItemSegments(start, end); } diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index 9567bfbc48..2dfea4a589 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -35,7 +35,6 @@ #include "lltexteditor.h" - // // Classes // @@ -137,9 +136,6 @@ private: LLPointer<class LLEmbeddedNotecardOpener> mInventoryCallback; - // *TODO: Add right click menus for SLURLs - //LLViewHandle mPopupMenuHandle; - // // Inner classes // diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 461f7fc1c7..241c6fd511 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1596,8 +1596,6 @@ void LLViewerWindow::initWorldUI() gFloaterView->setRect(floater_view_rect); gNotifyBoxView->setRect(notify_view_rect); - // *Note: this is where gFloaterMute used to be initialized. - LLWorldMapView::initClass(); // Force gFloaterWorldMap to initialize @@ -1636,6 +1634,11 @@ void LLViewerWindow::initWorldUI() navbar->showFavoritesPanel(FALSE); } + if (!gSavedSettings.getBOOL("ShowCameraAndMoveControls")) + { + LLBottomTray::getInstance()->showCameraAndMoveControls(FALSE); + } + getRootView()->addChild(gStatusBar); getRootView()->addChild(navbar); @@ -1668,6 +1671,9 @@ void LLViewerWindow::initWorldUI() // put behind everything else in the UI getRootView()->addChildInBack(gHUDView); } + + // this allows not to see UI elements created while UI initializing after Alt+Tab was pressed during login. EXT-744. + moveProgressViewToFront(); } // Destroy the UI @@ -2870,7 +2876,7 @@ void LLViewerWindow::updateLayout() { gFloaterTools->setVisible(FALSE); } - gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible()); + //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible()); } // Always update console @@ -4417,8 +4423,7 @@ void LLViewerWindow::moveProgressViewToFront() { if( mProgressView && mRootView ) { - mRootView->removeChild( mProgressView ); - mRootView->addChild( mProgressView ); + mRootView->sendChildToFront(mProgressView); } } diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 300a5db7c3..3204c2d264 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -67,6 +67,7 @@ void LLWeb::initClass() LLAlertDialog::setURLLoader(&sAlertURLLoader); } + // static void LLWeb::loadURL(const std::string& url) { @@ -76,12 +77,19 @@ void LLWeb::loadURL(const std::string& url) } else { - LLFloaterReg::showInstance("media_browser",url); + loadURLInternal(url); } } // static +void LLWeb::loadURLInternal(const std::string &url) +{ + LLFloaterReg::showInstance("media_browser", url); +} + + +// static void LLWeb::loadURLExternal(const std::string& url) { std::string escaped_url = escapeURL(url); diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 71cc236621..96a53db2ca 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -36,23 +36,29 @@ #include <string> +/// +/// The LLWeb class provides various static methods to display the +/// contents of a Url in a web browser. Variations are provided to +/// let you specifically use the Second Life internal browser, the +/// operating system's default browser, or to respect the user's +/// setting for which of these two they prefer to use with SL. +/// class LLWeb { public: static void initClass(); - // Loads unescaped url in either internal web browser or external - // browser, depending on user settings. + /// Load the given url in the user's preferred web browser static void loadURL(const std::string& url); - + /// Load the given url in the user's preferred web browser static void loadURL(const char* url) { loadURL( ll_safe_string(url) ); } - - // Loads unescaped url in external browser. + /// Load the given url in the Second Life internal web browser + static void loadURLInternal(const std::string &url); + /// Load the given url in the operating system's web browser static void loadURLExternal(const std::string& url); - // Returns escaped (eg, " " to "%20") url + // Returns escaped url (eg, " " to "%20") - used by all loadURL methods static std::string escapeURL(const std::string& url); - }; #endif diff --git a/indra/newview/skins/default/textures/places_rating_adult.tga b/indra/newview/skins/default/textures/places_rating_adult.tga Binary files differnew file mode 100644 index 0000000000..c344fb1e78 --- /dev/null +++ b/indra/newview/skins/default/textures/places_rating_adult.tga diff --git a/indra/newview/skins/default/textures/places_rating_mature.tga b/indra/newview/skins/default/textures/places_rating_mature.tga Binary files differnew file mode 100644 index 0000000000..61c879bc92 --- /dev/null +++ b/indra/newview/skins/default/textures/places_rating_mature.tga diff --git a/indra/newview/skins/default/textures/places_rating_pg.tga b/indra/newview/skins/default/textures/places_rating_pg.tga Binary files differnew file mode 100644 index 0000000000..7805dbce60 --- /dev/null +++ b/indra/newview/skins/default/textures/places_rating_pg.tga diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 0bd5f114ed..e32ea0944e 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -93,6 +93,7 @@ <texture name="Info_Press" file_name="navbar/Info_Press.png" preload="false"/> <texture name="ListItem_Select" file_name="widgets/ListItem_Select.png" preload="true" /> + <texture name="ListItem_Over" file_name="widgets/ListItem_Over.png" preload="true" /> <texture name="menu_separator" file_name="navbar/FileMenu_Divider.png" scale.left="4" scale.top="166" scale.right="0" scale.bottom="0" /> diff --git a/indra/newview/skins/default/xui/en/floater_activeim.xml b/indra/newview/skins/default/xui/en/floater_activeim.xml index 38c6d44fdf..0af4e1db54 100644 --- a/indra/newview/skins/default/xui/en/floater_activeim.xml +++ b/indra/newview/skins/default/xui/en/floater_activeim.xml @@ -5,7 +5,7 @@ top="26" left="0" height="22" - width="350" + width="320" follows="right|bottom" background_visible="true" can_close="true" @@ -18,13 +18,14 @@ layout="topleft" top="20" left="1" - width="349" + width="320" height="2" name="panel_list_container"> <scrolling_panel_list follows="left|right" layout="topleft" + left="1" name="chiclet_row_panel_list" - width="335"/> + width="318"/> </scroll_container> </floater>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/floater_media_browser.xml b/indra/newview/skins/default/xui/en/floater_media_browser.xml index afc72a78a9..28b8139bfd 100644 --- a/indra/newview/skins/default/xui/en/floater_media_browser.xml +++ b/indra/newview/skins/default/xui/en/floater_media_browser.xml @@ -7,6 +7,7 @@ min_width="467" name="floater_about" save_rect="true" + single_instance="true" title="Media Browser" width="820"> <floater.string diff --git a/indra/newview/skins/default/xui/en/floater_preview_gesture.xml b/indra/newview/skins/default/xui/en/floater_preview_gesture.xml index 90711e3acc..0f6504c875 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_gesture.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_gesture.xml @@ -76,7 +76,7 @@ height="40" layout="topleft" left_delta="84" - name="desc" + name="desc2" top_delta="-4" width="180" /> @@ -116,17 +116,17 @@ <panel class="floater_snapshot_capture" filename="floater_snapshot_Info.xml" - name="snapshot_capture_tab"/> + name="snapshot_capture_panel"/> </accordion_tab> <accordion_tab min_height="100" title="Permissions" - name="snapshot_capture_tab" + name="snapshot_capture_tab2" can_resize="false"> <panel class="floater_snapshot_capture" filename="floater_snapshot_Permissions.xml" - name="snapshot_capture_tab"/> + name="snapshot_capture_panel2"/> </accordion_tab> </accordion> <!--check_box @@ -164,7 +164,7 @@ label="Cancel (not working)" layout="topleft" left_pad="5" - name="save_btn" + name="cancel_btn" top_delta="0" width="80" /> diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml index fcbc27a5f9..0da1e42986 100644 --- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml +++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <floater - height="590" + height="600" layout="topleft" name="floater_report_abuse" title="Report Abuse" - width="390"> + width="305"> <floater.string name="Screenshot"> Screenshot @@ -15,27 +15,28 @@ follows="left|top" height="114" layout="topleft" - left="238" + left="10" name="screenshot" - top="36" + top="25" width="134" /> <check_box height="16" label="Include screenshot" layout="topleft" - left="13" + left_pad="10" name="screen_check" - top="134" + top="110" width="116" /> <text type="string" length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" - left_delta="3" + left="10" name="reporter_title" - top_delta="-102" + top_pad="12" width="50"> Reporter: </text> @@ -48,7 +49,7 @@ left_pad="12" name="reporter_field" top_delta="0" - width="150"> + width="193"> Loremipsum Dolorsitamut </text> <text @@ -56,10 +57,11 @@ length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" - left="16" + left="10" name="sim_title" - top="48" + top_pad="5" width="60"> Region: </text> @@ -72,7 +74,7 @@ left_pad="2" name="sim_field" top_delta="0" - width="120"> + width="193"> Region Name </text> <text @@ -80,10 +82,11 @@ length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" - left="16" + left="10" name="pos_title" - top="64" + top_pad="5" width="50"> Position: </text> @@ -96,18 +99,18 @@ left_pad="12" name="pos_field" top_delta="0" - width="120"> + width="193"> {128.1, 128.1, 15.4} </text> - <text + <text type="string" length="1" follows="left|top" height="16" layout="topleft" - left="16" + left="10" name="select_object_label" - top="82" + top_pad="5" width="220"> Click the button then the object: </text> @@ -118,15 +121,16 @@ name="pick_btn" picture_style="true" tool_tip="Object Picker - Identify an object as the subject of this report" - top_delta="14" + top_pad="0" width="32" /> <text type="string" length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" - left_pad="5" + left="48" name="object_name_label" top_delta="0" width="60"> @@ -141,7 +145,7 @@ left_pad="6" name="object_name" top_delta="0" - width="109"> + width="157"> Consetetur Sadipscing </text> <text @@ -149,10 +153,11 @@ length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" - left="53" + left="48" name="owner_name_label" - top="112" + top_pad="5" width="60"> Owner: </text> @@ -165,17 +170,17 @@ left_pad="6" name="owner_name" top_delta="0" - width="109"> + width="157"> Hendrerit Vulputate - </text> + </text> <combo_box height="20" layout="topleft" - left="16" + left="10" name="category_combo" tool_tip="Category -- select the category that best describes this report" - top="156" - width="356"> + top_pad="10" + width="265"> <combo_box.item label="Select category" name="Select_category" @@ -338,156 +343,161 @@ length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" left_delta="0" name="abuser_name_title" - top_pad="10" - width="180"> + top_pad="12" + width="265"> Abuser name: </text> <line_editor border_style="line" border_thickness="1" follows="left|top" - height="16" + height="20" layout="topleft" left_delta="0" max_length="32" name="abuser_name_edit" top_pad="2" - width="180" /> + width="170" /> <button height="20" - label="Choose Resident" + font="SansSerifSmall" + label="Choose" layout="topleft" - left_pad="10" + left_pad="5" name="select_abuser" tool_tip="Select the name of the abuser from a list" - top_delta="-2" - width="160" /> + top_delta="0" + width="90" /> <check_box - height="16" + height="20" label="Don't know abuser's name" layout="topleft" - left="13" + left="10" name="omit_abuser_name" tool_tip="Check this if you are unable to provide the abuser's name" - top="224" + top_pad="2" visible="false" - width="116" /> + width="250" /> <text type="string" length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" left_delta="3" name="abuser_name_title2" - top_pad="8" - width="180"> + top_pad="10" + width="265"> Location of Abuse: </text> <line_editor border_style="line" border_thickness="1" follows="left|top" - height="16" + height="20" layout="topleft" - left_delta="0" + left="10" max_length="256" name="abuse_location_edit" top_pad="2" - width="356" /> + width="265" /> <text type="string" length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" left_delta="0" name="sum_title" - top_pad="8" - width="180"> + top_pad="10" + width="265"> Summary: </text> <line_editor border_style="line" border_thickness="1" follows="left|top" - height="16" + height="20" layout="topleft" left_delta="0" max_length="64" name="summary_edit" top_pad="2" - width="356" /> + width="265" /> <text type="string" length="1" follows="left|top" height="16" + font.style="BOLD" layout="topleft" left_delta="0" name="dscr_title" - top_pad="8" - width="180"> + top_pad="10" + width="50"> Details: </text> <text type="string" length="1" follows="left|top" - height="48" + height="16" layout="topleft" - left_delta="54" + left_pad="5" name="bug_aviso" top_delta="0" - width="308"> - Please be specific about the date, location, nature of -abuse, relevant chat/IM text, and select the object -if possible. + width="200"> + Please be as specific as possible. </text> <text_editor follows="left|top" - height="146" + height="50" layout="topleft" - left="16" + left="10" max_length="800" mouse_opaque="false" name="details_edit" - top="386" - width="356" + top_pad="2" + width="265" word_wrap="true" /> <text type="string" length="1" follows="left|top" - height="16" + height="50" layout="topleft" left_delta="0" + font.style="BOLD" name="incomplete_title" top_pad="8" - width="342"> + word_wrap="true" + width="265"> Note: Incomplete reports will not be investigated. </text> <button - bottom="580" + bottom="590" follows="right|bottom" height="20" label="Cancel" label_selected="Cancel" layout="topleft" name="cancel_btn" - right="373" - width="150" /> + right="275" + width="130" /> <button - bottom="580" + bottom="590" follows="right|bottom" height="20" label="Report Abuse" label_selected="Report Abuse" layout="topleft" name="send_btn" - right="217" - width="150" /> + right="140" + width="130" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_sys_well.xml b/indra/newview/skins/default/xui/en/floater_sys_well.xml index 46c8960fbd..d76ea398d5 100644 --- a/indra/newview/skins/default/xui/en/floater_sys_well.xml +++ b/indra/newview/skins/default/xui/en/floater_sys_well.xml @@ -4,16 +4,16 @@ background_visible="true" bevel_style="in" bg_alpha_color="0.0 0.0 0.0 0.0" - height="30" left="0" top="0" follows="right|bottom" layout="topleft" name="notification_chiclet" save_rect="true" - title="NOTIFICATIONS" + title="NOTIFICATIONS" width="320" min_width="320" + height="60" can_minimize="false" can_tear_off="false" can_resize="false" @@ -21,20 +21,36 @@ can_close="false" can_dock="true" > - <scroll_container - follows="top|bottom" - layout="topleft" - name="notification_list_container" - left="0" - top="18" - width="320" - height="12"> - <scrolling_panel_list - layout="topleft" - name="notification_list" - left="1" - top="0" - height="10" - width="318" /> - </scroll_container> + <scroll_container + follows="top|bottom" + layout="topleft" + name="notification_list_container" + left="0" + top="18" + width="320" + height="42"> + <panel + layout="topleft" + name="twin_list_panel" + left="1" + top="0" + width="318" + height="32" + bg_alpha_color="1.0 1.0 1.0 1.0"> + <scrolling_panel_list + layout="topleft" + name="notification_list" + left="1" + top="0" + height="0" + width="318"/> + <scrolling_panel_list + layout="topleft" + name="im_row_panel_list" + left="1" + top="2" + height="0" + width="318"/> + </panel> +</scroll_container> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 51e4d15e5d..a126a932df 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1003,12 +1003,15 @@ name="sale type" intial_value="2"> <combo_item + name="Copy" label="Copy" value="2" /> <combo_item + name="Contents" label="Contents" value="3" /> <combo_item + name="Original" label="Original" value="1" /> </combo_box> diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml index bb5a4e51f7..6ef1eb9513 100644 --- a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml @@ -15,4 +15,8 @@ <menu_item_call name="organize_offline" label="Organize Offline Friends"> <menu_item_call.on_click function="People.Friends.ViewSort.Action" userdata="organize_offline" /> </menu_item_call> + <menu_item_separator layout="topleft" /> + <menu_item_call name="show_blocked_list" label="Show Blocked Residents & Objects"> + <menu_item_call.on_click function="SideTray.ShowPanel" parameter="panel_block_list_sidetray" /> + </menu_item_call> </menu> diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml index 8c2c5e8c9e..2b0f029016 100644 --- a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml @@ -15,4 +15,8 @@ <menu_item_call name="view_icons" label="View People Icons"> <menu_item_call.on_click function="People.Nearby.ViewSort.Action" userdata="view_icons" /> </menu_item_call> + <menu_item_separator layout="topleft" /> + <menu_item_call name="show_blocked_list" label="Show Blocked Residents & Objects"> + <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" /> + </menu_item_call> </menu> diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml index 00cf443cc6..88b0528e53 100644 --- a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml @@ -12,4 +12,8 @@ <menu_item_call name="view_icons" label="View People Icons"> <menu_item_call.on_click function="People.Recent.ViewSort.Action" userdata="view_icons" /> </menu_item_call> + <menu_item_separator layout="topleft" /> + <menu_item_call name="show_blocked_list" label="Show Blocked Residents & Objects"> + <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" /> + </menu_item_call> </menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_agent.xml b/indra/newview/skins/default/xui/en/menu_url_agent.xml new file mode 100644 index 0000000000..463a9fccb6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_agent.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Show Resident Profile" + layout="topleft" + name="show_agent"> + <menu_item_call.on_click + function="Url.Execute" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy Name To Clipboard" + layout="topleft" + name="url_copy_label"> + <menu_item_call.on_click + function="Url.CopyLabel" /> + </menu_item_call> + <menu_item_call + label="Copy SLURL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_group.xml b/indra/newview/skins/default/xui/en/menu_url_group.xml new file mode 100644 index 0000000000..cec0aa421e --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_group.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Show Group Information" + layout="topleft" + name="show_group"> + <menu_item_call.on_click + function="Url.Execute" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy Group To Clipboard" + layout="topleft" + name="url_copy_label"> + <menu_item_call.on_click + function="Url.CopyLabel" /> + </menu_item_call> + <menu_item_call + label="Copy SLURL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_http.xml b/indra/newview/skins/default/xui/en/menu_url_http.xml new file mode 100644 index 0000000000..2503b4a2a3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_http.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Open Web Page" + layout="topleft" + name="url_open"> + <menu_item_call.on_click + function="Url.Open" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Open in Internal Browser" + layout="topleft" + name="url_open_internal"> + <menu_item_call.on_click + function="Url.OpenInternal" /> + </menu_item_call> + <menu_item_call + label="Open in External Browser" + layout="topleft" + name="url_open_external"> + <menu_item_call.on_click + function="Url.OpenExternal" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy URL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_objectim.xml b/indra/newview/skins/default/xui/en/menu_url_objectim.xml new file mode 100644 index 0000000000..7d09403b15 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_objectim.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Show Object Information" + layout="topleft" + name="show_object"> + <menu_item_call.on_click + function="Url.Execute" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Teleport to Object Location" + layout="topleft" + name="teleport_to_object"> + <menu_item_call.on_click + function="Url.Teleport" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy Object Name To Clipboard" + layout="topleft" + name="url_copy_label"> + <menu_item_call.on_click + function="Url.CopyLabel" /> + </menu_item_call> + <menu_item_call + label="Copy SLURL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_parcel.xml b/indra/newview/skins/default/xui/en/menu_url_parcel.xml new file mode 100644 index 0000000000..bbd63c6d8c --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_parcel.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Show Parcel Information" + layout="topleft" + name="show_parcel"> + <menu_item_call.on_click + function="Url.Execute" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy SLURL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_slapp.xml b/indra/newview/skins/default/xui/en/menu_url_slapp.xml new file mode 100644 index 0000000000..19df721b2b --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_slapp.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Run This Command" + layout="topleft" + name="run_slapp"> + <menu_item_call.on_click + function="Url.Execute" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy SLURL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_slurl.xml b/indra/newview/skins/default/xui/en/menu_url_slurl.xml new file mode 100644 index 0000000000..0e9525fa4b --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_slurl.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Show Place Information" + layout="topleft" + name="show_place"> + <menu_item_call.on_click + function="Url.Execute" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Teleport to Location" + layout="topleft" + name="teleport_to_location"> + <menu_item_call.on_click + function="Url.Teleport" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy SLURL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_url_teleport.xml b/indra/newview/skins/default/xui/en/menu_url_teleport.xml new file mode 100644 index 0000000000..22cc035e49 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_url_teleport.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<context_menu + layout="topleft" + name="Url Popup"> + <menu_item_call + label="Teleport To This Location" + layout="topleft" + name="teleport"> + <menu_item_call.on_click + function="Url.Execute" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Copy SLURL To Clipboard" + layout="topleft" + name="url_copy"> + <menu_item_call.on_click + function="Url.CopyUrl" /> + </menu_item_call> +</context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index ef9e22d908..6bc12368b7 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -229,7 +229,7 @@ function="Floater.Toggle" parameter="communicate" /> </menu_item_check> - <menu_item_call + <menu_item_call label="(Temp) Media Remote Ctrl" layout="topleft" name="Preferences" @@ -284,6 +284,44 @@ function="Floater.Show" parameter="region_info" /> </menu_item_call> + <menu + create_jump_keys="true" + label="Land Options" + layout="topleft" + name="Land" + tear_off="true"> + <menu_item_check + label="Show Property Lines" + layout="topleft" + name="Property Lines" + shortcut="control|alt|shift|P"> + <menu_item_check.on_check + control="ShowPropertyLines" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="ShowPropertyLines" /> + </menu_item_check> + <menu_item_check + label="Show Land Owners" + layout="topleft" + name="Land Owners"> + <menu_item_check.on_check + control="ShowParcelOwners" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="ShowParcelOwners" /> + </menu_item_check> + <menu_item_check + label="Show Ban Lines" + layout="topleft" + name="Ban Lines"> + <menu_item_check.on_check + control="ShowBanLines" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="ShowBanLines" /> + </menu_item_check> + </menu> <menu_item_separator layout="topleft" /> <menu @@ -351,7 +389,7 @@ shortcut="control|shift|M"> <menu_item_check.on_check function="Floater.Visible" - parameter="mini_map" /> + parameter="mini_map" /> <menu_item_check.on_click function="Floater.Toggle" parameter="mini_map" /> @@ -369,7 +407,7 @@ </menu_item_call> <menu_item_separator layout="topleft" /> - <menu + <menu create_jump_keys="true" label="Sun Settings" layout="topleft" @@ -430,87 +468,78 @@ </menu> <menu_item_separator layout="topleft" /> - <menu_item_check - label="Build" + </menu> + <menu + create_jump_keys="true" + label="Build" + layout="topleft" + name="BuildTools" + tear_off="true" + visible="true"> + <menu_item_check + label="Show Build Tools" layout="topleft" - name="Build" - shortcut="B"> + name="Show Build Tools" + shortcut="control|B"> <menu_item_check.on_check function="Build.Active" /> <menu_item_check.on_click function="Build.Toggle" /> <menu_item_check.on_enable function="Build.Enabled" /> - </menu_item_check> - </menu> - <menu - label="Help" - layout="topleft" - name="Help" - tear_off="true"> - <menu_item_call - label="[SECOND_LIFE] Help" - layout="topleft" - name="Second Life Help" - shortcut="F1"> - <menu_item_call.on_click - function="ShowFloater" - parameter="help f1" /> - </menu_item_call> - <menu_item_call - label="Tutorial" - layout="topleft" - name="Tutorial"> - <menu_item_call.on_click - function="Floater.Show" - parameter="hud" /> - </menu_item_call> - <menu_item_check - label="Show Quick Tips" - layout="topleft" - name="Show Quick Tips"> - <menu_item_check.on_check - function="Help.CheckShowFirstTimeTip" /> - <menu_item_check.on_click - function="Help.ShowQuickTips" /> - </menu_item_check> - <menu_item_separator - layout="topleft" /> - <menu_item_call - label="Report Bug..." - layout="topleft" - name="ReportBug"> - <menu_item_call.on_click - function="PromptShowURL" - name="ReportBug_url" - parameter="hud,http://help.secondlife.com/en/bugreport/" /> - </menu_item_call> - <menu_item_call - label="Report Abuse..." - layout="topleft" - name="Report Abuse"> - <menu_item_call.on_click - function="ShowFloater" - parameter="complaint reporter" /> - </menu_item_call> - <menu_item_separator - layout="topleft" /> - <menu_item_call - label="About [APP_NAME]" - layout="topleft" - name="About Second Life"> - <menu_item_call.on_click - function="Floater.Show" - parameter="sl_about" /> - </menu_item_call> - </menu> - <menu - create_jump_keys="true" - label="Tools" - layout="topleft" - name="BuildTools" - tear_off="true" - visible="false"> + </menu_item_check> + <menu + create_jump_keys="true" + label="Select Build Tool" + layout="topleft" + name="Select Tool" + tear_off="true"> + <menu_item_call + label="Focus Tool" + layout="topleft" + name="Focus" + shortcut="control|1"> + <menu_item_call.on_click + function="Tools.SelectTool" + parameter="focus" /> + </menu_item_call> + <menu_item_call + label="Move Tool" + layout="topleft" + name="Move" + shortcut="control|2"> + <menu_item_call.on_click + function="Tools.SelectTool" + parameter="move" /> + </menu_item_call> + <menu_item_call + label="Edit Tool" + layout="topleft" + name="Edit" + shortcut="control|3"> + <menu_item_call.on_click + function="Tools.SelectTool" + parameter="edit" /> + </menu_item_call> + <menu_item_call + label="Create Tool" + layout="topleft" + name="Create" + shortcut="control|4"> + <menu_item_call.on_click + function="Tools.SelectTool" + parameter="create" /> + </menu_item_call> + <menu_item_call + label="Land Tool" + layout="topleft" + name="Land" + shortcut="control|5"> + <menu_item_call.on_click + function="Tools.SelectTool" + parameter="land" /> + </menu_item_call> + </menu> <menu create_jump_keys="true" label="Edit" @@ -612,6 +641,159 @@ function="Edit.EnableDeselect" /> </menu_item_call> </menu> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Link" + layout="topleft" + name="Link" + shortcut="control|L"> + <menu_item_call.on_click + function="Tools.Link" /> + <menu_item_call.on_enable + function="Tools.EnableLink" /> + </menu_item_call> + <menu_item_call + label="Unlink" + layout="topleft" + name="Unlink" + shortcut="control|shift|L"> + <menu_item_call.on_click + function="Tools.Unlink" /> + <menu_item_call.on_enable + function="Tools.EnableUnlink" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu_item_call + label="Focus on Selection" + layout="topleft" + name="Focus on Selection" + shortcut="H"> + <menu_item_call.on_click + function="Tools.LookAtSelection" + parameter="focus" /> + <menu_item_call.on_enable + function="Tools.SomethingSelectedNoHUD" /> + </menu_item_call> + <menu_item_call + label="Zoom to Selection" + layout="topleft" + name="Zoom to Selection" + shortcut="shift|H"> + <menu_item_call.on_click + function="Tools.LookAtSelection" + parameter="zoom" /> + <menu_item_call.on_enable + function="Tools.SomethingSelectedNoHUD" /> + </menu_item_call> + <menu_item_separator + layout="topleft" /> + <menu + create_jump_keys="true" + label="Object" + layout="topleft" + name="Object" + tear_off="true"> + <menu_item_call + label="Buy" + layout="topleft" + name="Menu Object Take" + visible="true"> + <menu_item_call.on_click + function="Tools.BuyOrTake" /> + <menu_item_call.on_enable + function="Tools.EnableBuyOrTake" + name="EnableBuyOrTake" + parameter="Buy,Take" /> + </menu_item_call> + <menu_item_call + label="Take Copy" + layout="topleft" + name="Take Copy"> + <menu_item_call.on_click + function="Tools.TakeCopy" /> + <menu_item_call.on_enable + function="Tools.EnableTakeCopy" /> + </menu_item_call> + <menu_item_call + label="Save Back to My Inventory" + layout="topleft" + name="Save Object Back to My Inventory"> + <menu_item_call.on_click + function="Tools.SaveToInventory" /> + <menu_item_call.on_enable + function="Tools.EnableSaveToInventory" /> + </menu_item_call> + <menu_item_call + label="Save Back to Object Contents" + layout="topleft" + name="Save Object Back to Object Contents"> + <menu_item_call.on_click + function="Tools.SaveToObjectInventory" /> + <menu_item_call.on_enable + function="Tools.EnableSaveToObjectInventory" /> + </menu_item_call> + </menu> + <menu + create_jump_keys="true" + label="Scripts" + layout="topleft" + name="Scripts" + tear_off="true"> + <menu_item_call + label="Recompile Scripts (Mono)" + layout="topleft" + name="Mono"> + <menu_item_call.on_click + function="Tools.SelectedScriptAction" + parameter="compile mono" /> + <menu_item_call.on_enable + function="EditableSelectedMono" /> + </menu_item_call> + <menu_item_call + label="Recompile Scripts (LSL)" + layout="topleft" + name="LSL"> + <menu_item_call.on_click + function="Tools.SelectedScriptAction" + parameter="compile lsl" /> + <menu_item_call.on_enable + function="EditableSelected" /> + </menu_item_call> + <menu_item_call + label="Reset Scripts" + layout="topleft" + name="Reset Scripts"> + <menu_item_call.on_click + function="Tools.SelectedScriptAction" + parameter="reset" /> + <menu_item_call.on_enable + function="EditableSelected" /> + </menu_item_call> + <menu_item_call + label="Set Scripts to Running" + layout="topleft" + name="Set Scripts to Running"> + <menu_item_call.on_click + function="Tools.SelectedScriptAction" + parameter="start" /> + <menu_item_call.on_enable + function="EditableSelected" /> + </menu_item_call> + <menu_item_call + label="Set Scripts to Not Running" + layout="topleft" + name="Set Scripts to Not Running"> + <menu_item_call.on_click + function="Tools.SelectedScriptAction" + parameter="stop" /> + <menu_item_call.on_enable + function="EditableSelected" /> + </menu_item_call> + </menu> + <menu_item_separator + layout="topleft" /> <menu create_jump_keys="true" label="Options" @@ -800,196 +982,68 @@ parameter="CheesyBeacon" /> </menu_item_check> </menu> - <menu - create_jump_keys="true" - label="Land" - layout="topleft" - name="Land" - tear_off="true"> - <menu_item_check - label="Property Lines" - layout="topleft" - name="Property Lines" - shortcut="control|alt|shift|P"> - <menu_item_check.on_check - control="ShowPropertyLines" /> - <menu_item_check.on_click - function="ToggleControl" - parameter="ShowPropertyLines" /> - </menu_item_check> - <menu_item_check - label="Land Owners" - layout="topleft" - name="Land Owners"> - <menu_item_check.on_check - control="ShowParcelOwners" /> - <menu_item_check.on_click - function="ToggleControl" - parameter="ShowParcelOwners" /> - </menu_item_check> - <menu_item_check - label="Ban Lines" - layout="topleft" - name="Ban Lines"> - <menu_item_check.on_check - control="ShowBanLines" /> - <menu_item_check.on_click - function="ToggleControl" - parameter="ShowBanLines" /> - </menu_item_check> - </menu> </menu> - <menu - create_jump_keys="true" - label="Actions" + </menu> + <menu + label="Help" + layout="topleft" + name="Help" + tear_off="true"> + <menu_item_call + label="[SECOND_LIFE] Help" layout="topleft" - name="Actions" - tear_off="true"> - <menu_item_call - label="Link" - layout="topleft" - name="Link" - shortcut="control|L"> - <menu_item_call.on_click - function="Tools.Link" /> - <menu_item_call.on_enable - function="Tools.EnableLink" /> - </menu_item_call> - <menu_item_call - label="Unlink" - layout="topleft" - name="Unlink" - shortcut="control|shift|L"> - <menu_item_call.on_click - function="Tools.Unlink" /> - <menu_item_call.on_enable - function="Tools.EnableUnlink" /> - </menu_item_call> - <menu_item_separator - layout="topleft" /> - <menu_item_call - label="Focus on Selection" - layout="topleft" - name="Focus on Selection" - shortcut="H"> - <menu_item_call.on_click - function="Tools.LookAtSelection" - parameter="focus" /> - <menu_item_call.on_enable - function="Tools.SomethingSelectedNoHUD" /> - </menu_item_call> - <menu_item_call - label="Zoom to Selection" - layout="topleft" - name="Zoom to Selection" - shortcut="shift|H"> - <menu_item_call.on_click - function="Tools.LookAtSelection" - parameter="zoom" /> - <menu_item_call.on_enable - function="Tools.SomethingSelectedNoHUD" /> - </menu_item_call> - <menu_item_separator + name="Second Life Help" + shortcut="F1"> + <menu_item_call.on_click + function="ShowFloater" + parameter="help f1" /> + </menu_item_call> + <menu_item_call + label="Tutorial" + layout="topleft" + name="Tutorial"> + <menu_item_call.on_click + function="Floater.Show" + parameter="hud" /> + </menu_item_call> + <menu_item_check + label="Show Quick Tips" + layout="topleft" + name="Show Quick Tips"> + <menu_item_check.on_check + function="Help.CheckShowFirstTimeTip" /> + <menu_item_check.on_click + function="Help.ShowQuickTips" /> + </menu_item_check> + <menu_item_separator layout="topleft" /> - <menu_item_call - label="Buy Object" - layout="topleft" - name="Menu Object Take" - visible="false"> - <menu_item_call.on_click - function="Tools.BuyOrTake" /> - <menu_item_call.on_enable - function="Tools.EnableBuyOrTake" - name="EnableBuyOrTake" - parameter="Buy,Take" /> - </menu_item_call> - <menu_item_call - label="Take Copy" - layout="topleft" - name="Take Copy"> - <menu_item_call.on_click - function="Tools.TakeCopy" /> - <menu_item_call.on_enable - function="Tools.EnableTakeCopy" /> - </menu_item_call> - <menu_item_call - label="Save Object Back to My Inventory" + <menu_item_call + label="Report Bug..." layout="topleft" - name="Save Object Back to My Inventory"> - <menu_item_call.on_click - function="Tools.SaveToInventory" /> - <menu_item_call.on_enable - function="Tools.EnableSaveToInventory" /> - </menu_item_call> - <menu_item_call - label="Save Object Back to Object Contents" + name="ReportBug"> + <menu_item_call.on_click + function="PromptShowURL" + name="ReportBug_url" + parameter="hud,http://help.secondlife.com/en/bugreport/" /> + </menu_item_call> + <menu_item_call + label="Report Abuse..." layout="topleft" - name="Save Object Back to Object Contents"> + name="Report Abuse"> <menu_item_call.on_click - function="Tools.SaveToObjectInventory" /> - <menu_item_call.on_enable - function="Tools.EnableSaveToObjectInventory" /> + function="ShowFloater" + parameter="complaint reporter" /> </menu_item_call> - <menu_item_separator + <menu_item_separator layout="topleft" /> - <menu - create_jump_keys="true" - label="Recompile Scripts in Selection" - layout="topleft" - name="Recompile Scripts in Selection" - tear_off="true"> - <menu_item_call - label="Mono" - layout="topleft" - name="Mono"> - <menu_item_call.on_click - function="Tools.SelectedScriptAction" - parameter="compile mono" /> - <menu_item_call.on_enable - function="EditableSelectedMono" /> - </menu_item_call> - <menu_item_call - label="LSL" - layout="topleft" - name="LSL"> - <menu_item_call.on_click - function="Tools.SelectedScriptAction" - parameter="compile lsl" /> - <menu_item_call.on_enable - function="EditableSelected" /> - </menu_item_call> - </menu> - <menu_item_call - label="Reset Scripts in Selection" - layout="topleft" - name="Reset Scripts in Selection"> - <menu_item_call.on_click - function="Tools.SelectedScriptAction" - parameter="reset" /> - <menu_item_call.on_enable - function="EditableSelected" /> - </menu_item_call> - <menu_item_call - label="Set Scripts to Running in Selection" - layout="topleft" - name="Set Scripts to Running in Selection"> - <menu_item_call.on_click - function="Tools.SelectedScriptAction" - parameter="start" /> - <menu_item_call.on_enable - function="EditableSelected" /> - </menu_item_call> - <menu_item_call - label="Set Scripts to Not Running in Selection" - layout="topleft" - name="Set Scripts to Not Running in Selection"> - <menu_item_call.on_click - function="Tools.SelectedScriptAction" - parameter="stop" /> - <menu_item_call.on_enable - function="EditableSelected" /> - </menu_item_call> - </menu> + <menu_item_call + label="About [APP_NAME]" + layout="topleft" + name="About Second Life"> + <menu_item_call.on_click + function="Floater.Show" + parameter="sl_about" /> + </menu_item_call> </menu> <menu label="Advanced" @@ -1035,7 +1089,6 @@ function="World.AlwaysRun" /> </menu_item_check> <menu_item_check - control_name="FlyBtnState" label="Fly" layout="topleft" name="Fly" @@ -1827,7 +1880,7 @@ function="Advanced.ShowDebugSettings" parameter="all" /> </menu_item_call> - <menu_item_check + <menu_item_check label="Debug (QA) Mode" layout="topleft" name="Debug Mode" @@ -2210,8 +2263,7 @@ <menu_item_check label="View Admin Options" layout="topleft" - name="View Admin Options" - shortcut="control|alt|V"> + name="View Admin Options"> <menu_item_check.on_check function="Advanced.CheckViewAdminOptions" parameter="ViewAdminOptions" /> @@ -2497,7 +2549,7 @@ name="Simple Web Browser Test"> <menu_item_call.on_click function="Floater.Show" - parameter="html_simple.http://www.secondlife.com" /> + parameter="html_simple.http://www.secondlife.com" /> </menu_item_call> <menu_item_call label="UI/Color Settings" @@ -2666,7 +2718,7 @@ name="Show Font Test"> <menu_item_call.on_click function="Floater.Show" - parameter="font_test" /> + parameter="font_test" /> </menu_item_call> <menu_item_call label="Load from XML..." @@ -3144,7 +3196,7 @@ name="God Tools"> <menu_item_call.on_click function="Floater.Show" - parameter="god_tools" /> + parameter="god_tools" /> <menu_item_call.on_enable function="EnableGodCustomerService" /> </menu_item_call> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 98c9ec868a..8b20918700 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -4495,7 +4495,7 @@ Link to this from a web page to give others easy access to this location, or try icon="alertmodal.tga" name="GraphicsPreferencesHelp" type="alertmodal"> -This panel controls window size and resolution and the quality of the client's graphics. The Preferences > Graphics interface allows you to choose between four graphics levels: Low, Mid, High, and Ultra. You may also customize your graphics settings by checking the Custom checkbox and manipulating the following settings: +This panel controls window size and resolution and the quality of the client's graphics. The Preferences > Graphics interface allows you to choose between four graphics levels: Low, Mid, High, and Ultra. You may also customize your graphics settings by clicking the Advanced button and manipulating the following settings: Shaders: Enable or disable various types of pixel shaders. @@ -5029,7 +5029,7 @@ You must have payment information on file to visit this area. Do you want to go icon="alertmodal.tga" name="MissingString" type="alertmodal"> -How odd. The string [STRING_NAME] is missing from strings.xml +The string [STRING_NAME] is missing from strings.xml </notification> <notification diff --git a/indra/newview/skins/default/xui/en/panel_activeim_row.xml b/indra/newview/skins/default/xui/en/panel_activeim_row.xml index 8977f30a51..f5af8e7b30 100644 --- a/indra/newview/skins/default/xui/en/panel_activeim_row.xml +++ b/indra/newview/skins/default/xui/en/panel_activeim_row.xml @@ -1,47 +1,53 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<panel - follows="bottom|right" +<panel name="panel_activeim_row" layout="topleft" + follows="left|right" top="0" left="0" - height="40" - width="332" + height="35" + width="318" background_visible="true" bevel_style="in" bg_alpha_color="0 0 0 0"> - <chiclet_im + <chiclet_im_p2p name="chiclet" layout="topleft" - top="4" - left="10" - height="26" + follows="left" + top="5" + left="5" + height="25" width="45"> - </chiclet_im> + </chiclet_im_p2p> <text type="string" name="contact_name" layout="topleft" top="8" - left="70" - height="20" - width="230" + left_pad="6" + height="28" + width="235" length="1" - follows="left|top|right|bottom" - font="SansSerifBigBold" - text_color="White">Contact Name</text> - <button - name="hide_btn" - layout="topleft" - top="10" - left="310" - height="20" - width="20" - label="" - image_unselected="toast_hide_btn.tga" - image_disabled="toast_hide_btn.tga" - image_selected="toast_hide_btn.tga" - image_hover_selected="toast_hide_btn.tga" - image_disabled_selected="toast_hide_btn.tga"> - </button> + follows="right|left" + font="SansSerifBold" + text_color="White"> + Contact Name + </text> + <button + top="5" + left_pad="5" + width="15" + height="15" + layout="topleft" + follows="right" + name="hide_btn" + mouse_opaque="true" + label="" + tab_stop="false" + image_unselected="toast_hide_btn.tga" + image_disabled="toast_hide_btn.tga" + image_selected="toast_hide_btn.tga" + image_hover_selected="toast_hide_btn.tga" + image_disabled_selected="toast_hide_btn.tga" + /> </panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml new file mode 100644 index 0000000000..5c8a8ee208 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + background_visible="true" + follows="left|top|right|bottom" + height="305" + layout="topleft" + name="block_list_panel" + min_height="350" + min_width="240" + width="280"> + <text + follows="top|left|right" + font="SansSerifHugeBold" + height="20" + layout="topleft" + left="10" + name="title_text" + text_color="white" + top="0" + width="250"> + Blocked List + </text> + <button + follows="top|right" + height="25" + image_overlay="BackArrow_Off" + layout="topleft" + name="back" + right="-9" + tab_stop="false" + top="0" + width="25"/> + <scroll_list + follows="left|top|right|bottom" + height="200" + layout="topleft" + left="5" + name="blocked" + tool_tip="List of currently blocked residents" + top="30" + width="270" /> + <button + follows="left|bottom" + height="20" + label="Block Resident..." + label_selected="Block Resident..." + layout="topleft" + left_delta="0" + name="Block resident..." + tool_tip="Pick a resident to block" + top_pad="4" + width="210"> + <button.commit_callback + function="Block.ClickPick" /> + </button> + <button + follows="left|bottom" + height="20" + label="Block object by name..." + label_selected="Block object by name..." + layout="topleft" + left_delta="0" + name="Block object by name..." + top_pad="4" + width="210" > + <button.commit_callback + function="Block.ClickBlockByName" /> + </button> + <button + enabled="false" + follows="left|bottom" + height="20" + label="Unblock" + label_selected="Unblock" + layout="topleft" + left_delta="0" + name="Unblock" + tool_tip="Remove resident or object from blocked list" + top_pad="4" + width="210" > + <button.commit_callback + function="Block.ClickRemove" /> + </button> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index b6d0678cfb..79ca839f28 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -216,41 +216,7 @@ left="0" top="0" width="5"/> - <layout_panel - auto_resize="false" - follows="right" - height="28" - layout="topleft" - min_height="28" - name="im_well_panel" - width="40" - top="0" - min_width="40" - user_resize="false"> - <chiclet_notification - follows="right" - height="25" - layout="topleft" - left="0" - name="im_well" - top="2" - width="40"> - <button - image_selected="im_notifications.tga" - image_unselected="im_notifications.tga"/> - <unread_notifications - width="20" - height="20" - left="18" - top="23"/> -<!-- - <chiclet_notification.commit_callback - function="Notification.Show" - parameter="ClickUnimplemented" /> - --> - </chiclet_notification> - </layout_panel> - <icon + <icon auto_resize="false" color="0 0 0 0" follows="left|right" @@ -300,7 +266,7 @@ top="2" width="48"> <button - image_selected="bottom_tray_sys_notifications.tga" + image_selected="bottom_tray_sys_notifications_selected.tga" image_unselected="bottom_tray_sys_notifications.tga"/> <unread_notifications width="20" diff --git a/indra/newview/skins/default/xui/en/panel_edit_pick.xml b/indra/newview/skins/default/xui/en/panel_edit_pick.xml index 291803fbc5..5dd03656c6 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_pick.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_pick.xml @@ -9,6 +9,30 @@ name="panel_edit_pick" top="0" width="255"> + <text + type="string" + length="1" + follows="top" + font="SansSerifHugeBold" + height="15" + layout="topleft" + left="10" + name="title" + text_color="white" + top="5" + width="250"> + Edit Pick + </text> + <button + follows="top|right" + height="20" + image_overlay="BackArrow_Off" + layout="topleft" + name="back_btn" + picture_style="true" + right="-20" + top="7" + width="20" /> <scroll_container color="DkGray2" follows="left|top|right|bottom" @@ -27,64 +51,42 @@ left="0" width="240" height="575"> - <text - type="string" - length="1" - follows="top" - font="SansSerifHugeBold" - height="15" - layout="topleft" - left="10" - name="title" - text_color="white" - top="17" - width="250"> - Edit Pick - </text> <panel background_visible="true" bg_alpha_color="DkGray2" - width="280" + width="220" follows="left|right|top|bottom" height="560" layout="topleft" + left="0" + top="0"> + <texture_picker + follows="left|top|right" + height="190" + width="220" + layout="topleft" + top="20" left="10" - right="-10" - top_pad="5"> - <panel - follows="left|top|right" - height="150" - layout="topleft" - left="10" - right="-10" - top="10"> - <panel - follows="left|top|right" - height="150" - layout="topleft" > - <texture_picker - follows="left|top|right" - height="150" - layout="topleft" - name="pick_snapshot" /> - </panel> - <icon - height="16" - image_name="image_edit_icon.tga" - layout="topleft" - name="edit_icon" - right="-25" - top="30" - visible="false" - width="16" /> - </panel> + name="pick_snapshot" /> + <icon + height="16" + image_name="image_edit_icon.tga" + layout="topleft" + name="edit_icon" + left="245" + top="35" + visible="true" + width="16" /> <text type="string" length="1" follows="left|top" - height="16" + height="15" + font="SansSerifSmall" + font.style="BOLD" layout="topleft" left="10" + top="215" name="Name:" text_color="white"> Name: @@ -95,46 +97,49 @@ height="20" layout="topleft" left="10" + top_pad="2" max_length="63" name="pick_name" - right="-10" text_color="black" - width="255" /> + width="220" /> <text type="string" length="1" follows="left|top" - height="30" + height="15" + font="SansSerifSmall" + font.style="BOLD" layout="topleft" left="10" + top_pad="20" name="description_label" - text_color="white" - v_pad="15" - valign="center"> + text_color="white"> Description: </text> <text_editor follows="left|top|right" height="100" + width="220" hide_scrollbar="true" layout="topleft" left="10" + top_pad="2" max_length="1023" name="pick_desc" text_color="black" - right="-10" word_wrap="true" /> <text type="string" length="1" + font="SansSerifSmall" + font.style="BOLD" follows="left|top" - height="20" + height="15" layout="topleft" left="10" name="location_label" text_color="white" - v_pad="15" - valign="bottom"> + top_pad="20"> Location: </text> <text @@ -146,10 +151,9 @@ left="10" name="pick_location" right="-10" + top_pad="2" text_color="white" - v_pad="10" width="250" - valign="center" word_wrap="true"> loading... </text> @@ -166,7 +170,7 @@ </scroll_container> <panel follows="left|right|bottom" - height="25" + height="30" label="bottom_panel" layout="topleft" left="10" @@ -174,21 +178,21 @@ top_pad="2"> <button follows="bottom|left" - height="20" + height="25" label="Save [WHAT]" layout="topleft" name="save_changes_btn" - right="-120" - top="5" + left="0" + top="0" width="130" /> <button follows="bottom|left" - height="20" + height="25" label="Cancel" layout="topleft" name="cancel_btn" - right="-10" - top="5" - width="90" /> + left_pad="5" + top_delta="0" + width="130" /> </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_edit_profile.xml b/indra/newview/skins/default/xui/en/panel_edit_profile.xml index c0366437db..0d6d8ba97d 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_profile.xml @@ -12,7 +12,45 @@ name="edit_profile_panel" top="10" width="255"> - <scroll_container + <string + name="CaptionTextAcctInfo"> + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + </string> + <string + name="AcctTypeResident" + value="Resident" /> + <string + name="AcctTypeTrial" + value="Trial" /> + <string + name="AcctTypeCharterMember" + value="Charter Member" /> + <string + name="AcctTypeEmployee" + value="Linden Lab Employee" /> + <string + name="PaymentInfoUsed" + value="Payment Info Used" /> + <string + name="PaymentInfoOnFile" + value="Payment Info On File" /> + <string + name="NoPaymentInfoOnFile" + value="No Payment Info On File" /> + <string + name="AgeVerified" + value="Age-verified" /> + <string + name="NotAgeVerified" + value="Not Age-verified" /> + <string + name="partner_edit_link_url"> + http://www.secondlife.com/account/partners.php?lang=en + </string> + <string + name="no_partner_text" + value="None" /> + <scroll_container color="DkGray2" follows="left|top|right|bottom" height="300" @@ -34,7 +72,7 @@ background_visible="true" bg_alpha_color="DkGray2" follows="left|top|right|bottom" - height="620" + height="750" layout="topleft" left="0" name="data_panel" @@ -243,11 +281,10 @@ top_pad="15" value="Account Status:" width="100" /> - <link + <text type="string" follows="left|top" font="SansSerifSmall" - font.style="UNDERLINE" height="15" layout="topleft" left_pad="10" @@ -277,15 +314,14 @@ top_pad="15" value="Partner:" width="100" /> - <link + <text follows="left|top" height="15" - font.style="UNDERLINE" layout="topleft" left_pad="10" name="partner_edit_link" top_delta="0" - value="Edit" + value="[[URL] Edit]" width="100" /> <panel follows="left|top|right" diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml index 2de41a9ee6..6ba4d13117 100644 --- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml +++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml @@ -69,6 +69,7 @@ left_delta="0" name="founder_name" top_pad="10" + use_ellipses="true" width="140" /> <button top="632" diff --git a/indra/newview/skins/default/xui/en/panel_group_notify.xml b/indra/newview/skins/default/xui/en/panel_group_notify.xml index 8ebf1b69a7..f97daf922f 100644 --- a/indra/newview/skins/default/xui/en/panel_group_notify.xml +++ b/indra/newview/skins/default/xui/en/panel_group_notify.xml @@ -1,8 +1,12 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel background_visible="true" bevel_style="in" bg_alpha_color="0 0 0 0" - height="200" label="instant_message" layout="topleft" left="0" + height="155" label="instant_message" layout="topleft" left="0" name="panel_group_notify" top="0" width="350"> - <panel background_visible="true" bevel_style="in" bg_alpha_color="black" + <string + name="message_max_lines_count"> + 4 + </string> + <panel follows="top" background_visible="true" bevel_style="in" bg_alpha_color="black" height="50" label="header" layout="topleft" left="0" name="header" top="0" width="350"> <icon follows="left|top|right|bottom" height="40" width="40" layout="topleft" @@ -13,21 +17,61 @@ Sender Name / Group Name </text> </panel> - <text_editor type="string" length="1" bg_readonly_color="0 0 0 0" - follows="left|top|right|bottom" height="70" hide_scrollbar="true" - hide_border="true" layout="topleft" top="55" left="25" name="message" - text_color="GroupNotifyTextColor" text_readonly_color="GroupNotifyTextColor" width="300" word_wrap="true"> - Message - Body - </text_editor> - <icon follows="left|top|right|bottom" height="16" width="16" - layout="topleft" top="135" left="25" mouse_opaque="true" name="attachment_icon" /> + <text + follows="top" + height="20" + layout="topleft" + left="25" + name="subject" + text_color="GroupNotifyTextColor" + font="SansSerifBig" + top="60" + use_ellipses="true" + value="subject" + width="300" + word_wrap="true"> + subject + </text> + <text + follows="top" + height="20" + layout="topleft" + left="25" + name="datetime" + text_color="GroupNotifyTextColor" + font="SansSerif" + top="80" + use_ellipses="true" + value="datetime" + width="300" + word_wrap="true"> + datetime + </text> + <text + follows="left|top|bottom|right" + height="0" + layout="topleft" + left="25" + name="message" + text_color="GroupNotifyTextColor" + top="100" + use_ellipses="true" + value="message" + width="300" + word_wrap="true" + visible="true" > + </text> + <icon + follows="left|bottom|right" height="15" width="15" + layout="topleft" bottom="122" left="25" mouse_opaque="true" name="attachment_icon" visible="true" + /> <text font="SansSerif" font.style="UNDERLINE" font_shadow="hard" - type="string" length="1" follows="left|top|right|bottom" layout="topleft" - left="45" top="135" height="15" width="280" name="attachment" - text_color="GroupNotifyTextColor"> + type="string" length="1" follows="left|bottom|right" layout="topleft" + left="45" bottom="122" height="15" width="280" name="attachment" + text_color="GroupNotifyTextColor" visible="true"> Attachment - </text> - <button label="OK" layout="topleft" top="170" left="140" height="20" - width="70" name="btn_ok" /> -</panel> + </text> + + <button label="OK" layout="topleft" bottom="145" left="140" height="20" + width="70" name="btn_ok" follows="bottom" /> +</panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_instant_message.xml b/indra/newview/skins/default/xui/en/panel_instant_message.xml index 169fde7b47..ace456918c 100644 --- a/indra/newview/skins/default/xui/en/panel_instant_message.xml +++ b/indra/newview/skins/default/xui/en/panel_instant_message.xml @@ -10,6 +10,10 @@ name="im_panel" top="0" width="350"> + <string + name="message_max_lines_count"> + 6 + </string> <panel background_visible="true" bevel_style="in" @@ -56,7 +60,7 @@ width="50" /> </panel> <text - follows="left|bottom|right" + follows="left|top|bottom|right" height="60" layout="topleft" left="10" diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index dee911a45d..80dca8c0c1 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -107,8 +107,8 @@ <!-- picture_style="true" --> <!-- top_delta="0" --> <!-- width="168" /> --> - - <search_editor + + <search_combo_box bevel_style="none" border_style="line" border.border_thickness="0" @@ -118,12 +118,15 @@ height="22" label="Search" layout="topleft" - left_pad="7" + right="-10" mouse_opaque="false" - name="search_input" + name="search_combo_box" tool_tip="Search" top_delta="0" - width="200" /> + width="200" > + <combo_editor + label="Search" /> + </search_combo_box> </panel> <favorites_bar diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 22823ea98b..e5a417e3d0 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -130,24 +130,15 @@ min_height="100" name="tab_online" title="Online"> - <panel - follows="all" - height="150" - layout="topleft" - left="0" - name="tab_online_panel" - top="100" - width="285"> <avatar_list draw_heading="false" follows="all" - height="145" + height="150" layout="topleft" left="0" name="avatars_online" top="0" width="285" /> - </panel> </accordion_tab> <accordion_tab can_resize="false" @@ -155,14 +146,6 @@ min_height="100" name="tab_all" title="All"> - <panel - follows="all" - height="260" - layout="topleft" - left="0" - name="tab_all_panel" - top="100" - width="285"> <avatar_list draw_heading="false" follows="all" @@ -172,7 +155,6 @@ name="avatars_all" top="0" width="285" /> - </panel> </accordion_tab> </accordion> <panel diff --git a/indra/newview/skins/default/xui/en/panel_pick_info.xml b/indra/newview/skins/default/xui/en/panel_pick_info.xml index 80fa99c257..c330116702 100644 --- a/indra/newview/skins/default/xui/en/panel_pick_info.xml +++ b/indra/newview/skins/default/xui/en/panel_pick_info.xml @@ -8,24 +8,6 @@ name="panel_pick_info" top="0" width="255"> - <scroll_container - color="DkGray2" - follows="left|top|right|bottom" - height="300" - layout="topleft" - left="0" - name="profile_scroll" - reserve_scroll_corner="true" - opaque="true" - width="255"> - <panel - name="scroll_content_panel" - follows="left|top|right" - layout="topleft" - top="0" - left="0" - width="240" - height="575"> <text follows="top" font="SansSerifHugeBold" @@ -47,6 +29,24 @@ right="-20" top="7" width="20" /> + <scroll_container + color="DkGray2" + follows="left|top|right|bottom" + height="300" + layout="topleft" + left="0" + name="profile_scroll" + reserve_scroll_corner="true" + opaque="true" + width="255"> + <panel + name="scroll_content_panel" + follows="left|top|right" + layout="topleft" + top="0" + left="0" + width="240" + height="575"> <panel background_visible="true" bg_alpha_color="DkGray2" @@ -55,80 +55,51 @@ layout="topleft" left="0" min_height="300" - top="30" - width="255"> + top="0" + width="220"> <texture_picker enabled="false" follows="left|top|right" - height="300" + height="190" layout="topleft" left="10" name="pick_snapshot" - top="10" - width="245" /> - <text - follows="left|top" - font="SansSerifBigBold" - height="15" - layout="topleft" - left="10" - name="Name:" - text_color="white" - value="Name:" /> + top="20" + width="220" /> <text follows="left|top|right" - height="15" + height="20" layout="topleft" + font="SansSerif" + font.style="BOLD" left="10" name="pick_name" - right="-10" text_color="white" value="[name]" word_wrap="true" /> <text follows="left|top" - font="SansSerifBigBold" - height="15" + height="30" layout="topleft" left="10" - name="description_label" + name="pick_location" text_color="white" - top_pad="20" - valign="center" - value="Description:" /> + top_pad="10" + width="255" + word_wrap="true" + value="[loading...]" /> <text follows="left|top|right" - height="60" + height="150" layout="topleft" left="10" + top_pad="20" name="pick_desc" - right="-10" text_color="white" - valign="center" + width="225" value="[description]" - width="255" word_wrap="true" /> - <text - follows="left|top" - font="SansSerifBigBold" - height="20" - layout="topleft" - left="10" - name="location_label" - text_color="white" - top_pad="20" - valign="bottom" - value="Location:" /> - <text - follows="left|top" - height="30" - layout="topleft" - left="10" - name="pick_location" - text_color="white" - valign="center" - value="[loading...]" /> - </panel> + </panel> </panel> </scroll_container> <panel @@ -136,9 +107,8 @@ height="30" layout="topleft" top_pad="2" - left="8" - name="buttons" - right="-10"> + left="10" + name="buttons"> <button follows="bottom|left" font="SansSerifSmallBold" @@ -148,14 +118,14 @@ left="0" name="edit_btn" top="0" - width="50" /> + width="80" /> <button follows="bottom|left" font="SansSerifSmallBold" height="25" label="Teleport" layout="topleft" - left_pad="2" + left_pad="3" name="teleport_btn" top="0" width="80" /> @@ -165,9 +135,9 @@ height="25" label="Map" layout="topleft" - left_pad="2" + left_pad="3" name="show_on_map_btn" top="0" - width="100" /> + width="80" /> </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_pick_list_item.xml b/indra/newview/skins/default/xui/en/panel_pick_list_item.xml index 6f4110067b..4c8c4efbe7 100644 --- a/indra/newview/skins/default/xui/en/panel_pick_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_pick_list_item.xml @@ -8,6 +8,26 @@ name="picture_item" top="0" width="275"> + <icon + height="120" + image_name="ListItem_Over" + left="0" + mouse_opaque="false" + name="hovered_icon" + top="0" + scale_image="true" + visible="false" + width="270"/> + <icon + height="120" + image_name="ListItem_Select" + left="0" + mouse_opaque="false" + name="selected_icon" + top="0" + scale_image="true" + visible="false" + width="270"/> <texture_picker allow_no_texture="true" default_image_name="None" diff --git a/indra/newview/skins/default/xui/en/panel_picks.xml b/indra/newview/skins/default/xui/en/panel_picks.xml index ff161cc2ab..c56bb32feb 100644 --- a/indra/newview/skins/default/xui/en/panel_picks.xml +++ b/indra/newview/skins/default/xui/en/panel_picks.xml @@ -28,11 +28,11 @@ opaque="true" top="0" width="284"> - <panel + <list height="115" layout="topleft" left="0" - name="back_panel" + name="picks_list" top="0" width="284" /> </scroll_container> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 060d84b2e4..88bf3d3b22 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -120,7 +120,7 @@ height="10" left="30" text_color="EmphasisColor" - name="text_box1" + name="heading1" top_pad="30" width="270"> Camera: @@ -166,7 +166,7 @@ Camera: length="1" height="10" left="30" - name="text_box1" + name="heading2" width="270"> Automatic positioning for: </text> @@ -194,7 +194,7 @@ Automatic positioning for: height="10" left="30" text_color="EmphasisColor" - name="text_box1" + name="heading3" top_pad="30" width="270"> My Avatar: diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml index 95d8d2ce2a..70292a38aa 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml @@ -260,7 +260,7 @@ label="Show my name" layout="topleft" left_delta="0" - name="show_my_name_checkbox" + name="show_my_name_checkbox1" top_pad="5" width="300" /> <check_box @@ -280,7 +280,7 @@ label="Show group titles" layout="topleft" left_delta="-175" - name="show_all_title_checkbox" + name="show_all_title_checkbox1" top_pad="5" width="300" /> <text diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index d90be9ea25..135dcb167b 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -167,11 +167,10 @@ width="255"> Homepage: </text> - <link + <text follows="left|top|right" height="15" layout="topleft" - font.style="UNDERLINE" left="10" name="homepage_edit" top_pad="5" @@ -212,11 +211,10 @@ top_pad="15" value="Account Status:" width="100" /> - <!-- <link + <!-- <text type="string" follows="left|top" font="SansSerifSmall" - font.style="UNDERLINE" height="15" layout="topleft" left_pad="10" @@ -246,16 +244,15 @@ top_pad="15" value="Partner:" width="100" /> - <!--<link + <text follows="left|top" height="15" - font.style="UNDERLINE" layout="topleft" left_pad="10" name="partner_edit_link" top_delta="0" - value="Edit" - width="100" /> --> + value="[[URL] Edit]" + width="100" /> <panel follows="left|top|right" height="15" diff --git a/indra/newview/skins/default/xui/en/panel_profile_view.xml b/indra/newview/skins/default/xui/en/panel_profile_view.xml index 32223d542d..9aa2c304f2 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_view.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_view.xml @@ -8,6 +8,14 @@ min_width="240" name="panel_target_profile" width="305"> + <string + name="status_online"> + Online + </string> + <string + name="status_offline"> + Offline + </string> <text follows="top|left|right" font="SansSerifHugeBold" diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index 4f23c4d26d..9b2461db7c 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -99,12 +99,12 @@ halign="left" height="100" layout="topleft" - left="30" + left="45" line_spacing="2" name="message_text" text_color="LoginProgressBoxTextColor" top="145" - width="610" /> + width="550" /> </layout_panel> <layout_panel height="200" diff --git a/indra/newview/skins/default/xui/en/panel_side_tray.xml b/indra/newview/skins/default/xui/en/panel_side_tray.xml index e9eac2c9dc..e166675364 100644 --- a/indra/newview/skins/default/xui/en/panel_side_tray.xml +++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml @@ -57,6 +57,13 @@ label="Group Info" border="true" /> + <panel + class="panel_block_list_sidetray" + name="panel_block_list_sidetray" + filename="panel_block_list_sidetray.xml" + label="Blocked Residents & Objects" + border="true" + /> </panel_container> </sidetray_tab> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 4c9b1897d5..b8152a4956 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -74,6 +74,18 @@ <string name="TooltipMustSingleDrop">Only a single item can be dragged here</string> <string name="TooltipAltLeft">Alt-Left arrow for previous tab</string> <string name="TooltipAltRight">Alt-Right arrow for next tab</string> + + <!-- tooltips for Urls --> + <string name="TooltipHttpUrl">Click to view this web page</string> + <string name="TooltipSLURL">Click to view this location's information</string> + <string name="TooltipAgentUrl">Click to view this resident's profile</string> + <string name="TooltipGroupUrl">Click to view this group's description</string> + <string name="TooltipEventUrl">Click to view this event's description</string> + <string name="TooltipClassifiedUrl">Click to view this classified</string> + <string name="TooltipParcelUrl">Click to view this parcel's description</string> + <string name="TooltipTeleportUrl">Click to teleport to this location</string> + <string name="TooltipObjectIMUrl">Click to view this object's description</string> + <string name="TooltipSLAPP">Click to run the secondlife:// command</string> <!-- ButtonToolTips, llfloater.cpp --> <string name="BUTTON_CLOSE_DARWIN">Close (⌘-W)</string> @@ -259,6 +271,7 @@ <!-- IM --> <string name="IM_logging_string">-- Instant message logging enabled --</string> + <string name="Unnamed">(Unnamed)</string> <!-- Sim Access labels --> <string name="SIM_ACCESS_PG">PG</string> @@ -288,358 +301,1439 @@ <string name="choose_the_directory">Choose Directory</string> <!-- LSL Usage Hover Tips --> - <string name="LSLTipSleepTime">Sleeps script for [SLEEP_TIME] seconds.</string> + <string name="LSLTipSleepTime"> +Sleeps script for [SLEEP_TIME] seconds. + </string> - <string name="LSLTipText_llSin">float llSin(float theta)\ntheta in radians</string> - <string name="LSLTipText_llCos">float llCos(float theta)\ntheta in radians</string> - <string name="LSLTipText_llTan">float llTan(float theta)\ntheta radians</string> - <string name="LSLTipText_llAtan2">float llAtan2(float y, float x)</string> - <string name="LSLTipText_llSqrt">float llSqrt(float val)\nreturns 0 and triggers a Math Error for imaginary results</string> - <string name="LSLTipText_llPow">float llPow(float base, float exponent)\nreturns 0 and triggers Math Error for imaginary results</string> - <string name="LSLTipText_llAbs">integer llAbs(integer val)</string> - <string name="LSLTipText_llFabs">float llFabs(float val)</string> - <string name="LSLTipText_llFrand">float llFrand(float mag)\nreturns random number in range [0,mag)</string> - <string name="LSLTipText_llFloor">integer llFloor(float val)\nreturns largest integer value <= val</string> - <string name="LSLTipText_llCeil">integer llCeil(float val)\nreturns smallest integer value >= val</string> - <string name="LSLTipText_llRound">integer llRound(float val)\nreturns val rounded to the nearest integer</string> - <string name="LSLTipText_llVecMag">float llVecMag(vector v)\nreturns the magnitude of v</string> - <string name="LSLTipText_llVecNorm">vector llVecNorm(vector v)\nreturns the v normalized</string> - <string name="LSLTipText_llVecDist">float llVecDist(vector v1, vector v2)\nreturns the 3D distance between v1 and v2</string> - <string name="LSLTipText_llRot2Euler">vector llRot2Euler(rotation q)\nreturns the Euler representation (roll, pitch, yaw) of q</string> - <string name="LSLTipText_llEuler2Rot">rotation llEuler2Rot(vector v)\nreturns the rotation representation of Euler Angles v</string> - <string name="LSLTipText_llAxes2Rot">rotation llAxes2Rot(vector fwd, vector left, vector up)\nreturns the rotation defined by the coordinate axes</string> - <string name="LSLTipText_llRot2Fwd">vector llRot2Fwd(rotation q)\nreturns the forward vector defined by q</string> - <string name="LSLTipText_llRot2Left">vector llRot2Left(rotation q)\nreturns the left vector defined by q</string> - <string name="LSLTipText_llRot2Up">vector llRot2Up(rotation q)\nreturns the up vector defined by q</string> - <string name="LSLTipText_llRotBetween">rotation llRotBetween(vector v1, vector v2)\nreturns the rotation to rotate v1 to v2</string> - <string name="LSLTipText_llWhisper">llWhisper(integer channel, string msg)\nwhispers msg on channel</string> - <string name="LSLTipText_llSay">llSay(integer channel, string msg)\nsays msg on channel</string> - <string name="LSLTipText_llShout">llShout(integer channel, string msg)\nshouts msg on channel</string> - <string name="LSLTipText_llListen">integer llListen(integer channel, string name, key id, string msg)\nsets a callback for msg on channel from name and id (name, id, and/or msg can be empty) and returns an identifier that can be used to deactivate or remove the listen</string> - <string name="LSLTipText_llListenControl">llListenControl(integer number, integer active)\nmakes a listen event callback active or inactive</string> - <string name="LSLTipText_llListenRemove">llListenRemove(integer number)\nremoves listen event callback number</string> - <string name="LSLTipText_llSensor">llSensor(string name, key id, integer type, float range, float arc)\nPerforms a single scan for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0)</string> - <string name="LSLTipText_llSensorRepeat">llSensorRepeat(string name, key id, integer type, float range, float arc, float rate)\nsets a callback for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) and repeats every rate seconds</string> - <string name="LSLTipText_llSensorRemove">llSensorRemove()\nremoves sensor</string> - <string name="LSLTipText_llDetectedName">string llDetectedName(integer number)\nreturns the name of detected object number (returns empty string if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedKey">key llDetectedKey(integer number)\nreturns the key of detected object number (returns empty key if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedOwner">key llDetectedOwner(integer number)\nreturns the key of detected object's owner (returns empty key if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedType">integer llDetectedType(integer number)\nreturns the type (AGENT, ACTIVE, PASSIVE, SCRIPTED) of detected object (returns 0 if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedPos">vector llDetectedPos(integer number)\nreturns the position of detected object number (returns <0,0,0> if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedVel">vector llDetectedVel(integer number)\nreturns the velocity of detected object number (returns <0,0,0> if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedGrab">vector llDetectedGrab(integer number)\nreturns the grab offset of the user touching object (returns <0,0,0> if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedRot">rotation llDetectedRot(integer number)\nreturns the rotation of detected object number (returns <0,0,0,1> if number is not valid sensed object)</string> - <string name="LSLTipText_llDetectedGroup">integer llDetectedGroup(integer number)\nReturns TRUE if detected object is part of same group as owner</string> - <string name="LSLTipText_llDetectedLinkNumber">integer llDetectedLinkNumber(integer number)\nreturns the link position of the triggered event for touches and collisions only</string> - <string name="LSLTipText_llDie">llDie()\ndeletes the object</string> - <string name="LSLTipText_llGround">float llGround(vector v)\nreturns the ground height below the object position + v</string> - <string name="LSLTipText_llCloud">float llCloud(vector v)\nreturns the cloud density at the object position + v</string> - <string name="LSLTipText_llWind">vector llWind(vector v)\nreturns the wind velocity at the object position + v</string> - <string name="LSLTipText_llSetStatus">llSetStatus(integer status, integer value)\nsets status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB,\nSTATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) to value</string> - <string name="LSLTipText_llGetStatus">integer llGetStatus(integer status)\ngets value of status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB,\nSTATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z)</string> - <string name="LSLTipText_llSetScale">llSetScale(vector scale)\nsets the scale</string> - <string name="LSLTipText_llGetScale">vector llGetScale()\ngets the scale</string> - <string name="LSLTipText_llSetColor">llSetColor(vector color, integer face)\nsets the color</string> - <string name="LSLTipText_llGetAlpha">float llGetAlpha(integer face)\ngets the alpha</string> - <string name="LSLTipText_llSetAlpha">llSetAlpha(float alpha, integer face)\nsets the alpha</string> - <string name="LSLTipText_llGetColor">vector llGetColor(integer face)\ngets the color</string> - <string name="LSLTipText_llSetTexture">llSetTexture(string texture, integer face)\nsets the texture of face</string> - <string name="LSLTipText_llScaleTexture">llScaleTexture(float scales, float scalet, integer face)\nsets the texture s, t scales for the chosen face</string> - <string name="LSLTipText_llOffsetTexture">llOffsetTexture(float offsets, float offsett, integer face)\nsets the texture s, t offsets for the chosen face</string> - <string name="LSLTipText_llRotateTexture">llRotateTexture(float rotation, integer face)\nsets the texture rotation for the chosen face</string> - <string name="LSLTipText_llGetTexture">string llGetTexture(integer face)\ngets the texture of face (if it's a texture in the object inventory, otherwise the key in a string)</string> - <string name="LSLTipText_llSetPos">llSetPos(vector pos)\nsets the position (if the script isn't physical)</string> - <string name="LSLTipText_llGetPos">vector llGetPos()\ngets the position (if the script isn't physical)</string> - <string name="LSLTipText_llGetLocalPos">vector llGetLocalPos()\ngets the position relative to the root (if the script isn't physical)</string> - <string name="LSLTipText_llSetRot">llSetRot(rotation rot)\nsets the rotation (if the script isn't physical)</string> - <string name="LSLTipText_llGetRot">rotation llGetRot()\ngets the rotation (if the script isn't physical)</string> - <string name="LSLTipText_llGetLocalRot">rotation llGetLocalRot()\ngets the rotation local to the root (if the script isn't physical)</string> - <string name="LSLTipText_llSetForce">llSetForce(vector force, integer local)\nsets force on object, in local coords if local == TRUE (if the script is physical)</string> - <string name="LSLTipText_llGetForce">vector llGetForce()\ngets the force (if the script is physical)</string> - <string name="LSLTipText_llTarget">integer llTarget(vector position, float range)\nset positions within range of position as a target and return an ID for the target</string> - <string name="LSLTipText_llTargetRemove">llTargetRemove(integer number)\nremoves target number</string> - <string name="LSLTipText_llRotTarget">integer llRotTarget(rotation rot, float error)\nset rotations with error of rot as a rotational target and return an ID for the rotational target</string> - <string name="LSLTipText_llRotTargetRemove">llRotTargetRemove(integer number)\nremoves rotational target number</string> - <string name="LSLTipText_llMoveToTarget">llMoveToTarget(vector target, float tau)\ncritically damp to target in tau seconds (if the script is physical)</string> - <string name="LSLTipText_llStopMoveToTarget">llStopMoveToTarget()\nStops critically damped motion</string> - <string name="LSLTipText_llApplyImpulse">llApplyImpulse(vector force, integer local)\napplies impulse to object, in local coords if local == TRUE (if the script is physical)</string> - <string name="LSLTipText_llApplyRotationalImpulse">llApplyRotationalImpulse(vector force, integer local)\napplies rotational impulse to object, in local coords if local == TRUE (if the script is physical)</string> - <string name="LSLTipText_llSetTorque">llSetTorque(vector torque, integer local)\nsets the torque of object, in local coords if local == TRUE (if the script is physical)</string> - <string name="LSLTipText_llGetTorque">vector llGetTorque()\ngets the torque (if the script is physical)</string> - <string name="LSLTipText_llSetForceAndTorque">llSetForceAndTorque(vector force, vector torque, integer local)\nsets the force and torque of object, in local coords if local == TRUE (if the script is physical)</string> - <string name="LSLTipText_llGetVel">vector llGetVel()\ngets the velocity</string> - <string name="LSLTipText_llGetAccel">vector llGetAccel()\ngets the acceleration</string> - <string name="LSLTipText_llGetOmega">vector llGetOmega()\ngets the omega</string> - <string name="LSLTipText_llGetTimeOfDay">float llGetTimeOfDay()\ngets the time in seconds since Second Life server midnight (or since server up-time; whichever is smaller)</string> - <string name="LSLTipText_llGetWallclock">float llGetWallclock()\ngets the time in seconds since midnight</string> - <string name="LSLTipText_llGetTime">float llGetTime()\ngets the time in seconds since creation</string> - <string name="LSLTipText_llResetTime">llResetTime()\nsets the time to zero</string> - <string name="LSLTipText_llGetAndResetTime">float llGetAndResetTime()\ngets the time in seconds since creation and sets the time to zero</string> - <string name="LSLTipText_llSound">llSound(string sound, float volume, integer queue, integer loop)\nplays sound at volume and whether it should loop or not</string> - <string name="LSLTipText_llPlaySound">llPlaySound(string sound, float volume)\nplays attached sound once at volume (0.0 - 1.0)</string> - <string name="LSLTipText_llLoopSound">llLoopSound(string sound, float volume)\nplays attached sound looping indefinitely at volume (0.0 - 1.0)</string> - <string name="LSLTipText_llLoopSoundMaster">llLoopSoundMaster(string sound, float volume)\nplays attached sound looping at volume (0.0 - 1.0), declares it a sync master</string> - <string name="LSLTipText_llLoopSoundSlave">llLoopSoundSlave(string sound, float volume)\nplays attached sound looping at volume (0.0 - 1.0), synced to most audible sync master</string> - <string name="LSLTipText_llPlaySoundSlave">llPlaySoundSlave(string sound, float volume)\nplays attached sound once at volume (0.0 - 1.0), synced to next loop of most audible sync master</string> - <string name="LSLTipText_llTriggerSound">llTriggerSound(string sound, float volume)\nplays sound at volume (0.0 - 1.0), centered at but not attached to object</string> - <string name="LSLTipText_llStopSound">llStopSound()\nStops currently attached sound</string> - <string name="LSLTipText_llPreloadSound">llPreloadSound(string sound)\npreloads a sound on viewers within range</string> - <string name="LSLTipText_llGetSubString">string llGetSubString(string src, integer start, integer end)\nreturns the indicated substring</string> - <string name="LSLTipText_llDeleteSubString">string llDeleteSubString(string src, integer start, integer end)\nremoves the indicated substring and returns the result</string> - <string name="LSLTipText_llInsertString">string llInsertString(string dst, integer position, string src)\ninserts src into dst at position and returns the result</string> - <string name="LSLTipText_llToUpper">string llToUpper(string src)\nconvert src to all upper case and returns the result</string> - <string name="LSLTipText_llToLower">string llToLower(string src)\nconvert src to all lower case and returns the result</string> - <string name="LSLTipText_llGiveMoney">llGiveMoney(key destination, integer amount)\ntransfer amount of money from script owner to destination</string> - <string name="LSLTipText_llMakeExplosion">llMakeExplosion(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset)\nMake a round explosion of particles</string> - <string name="LSLTipText_llMakeFountain">llMakeFountain(integer particles, float scale, float vel, float lifetime, float arc, integer bounce, string texture, vector offset, float bounce_offset)\nMake a fountain of particles</string> - <string name="LSLTipText_llMakeSmoke">llMakeSmoke(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset)\nMake smoke like particles</string> - <string name="LSLTipText_llMakeFire">llMakeFire(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset)\nMake fire like particles</string> - <string name="LSLTipText_llRezObject">llRezObject(string inventory, vector pos, vector vel, rotation rot, integer param)\nInstanciate owners inventory object at pos with velocity vel and rotation rot with start parameter param</string> - <string name="LSLTipText_llLookAt">llLookAt(vector target, F32 strength, F32 damping)\nCause object name to point it's forward axis towards target</string> - <string name="LSLTipText_llStopLookAt">llStopLookAt()\nStop causing object name to point at a target</string> - <string name="LSLTipText_llSetTimerEvent">llSetTimerEvent(float sec)\nCause the timer event to be triggered every sec seconds</string> - <string name="LSLTipText_llSleep">llSleep(float sec)\nPut script to sleep for sec seconds</string> - <string name="LSLTipText_llGetMass">float llGetMass()\nGet the mass of task name that script is attached to</string> - <string name="LSLTipText_llCollisionFilter">llCollisionFilter(string name, key id, integer accept)\nif accept == TRUE, only accept collisions with objects name and id (either is optional), otherwise with objects not name or id</string> - <string name="LSLTipText_llTakeControls">llTakeControls(integer controls, integer accept, integer pass_on)\nTake controls from agent task has permissions for. If (accept == (controls & input)), send input to task. If pass_on send to agent also.</string> - <string name="LSLTipText_llReleaseControls">llReleaseControls()\nStop taking inputs</string> - <string name="LSLTipText_llAttachToAvatar">llAttachToAvatar(integer attachment)\nAttach to avatar task has permissions for at point attachment</string> - <string name="LSLTipText_llDetachFromAvatar">llDetachFromAvatar()\nDrop off of avatar</string> - <string name="LSLTipText_llTakeCamera">llTakeCamera(key avatar)\nMove avatar's viewpoint to task</string> - <string name="LSLTipText_llReleaseCamera">llReleaseCamera(key avatar)\nReturn camera to agent</string> - <string name="LSLTipText_llGetOwner">key llGetOwner()\nReturns the owner of the task</string> - <string name="LSLTipText_llInstantMessage">llInstantMessage(key user, string message)\nIMs message to the user</string> - <string name="LSLTipText_llEmail">llEmail(string address, string subject, string message)\nSends email to address with subject and message</string> - <string name="LSLTipText_llGetNextEmail">llGetNextEmail(string address, string subject)\nGet the next waiting email with appropriate address and/or subject (if blank they are ignored)</string> - <string name="LSLTipText_llGetKey">key llGetKey()\nGet the key for the task the script is attached to</string> - <string name="LSLTipText_llSetBuoyancy">llSetBuoyancy(float buoyancy)\nSet the tasks buoyancy (0 is none, < 1.0 sinks, 1.0 floats, > 1.0 rises)</string> - <string name="LSLTipText_llSetHoverHeight">llSetHoverHeight(float height, integer water, float tau)\nCritically damps to a height (either above ground level or above the higher of land and water if water == TRUE)</string> - <string name="LSLTipText_llStopHover">llStopHover()\nStop hovering to a height</string> - <string name="LSLTipText_llMinEventDelay">llMinEventDelay(float delay)\nSet the minimum time between events being handled</string> - <string name="LSLTipText_llSoundPreload">llSoundPreload(string sound)\npreloads a sound on viewers within range</string> - <string name="LSLTipText_llRotLookAt">llRotLookAt(rotation target, F32 strength, F32 damping)\nCause object name to point it's forward axis towards target</string> - <string name="LSLTipText_llStringLength">integer llStringLength(string str)\nReturns the length of string</string> - <string name="LSLTipText_llStartAnimation">llStartAnimation(string anim)\nStart animation anim for agent that owns object</string> - <string name="LSLTipText_llStopAnimation">llStopAnimation(string anim)\nStop animation anim for agent that owns object</string> - <string name="LSLTipText_llPointAt">llPointAt(vector pos)\nMake agent that owns object point at pos</string> - <string name="LSLTipText_llStopPointAt">llStopPointAt()\nStop agent that owns object pointing</string> - <string name="LSLTipText_llTargetOmega">llTargetOmega(vector axis, float spinrate, float gain)\nAttempt to spin at spinrate with strength gain</string> - <string name="LSLTipText_llGetStartParameter">integer llGetStartParameter()\nGet's the start paramter passed to llRezObject</string> - <string name="LSLTipText_llGodLikeRezObject">llGodLikeRezObject(key inventory, vector pos)\nrez directly off of a UUID if owner has dog-bit set</string> - <string name="LSLTipText_llRequestPermissions">llRequestPermissions(key agent, integer perm)\nask agent to allow the script to do perm (NB: Debit, ownership, link, joint, and permission requests can only go to the task's owner)</string> - <string name="LSLTipText_llGetPermissionsKey">key llGetPermissionsKey()\nReturn agent that permissions are enabled for. NULL_KEY if not enabled</string> - <string name="LSLTipText_llGetPermissions">integer llGetPermissions()\nreturn what permissions have been enabled</string> - <string name="LSLTipText_llGetLinkNumber">integer llGetLinkNumber()\nReturns what number in a link set the script is attached to (0 means no link, 1 the root, 2 for first child, etc)</string> - <string name="LSLTipText_llSetLinkColor">llSetLinkColor(integer linknumber, vector color, integer face)\nIf a task exists in the link chain at linknumber, set face to color</string> - <string name="LSLTipText_llCreateLink">llCreateLink(key target, integer parent)\nAttempt to link task script is attached to and target (requires permission PERMISSION_CHANGE_LINKS be set). If parent == TRUE, task script is attached to is the root</string> - <string name="LSLTipText_llBreakLink">llBreakLink(integer linknum)\nDelinks the task with the given link number (requires permission PERMISSION_CHANGE_LINKS be set)</string> - <string name="LSLTipText_llBreakAllLinks">llBreakAllLinks()\nDelinks all tasks in the link set (requires permission PERMISSION_CHANGE_LINKS be set)</string> - <string name="LSLTipText_llGetLinkKey">key llGetLinkKey(integer linknum)\nGet the key of linknumber in link set</string> - <string name="LSLTipText_llGetLinkName">string llGetLinkName(integer linknum)\nGet the name of linknumber in link set</string> - <string name="LSLTipText_llGetInventoryNumber">integer llGetInventoryNumber(integer type)\nGet the number of items of a given type in the task's inventory.\nValid types: INVENTORY_TEXTURE, INVENTORY_SOUND, INVENTORY_OBJECT, INVENTORY_SCRIPT, INVENTORY_CLOTHING, INVENTORY_BODYPART, INVENTORY_NOTECARD, INVENTORY_LANDMARK, INVENTORY_ALL</string> - <string name="LSLTipText_llGetInventoryName">string llGetInventoryName(integer type, integer number)\nGet the name of the inventory item number of type</string> - <string name="LSLTipText_llSetScriptState">llSetScriptState(string name, integer run)\nControl the state of a script name.</string> - <string name="LSLTipText_llGetEnergy">float llGetEnergy()\nReturns how much energy is in the object as a percentage of maximum</string> - <string name="LSLTipText_llGiveInventory">llGiveInventory(key destination, string inventory)\nGive inventory to destination</string> - <string name="LSLTipText_llRemoveInventory">llRemoveInventory(string inventory)\nRemove the named inventory item</string> - <string name="LSLTipText_llSetText">llSetText(string text, vector color, float alpha)\nSet text floating over object</string> - <string name="LSLTipText_llWater">float llWater(vector v)\nreturns the water height below the object position + v</string> - <string name="LSLTipText_llPassTouches">llPassTouches(integer pass)\nif pass == TRUE, touches are passed from children on to parents (default is FALSE)</string> - <string name="LSLTipText_llRequestAgentData">key llRequestAgentData(key id, integer data)\nRequests data about agent id. When data is available the dataserver event will be raised</string> - <string name="LSLTipText_llRequestInventoryData">key llRequestInventoryData(string name)\nRequests data from object's inventory object. When data is available the dataserver event will be raised</string> - <string name="LSLTipText_llSetDamage">llSetDamage(float damage)\nSets the amount of damage that will be done to an object that this task hits. Task will be killed.</string> - <string name="LSLTipText_llTeleportAgentHome">llTeleportAgentHome(key id)\nTeleports agent on owner's land to agent's home location</string> - <string name="LSLTipText_llModifyLand">llModifyLand(integer action, integer size)\nModify land with action (LAND_LEVEL, LAND_RAISE, LAND_LOWER, LAND_SMOOTH, LAND_NOISE, LAND_REVERT)\non size (LAND_SMALL_BRUSH, LAND_MEDIUM_BRUSH, LAND_LARGE_BRUSH)</string> - <string name="LSLTipText_llCollisionSound">llCollisionSound(string impact_sound, float impact_volume)\nSuppress default collision sounds, replace default impact sounds with impact_sound (empty string to just suppress)</string> - <string name="LSLTipText_llCollisionSprite">llCollisionSprite(string impact_sprite)\nSuppress default collision sprites, replace default impact sprite with impact_sprite (empty string to just suppress)</string> - <string name="LSLTipText_llGetAnimation">string llGetAnimation(key id)\nGet the currently playing locomotion animation for avatar id</string> - <string name="LSLTipText_llResetScript">llResetScript()\nResets the script</string> - <string name="LSLTipText_llMessageLinked">llMessageLinked(integer linknum, integer num, string str, key id)\nSends num, str, and id to members of the link set (LINK_ROOT sends to root task in a linked set,\nLINK_SET sends to all tasks,\nLINK_ALL_OTHERS to all other tasks,\nLINK_ALL_CHILDREN to all children,\nLINK_THIS to the task the script it is in)</string> - <string name="LSLTipText_llPushObject">llPushObject(key id, vector impulse, vector ang_impulse, integer local)\nApplies impulse and ang_impulse to object id</string> - <string name="LSLTipText_llPassCollisions">llPassCollisions(integer pass)\nif pass == TRUE, collisions are passed from children on to parents (default is FALSE)</string> - <string name="LSLTipText_llGetScriptName">llGetScriptName()\nReturns the script name</string> - <string name="LSLTipText_llGetNumberOfSides">integer llGetNumberOfSides()\nReturns the number of sides</string> - <string name="LSLTipText_llAxisAngle2Rot">rotation llAxisAngle2Rot(vector axis, float angle)\nReturns the rotation generated angle about axis</string> - <string name="LSLTipText_llRot2Axis">vector llRot2Axis(rotation rot)\nReturns the rotation axis represented by rot</string> - <string name="LSLTipText_llRot2Angle">float llRot2Angle(rotation rot)\nReturns the rotation angle represented by rot</string> - <string name="LSLTipText_llAcos">float llAcos(float val)\nReturns the arccosine in radians of val</string> - <string name="LSLTipText_llAsin">float llAsin(float val)\nReturns the arcsine in radians of val</string> - <string name="LSLTipText_llAngleBetween">float llAngleBetween(rotation a, rotation b)\nReturns angle between rotation a and b</string> - <string name="LSLTipText_llGetInventoryKey">key llGetInventoryKey(string name)\nReturns the key of the inventory name</string> - <string name="LSLTipText_llAllowInventoryDrop">llAllowInventoryDrop(integer add)\nIf add == TRUE, users without permissions can still drop inventory items onto task</string> - <string name="LSLTipText_llGetSunDirection">vector llGetSunDirection()\nReturns the sun direction on the simulator</string> - <string name="LSLTipText_llGetTextureOffset">vector llGetTextureOffset(integer side)\nReturns the texture offset of side in the x and y components of a vector</string> - <string name="LSLTipText_llGetTextureScale">vector llGetTextureScale(integer side)\nReturns the texture scale of side in the x and y components of a vector</string> - <string name="LSLTipText_llGetTextureRot">float llGetTextureRot(integer side)\nReturns the texture rotation of side</string> - <string name="LSLTipText_llSubStringIndex">integer llSubStringIndex(string source, string pattern)\nFinds index in source where pattern first appears (returns -1 if not found)</string> - <string name="LSLTipText_llGetOwnerKey">key llGetOwnerKey(key id)\nFind the owner of id</string> - <string name="LSLTipText_llGetCenterOfMass">vector llGetCenterOfMass()\nGet the object's center of mass</string> - <string name="LSLTipText_llListSort">list llListSort(list src, integer stride, integer ascending)\nSort the list into blocks of stride in ascending order if ascending == TRUE. Note that sort only works between same types.</string> - <string name="LSLTipText_llGetListLength">integer llGetListLength(list src)\nGet the number of elements in the list</string> - <string name="LSLTipText_llList2Integer">integer llList2Integer(list src, integer index)\nCopy the integer at index in the list</string> - <string name="LSLTipText_llList2Float">float llList2Float(list src, integer index)\nCopy the float at index in the list</string> - <string name="LSLTipText_llList2String">string llList2String(list src, integer index)\nCopy the string at index in the list</string> - <string name="LSLTipText_llList2Key">key llList2Key(list src, integer index)\nCopy the key at index in the list</string> - <string name="LSLTipText_llList2Vector">vector llList2Vector(list src, integer index)\nCopy the vector at index in the list</string> - <string name="LSLTipText_llList2Rot">rotation llList2Rot(list src, integer index)\nCopy the rotation at index in the list</string> - <string name="LSLTipText_llList2List">list llList2List(list src, integer start, integer end)\nCopy the slice of the list from start to end</string> - <string name="LSLTipText_llDeleteSubList">list llDeleteSubList(list src, integer start, integer end)\nRemove the slice from the list and return the remainder</string> - <string name="LSLTipText_llGetListEntryType">integer llGetListEntryType(list src, integer index)\nReturns the type of the index entry in the list\n(TYPE_INTEGER, TYPE_FLOAT, TYPE_STRING, TYPE_KEY, TYPE_VECTOR, TYPE_ROTATION, or TYPE_INVALID if index is off list)</string> - <string name="LSLTipText_llList2CSV">string llList2CSV(list src)\nCreate a string of comma separated values from list</string> - <string name="LSLTipText_llCSV2List">list llCSV2List(string src)\nCreate a list from a string of comma separated values</string> - <string name="LSLTipText_llListRandomize">list llListRandomize(list src, integer stride)\nReturns a randomized list of blocks of size stride</string> - <string name="LSLTipText_llList2ListStrided">list llList2ListStrided(list src, integer start, integer end, integer stride)\nCopy the strided slice of the list from start to end</string> - <string name="LSLTipText_llGetRegionCorner">vector llGetRegionCorner()\nReturns a vector with the south west corner x,y position of the region the object is in</string> - <string name="LSLTipText_llListInsertList">list llListInsertList(list dest, list src, integer start)\nInserts src into dest at position start</string> - <string name="LSLTipText_llListFindList">integer llListFindList(list src, list test)\nReturns the start of the first instance of test in src, -1 if not found</string> - <string name="LSLTipText_llGetObjectName">string llGetObjectName()\nReturns the name of the object script is attached to</string> - <string name="LSLTipText_llSetObjectName">llSetObjectName(string name)\nSets the objects name</string> - <string name="LSLTipText_llGetDate">string llGetDate()\nGets the date as YYYY-MM-DD</string> - <string name="LSLTipText_llEdgeOfWorld">integer llEdgeOfWorld(vector pos, vector dir)\nChecks to see whether the border hit by dir from pos is the edge of the world (has no neighboring simulator)</string> - <string name="LSLTipText_llGetAgentInfo">integer llGetAgentInfo(key id)\nGets information about agent ID.\nReturns AGENT_FLYING, AGENT_ATTACHMENTS, AGENT_SCRIPTED, AGENT_SITTING, AGENT_ON_OBJECT, AGENT_MOUSELOOK, AGENT_AWAY, AGENT_BUSY, AGENT_TYPING, AGENT_CROUCHING, AGENT_ALWAYS_RUN, AGENT_WALKING and/or AGENT_IN_AIR.</string> - <string name="LSLTipText_llAdjustSoundVolume">llAdjustSoundVolume(float volume)\nadjusts volume of attached sound (0.0 - 1.0)</string> - <string name="LSLTipText_llSetSoundQueueing">llSetSoundQueueing(integer queue)\ndetermines whether attached sound calls wait for the current sound to finish (0 = no [default], nonzero = yes)</string> - <string name="LSLTipText_llSetSoundRadius">llSetSoundRadius(float radius)\nestablishes a hard cut-off radius for audibility of scripted sounds (both attached and triggered)</string> - <string name="LSLTipText_llKey2Name">string llKey2Name(key id)\nReturns the name of the object key, iff the object is in the current simulator, otherwise the empty string</string> - <string name="LSLTipText_llSetTextureAnim">llSetTextureAnim(integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate)\nAnimate the texture on the specified face/faces</string> - <string name="LSLTipText_llTriggerSoundLimited">llTriggerSoundLimited(string sound, float volume, vector tne, vector bsw)\nplays sound at volume (0.0 - 1.0), centered at but not attached to object, limited to AABB defined by vectors top-north-east and bottom-south-west</string> - <string name="LSLTipText_llEjectFromLand">llEjectFromLand(key pest)\nEjects pest from land that you own</string> - <string name="LSLTipText_llParseString2List">list llParseString2List(string src, list separators, list spacers)\nBreaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each)</string> - <string name="LSLTipText_llOverMyLand">integer llOverMyLand(key id)\nReturns TRUE if id is over land owner of object owns, FALSE otherwise</string> - <string name="LSLTipText_llGetLandOwnerAt">key llGetLandOwnerAt(vector pos)\nReturns the key of the land owner, NULL_KEY if public</string> - <string name="LSLTipText_llGetNotecardLine">key llGetNotecardLine(string name, integer line)\nReturns line line of notecard name via the dataserver event</string> - <string name="LSLTipText_llGetAgentSize">vector llGetAgentSize(key id)\nIf the agent is in the same sim as the object, returns the size of the avatar</string> - <string name="LSLTipText_llSameGroup">integer llSameGroup(key id)\nReturns TRUE if ID is in the same sim and has the same active group, otherwise FALSE</string> - <string name="LSLTipText_llUnSit">key llUnSit(key id)\nIf agent identified by id is sitting on the object the script is attached to or is over land owned by the objects owner, the agent is forced to stand up</string> - <string name="LSLTipText_llGroundSlope">vector llGroundSlope(vector v)\nreturns the ground slope below the object position + v</string> - <string name="LSLTipText_llGroundNormal">vector llGroundNormal(vector v)\nreturns the ground normal below the object position + v</string> - <string name="LSLTipText_llGroundContour">vector llGroundCountour(vector v)\nreturns the ground contour below the object position + v</string> - <string name="LSLTipText_llGetAttached">integer llGetAttached()\nreturns the object attachment point or 0 if not attached</string> - <string name="LSLTipText_llGetFreeMemory">integer llGetFreeMemory()\nreturns the available heap space for the current script</string> - <string name="LSLTipText_llGetRegionName">string llGetRegionName()\nreturns the current region name</string> - <string name="LSLTipText_llGetRegionTimeDilation">float llGetRegionTimeDilation()\nreturns the current time dilation as a float between 0 and 1</string> - <string name="LSLTipText_llGetRegionFPS">float llGetRegionFPS()\nreturns the mean region frames per second</string> - <string name="LSLTipText_llParticleSystem">llParticleSystem(list rules)\nCreates a particle system based on rules. Empty list removes particle system from object.\nList format is [ rule1, data1, rule2, data2 . . . rulen, datan ]</string> - <string name="LSLTipText_llGroundRepel">llGroundRepel(float height, integer water, float tau)\nCritically damps to height if within height*0.5 of level (either above ground level or above the higher of land and water if water == TRUE)</string> - <string name="LSLTipText_llGiveInventoryList">llGiveInventoryList(key destination, string category, list inventory)\nGive inventory to destination in a new category</string> - <string name="LSLTipText_llSetVehicleType">llSetVehicleType(integer type)\nsets vehicle to one of the default types</string> - <string name="LSLTipText_llSetVehicleFloatParam">llSetVehicleFloatParam(integer param, float value)\nsets the specified vehicle float parameter</string> - <string name="LSLTipText_llSetVehicleVectorParam">llSetVehicleVectorParam(integer param, vector vec)\nsets the specified vehicle vector parameter</string> - <string name="LSLTipText_llSetVehicleRotationParam">llSetVehicleVectorParam(integer param, rotation rot)\nsets the specified vehicle rotation parameter</string> - <string name="LSLTipText_llSetVehicleFlags">llSetVehicleFlags(integer flags)\nsets the enabled bits in 'flags'</string> - <string name="LSLTipText_llRemoveVehicleFlags">llRemoveVehicleFlags(integer flags)\nremoves the enabled bits in 'flags'</string> - <string name="LSLTipText_llSitTarget">llSitTarget(vector offset, rotation rot)\nSet the sit location for this object (if offset == <0,0,0> clear it)</string> - <string name="LSLTipText_llAvatarOnSitTarget">key llAvatarOnSitTarget()\nIf an avatar is sitting on the sit target, return the avatar's key, NULL_KEY otherwise</string> - <string name="LSLTipText_llAddToLandPassList">llAddToLandPassList(key avatar, float hours)\nAdd avatar to the land pass list for hours</string> - <string name="LSLTipText_llSetTouchText">llSetTouchText(string text)\nDisplays text in pie menu that acts as a touch</string> - <string name="LSLTipText_llSetSitText">llSetSitText(string text)\nDisplays text rather than sit in pie menu</string> - <string name="LSLTipText_llSetCameraEyeOffset">llSetCameraEyeOffset(vector offset)\nSets the camera eye offset used in this object if an avatar sits on it</string> - <string name="LSLTipText_llSetCameraAtOffset">llSetCameraAtOffset(vector offset)\nSets the camera at offset used in this object if an avatar sits on it</string> - <string name="LSLTipText_llDumpList2String">string llDumpList2String(list src, string separator)\nWrite the list out in a single string using separator between values</string> - <string name="LSLTipText_llScriptDanger">integer llScriptDanger(vector pos)\nReturns true if pos is over public land, sandbox land, land that doesn't allow everyone to edit and build, or land that doesn't allow outside scripts</string> - <string name="LSLTipText_llDialog">llDialog(key avatar, string message, list buttons, integer chat_channel\nShows a dialog box on the avatar's screen with the message.\nUp to 12 strings in the list form buttons.\nIf a button is clicked, the name is chatted on chat_channel.</string> - <string name="LSLTipText_llVolumeDetect">llVolumeDetect(integer detect)\nIf detect = TRUE, object becomes phantom but triggers collision_start and collision_end events\nwhen other objects start and stop interpenetrating.\nMust be applied to the root object.</string> - <string name="LSLTipText_llResetOtherScript">llResetOtherScript(string name)\nResets script name</string> - <string name="LSLTipText_llGetScriptState">integer llGetScriptState(string name)\nResets TRUE if script name is running</string> - <string name="LSLTipText_llRemoteLoadScript">Deprecated. Please use llRemoteLoadScriptPin instead.</string> - <string name="LSLTipText_llSetRemoteScriptAccessPin">llSetRemoteScriptAccessPin(integer pin)\nIf pin is set to a non-zero number, the task will accept remote script\nloads via llRemoteLoadScriptPin if it passes in the correct pin.\nOthersise, llRemoteLoadScriptPin is ignored.</string> - <string name="LSLTipText_llRemoteLoadScriptPin">llRemoteLoadScriptPin(key target, string name, integer pin, integer running, integer start_param)\nIf the owner of the object this script is attached can modify target,\nthey are in the same region,\nand the matching pin is used,\ncopy script name onto target,\nif running == TRUE, start the script with param.</string> - <string name="LSLTipText_llOpenRemoteDataChannel">llOpenRemoteDataChannel()\nCreates a channel to listen for XML-RPC calls. Will trigger a remote_data event with channel id once it is available.</string> - <string name="LSLTipText_llSendRemoteData">key llSendRemoteData(key channel, string dest, integer idata, string sdata)\nSend an XML-RPC request to dest through channel with payload of channel (in a string), integer idata and string sdata.\nA message identifier key is returned.\nAn XML-RPC reply will trigger a remote_data event and reference the message id.\nThe message_id is returned.</string> - <string name="LSLTipText_llRemoteDataReply">llRemoteDataReply(key channel, key message_id, string sdata, integer idata)\nSend an XML-RPC reply to message_id on channel with payload of string sdata and integer idata</string> - <string name="LSLTipText_llCloseRemoteDataChannel">llCloseRemoteDataChannel(key channel)\nCloses XML-RPC channel.</string> - <string name="LSLTipText_llMD5String">string llMD5String(string src, integer nonce)\nPerforms a RSA Data Security, Inc. MD5 Message-Digest Algorithm on string with nonce. Returns a 32 character hex string.</string> - <string name="LSLTipText_llSetPrimitiveParams">llSetPrimitiveParams(list rules)\nSet primitive parameters based on rules.</string> - <string name="LSLTipText_llStringToBase64">string llStringToBase64(string str)\nConverts a string to the Base 64 representation of the string.</string> - <string name="LSLTipText_llBase64ToString">string llBase64ToString(string str)\nConverts a Base 64 string to a conventional string. If the conversion creates any unprintable characters, they are converted to spaces.</string> - <string name="LSLTipText_llXorBase64Strings">string llXorBase64Strings(string s1, string s2)\nDEPRECATED! Please use llXorBase64StringsCorrect instead!! Incorrectly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. Retained for backwards compatability.</string> - <string name="LSLTipText_llRemoteDataSetRegion">llRemoteDataSetRegion()\nIf an object using remote data channels changes regions, you must call this function to reregister the remote data channels.\nYou do not need to make this call if you don't change regions.</string> - <string name="LSLTipText_llLog10">float llLog10(float val)\nReturns the base 10 log of val if val > 0, otherwise returns 0.</string> - <string name="LSLTipText_llLog">float llLog(float val)\nReturns the base e log of val if val > 0, otherwise returns 0.</string> - <string name="LSLTipText_llGetAnimationList">list llGetAnimationList(key id)\nGets a list of all playing animations for avatar id</string> - <string name="LSLTipText_llSetParcelMusicURL">llSetParcelMusicURL(string url)\nSets the streaming audio URL for the parcel object is on</string> - <string name="LSLTipText_llGetRootPosition">vector llGetRootPosition()\nGets the global position of the root object of the object script is attached to</string> - <string name="LSLTipText_llGetRootRotation">rotation llGetRootRotation()\nGets the global rotation of the root object of the object script is attached to</string> - <string name="LSLTipText_llGetObjectDesc">string llGetObjectDesc()\nReturns the description of the object the script is attached to</string> - <string name="LSLTipText_llSetObjectDesc">llSetObjectDesc(string name)\nSets the object's description</string> - <string name="LSLTipText_llGetCreator">key llGetCreator()\nReturns the creator of the object</string> - <string name="LSLTipText_llGetTimestamp">string llGetTimestamp()\nGets the timestamp in the format: YYYY-MM-DDThh:mm:ss.ff..fZ</string> - <string name="LSLTipText_llSetLinkAlpha">llSetLinkAlpha(integer linknumber, float alpha, integer face)\nIf a prim exists in the link chain at linknumber, set face to alpha</string> - <string name="LSLTipText_llGetNumberOfPrims">integer llGetNumberOfPrims()\nReturns the number of prims in a link set the script is attached to</string> - <string name="LSLTipText_llGetNumberOfNotecardLines">key llGetNumberOfNotecardLines(string name)\nReturns number of lines in notecard 'name' via the dataserver event (cast return value to integer)</string> - <string name="LSLTipText_llGetBoundingBox">list llGetBoundingBox(key object)\nReturns the bounding box around an object (including any linked prims) relative to the root prim, in a list: [ (vector) min_corner, (vector) max_corner ]</string> - <string name="LSLTipText_llGetGeometricCenter">vector llGetGeometricCenter()\nReturns the geometric center of the linked set the script is attached to.</string> - <string name="LSLTipText_llGetPrimitiveParams">list llGetPrimitiveParams(list params)\nGets primitive parameters specified in the params list.</string> - <string name="LSLTipText_llIntegerToBase64">string llIntegerToBase64(integer number)\nBig endian encode of of integer as a Base64 string.</string> - <string name="LSLTipText_llBase64ToInteger">integer llBase64ToInteger(string str)\nBig endian decode of a Base64 string into an integer.</string> - <string name="LSLTipText_llGetGMTclock">float llGetGMTclock()\nGets the time in seconds since midnight in GMT</string> - <string name="LSLTipText_llGetSimulatorHostname">string llGetSimulatorHostname()\nGets the hostname of the machine script is running on (same as string in viewer Help dialog)</string> - <string name="LSLTipText_llSetLocalRot">llSetLocalRot(rotation rot)\nsets the rotation of a child prim relative to the root prim</string> - <string name="LSLTipText_llParseStringKeepNulls">list llParseStringKeepNulls(string src, list separators, list spacers)\nBreaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each), keeping any null values generated.</string> - <string name="LSLTipText_llRezAtRoot">llRezAtRoot(string inventory, vector pos, vector vel, rotation rot, integer param)\nInstantiate owner's inventory object at pos with velocity vel and rotation rot with start parameter param.\nThe last selected root object's location will be set to pos</string> - <string name="LSLTipText_llGetObjectPermMask">integer llGetObjectPermMask(integer mask)\nReturns the requested permission mask for the root object the task is attached to.</string> - <string name="LSLTipText_llSetObjectPermMask">llSetObjectPermMask(integer mask, integer value)\nSets the given permission mask to the new value on the root object the task is attached to.</string> - <string name="LSLTipText_llGetInventoryPermMask">integer llGetInventoryPermMask(string item, integer mask)\nReturns the requested permission mask for the inventory item.</string> - <string name="LSLTipText_llSetInventoryPermMask">llSetInventoryPermMask(string item, integer mask, integer value)\nSets the given permission mask to the new value on the inventory item.</string> - <string name="LSLTipText_llGetInventoryCreator">key llGetInventoryCreator(string item)\nReturns the key for the creator of the inventory item.</string> - <string name="LSLTipText_llOwnerSay">llOwnerSay(string msg)\nsays msg to owner only (if owner in sim)</string> - <string name="LSLTipText_llRequestSimulatorData">key llRequestSimulatorData(string simulator, integer data)\nRequests data about simulator. When data is available the dataserver event will be raised</string> - <string name="LSLTipText_llForceMouselook">llForceMouselook(integer mouselook)\nIf mouselook is TRUE any avatar that sits on this object is forced into mouselook mode</string> - <string name="LSLTipText_llGetObjectMass">float llGetObjectMass(key id)\nGet the mass of the object with key id</string> - <string name="LSLTipText_llListReplaceList">list llListReplaceList(list dest, list src, integer start, integer end)\nReplaces start through end of dest with src.</string> - <string name="LSLTipText_llLoadURL">llLoadURL(key avatar_id, string message, string url)\nShows dialog to avatar avatar_id offering to load web page at URL. If user clicks yes, launches their web browser.</string> - <string name="LSLTipText_llParcelMediaCommandList">llParcelMediaCommandList(list command)\nSends a list of commands, some with arguments, to a parcel.</string> - <string name="LSLTipText_llParcelMediaQuery">list llParcelMediaQuery(list query)\nSends a list of queries, returns a list of results.</string> - <string name="LSLTipText_llModPow">integer llModPow(integer a, integer b, integer c)\nReturns a raised to the b power, mod c. ( (a**b)%c ). b is capped at 0xFFFF (16 bits).</string> - <string name="LSLTipText_llGetInventoryType">integer llGetInventoryType(string name)\nReturns the type of the inventory name</string> - <string name="LSLTipText_llSetPayPrice">llSetPayPrice(integer price, list quick_pay_buttons)\nSets the default amount when someone chooses to pay this object.</string> - <string name="LSLTipText_llGetCameraPos">vector llGetCameraPos()\nGets current camera position for agent task has permissions for.</string> - <string name="LSLTipText_llGetCameraRot">rotation llGetCameraRot()\nGets current camera orientation for agent task has permissions for.</string> - <string name="LSLTipText_llSetPrimURL">llSetPrimURL(string url)\nUpdates the URL for the web page shown on the sides of the object.</string> - <string name="LSLTipText_llRefreshPrimURL">llRefreshPrimURL()\nReloads the web page shown on the sides of the object.</string> - <string name="LSLTipText_llEscapeURL">string llEscapeURL(string url)\nReturns and escaped/encoded version of url, replacing spaces with %20 etc.</string> - <string name="LSLTipText_llUnescapeURL">string llUnescapeURL(string url)\nReturns and unescaped/unencoded version of url, replacing %20 with spaces etc.</string> - <string name="LSLTipText_llMapDestination">llMapDestination(string simname, vector pos, vector look_at)\nOpens world map centered on region with pos highlighted.\nOnly works for scripts attached to avatar, or during touch events.\n(NOTE: look_at currently does nothing)</string> - <string name="LSLTipText_llAddToLandBanList">llAddToLandBanList(key avatar, float hours)\nAdd avatar to the land ban list for hours</string> - <string name="LSLTipText_llRemoveFromLandPassList">llRemoveFromLandPassList(key avatar)\nRemove avatar from the land pass list</string> - <string name="LSLTipText_llRemoveFromLandBanList">llRemoveFromLandBanList(key avatar)\nRemove avatar from the land ban list</string> - <string name="LSLTipText_llSetCameraParams">llSetCameraParams(list rules)\nSets multiple camera parameters at once.\nList format is [ rule1, data1, rule2, data2 . . . rulen, datan ]</string> - <string name="LSLTipText_llClearCameraParams">llClearCameraParams()\nResets all camera parameters to default values and turns off scripted camera control.</string> - <string name="LSLTipText_llListStatistics">float llListStatistics(integer operation, list l)\nPerform statistical aggregate functions on list l using LIST_STAT_* operations.</string> - <string name="LSLTipText_llGetUnixTime">integer llGetUnixTime()\nGet the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC from the system clock.</string> - <string name="LSLTipText_llGetParcelFlags">integer llGetParcelFlags(vector pos)\nGet the parcel flags (PARCEL_FLAG_*) for the parcel including the point pos.</string> - <string name="LSLTipText_llGetRegionFlags">integer llGetRegionFlags()\nGet the region flags (REGION_FLAG_*) for the region the object is in.</string> - <string name="LSLTipText_llXorBase64StringsCorrect">string llXorBase64StringsCorrect(string s1, string s2)\nCorrectly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1.</string> - <string name="LSLTipText_llHTTPRequest">llHTTPRequest(string url, list parameters, string body)\nSend an HTTP request.</string> - <string name="LSLTipText_llResetLandBanList">llResetLandBanList()\nRemoves all residents from the land ban list.</string> - <string name="LSLTipText_llResetLandPassList">llResetLandPassList()\nRemoves all residents from the land access/pass list.</string> - <string name="LSLTipText_llGetObjectPrimCount">integer llGetObjectPrimCount(key object_id)\nReturns the total number of prims for an object.</string> - <string name="LSLTipText_llGetParcelPrimOwners">list llGetParcelPrimOwners(vector pos)\nReturns a list of all residents who own objects on the parcel and the number of objects they own.\nRequires owner-like permissions for the parcel.</string> - <string name="LSLTipText_llGetParcelPrimCount">integer llGetParcelPrimCount(vector pos, integer category, integer sim_wide)\nGets the number of prims on the parcel of the given category.\nCategories: PARCEL_COUNT_TOTAL, _OWNER, _GROUP, _OTHER, _SELECTED, _TEMP.</string> - <string name="LSLTipText_llGetParcelMaxPrims">integer llGetParcelMaxPrims(vector pos, integer sim_wide)\nGets the maximum number of prims allowed on the parcel at pos.</string> - <string name="LSLTipText_llGetParcelDetails">list llGetParcelDetails(vector pos, list params)\nGets the parcel details specified in params for the parcel at pos.\nParams is one or more of: PARCEL_DETAILS_NAME, _DESC, _OWNER, _GROUP, _AREA</string> - <string name="LSLTipText_llSetLinkPrimitiveParams">llSetLinkPrimitiveParams(integer linknumber, list rules)\nSet primitive parameters for linknumber based on rules.</string> - <string name="LSLTipText_llSetLinkTexture">llSetLinkTexture(integer link_pos, string texture, integer face)\nSets the texture of face for link_pos</string> - <string name="LSLTipText_llStringTrim">string llStringTrim(string src, integer trim_type)\nTrim leading and/or trailing spaces from a string.\nUses trim_type of STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL.</string> - <string name="LSLTipText_llRegionSay">llRegionSay(integer channel, string msg)\nbroadcasts msg to entire region on channel (not 0.)</string> - <string name="LSLTipText_llGetObjectDetails">list llGetObjectDetails(key id, list params)\nGets the object details specified in params for the object with key id.\nDetails are OBJECT_NAME, _DESC, _POS, _ROT, _VELOCITY, _OWNER, _GROUP, _CREATOR.</string> - <string name="LSLTipText_llSetClickAction">llSetClickAction(integer action)\nSets the action performed when a prim is clicked upon.</string> - <string name="LSLTipText_llGetRegionAgentCount">int llGetRegionAgentCount()\nreturns the number of agents in a region</string> - <string name="LSLTipText_llTextBox">llTextBox(key avatar, string message, integer chat_channel\nShows a dialog box on the avatar's screen with the message.\nA text box asks for input, and if entered the text is chatted on chat_channel.</string> - <string name="LSLTipText_llGetAgentLanguage">string llGetAgentLanguage(key id)\nGets the agents preferred language..</string> - <string name="LSLTipText_llDetectedTouchUV">vector llDetectedTouchUV(integer number)\nreturns the u and v coordinates in the first two components of a vector, for a triggered touch event</string> - <string name="LSLTipText_llDetectedTouchFace">integer llDetectedTouchFace(integer number)\nreturns the index of the face on the object for a triggered touch event</string> - <string name="LSLTipText_llDetectedTouchPos">vector llDetectedTouchPos(integer number)\nreturns the position touched for a triggered touch event</string> - <string name="LSLTipText_llDetectedTouchNormal">vector llDetectedTouchNormal(integer number)\nreturns the surface normal for a triggered touch event</string> - <string name="LSLTipText_llDetectedTouchBinormal">vector llDetectedTouchBinormal(integer number)\nreturns the surface binormal for a triggered touch event</string> - <string name="LSLTipText_llDetectedTouchST">vector llDetectedTouchST(integer number)\nreturns the s and t coordinates in the first two components of a vector, for a triggered touch event</string> - <string name="LSLTipText_llSHA1String">string llSHA1String(string sr)\nPerforms a SHA1 security Hash. Returns a 40 character hex string.</string> - <string name="LSLTipText_llGetFreeURLs">integer llGetFreeURLs()\nreturns the available urls for the current script</string> - <string name="LSLTipText_llRequestURL">key llRequestURL()\nRequests one HTTP:// url for use by this object\nTriggers an http_server event with results.</string> - <string name="LSLTipText_llRequestSecureURL">key llRequestSecureURL()\nRequests one HTTPS:// (SSL) url for use by this object\nTriggers an http_server event with results.</string> - <string name="LSLTipText_llReleaseURL">llReleaseURL(string url)\nReleases the specified URL, it will no longer be usable.</string> - <string name="LSLTipText_llHTTPResponse">llHTTPResponse(key id, integer status, string body)\nResponds to request id with status and body.</string> - <string name="LSLTipText_llGetHTTPHeader">string llGetHTTPHeader(key id, string header)\nGet the value for header for request id.</string> + <string name="LSLTipText_llSin"> +float llSin(float theta) +theta in radians + </string> + <string name="LSLTipText_llCos"> +float llCos(float theta) +theta in radians + </string> + <string name="LSLTipText_llTan"> +float llTan(float theta) +theta radians + </string> + <string name="LSLTipText_llAtan2"> +float llAtan2(float y, float x) + </string> + <string name="LSLTipText_llSqrt"> +float llSqrt(float val) +returns 0 and triggers a Math Error for imaginary results + </string> + <string name="LSLTipText_llPow"> +float llPow(float base, float exponent) +returns 0 and triggers Math Error for imaginary results + </string> + <string name="LSLTipText_llAbs"> +integer llAbs(integer val) + </string> + <string name="LSLTipText_llFabs"> +float llFabs(float val) + </string> + <string name="LSLTipText_llFrand"> +float llFrand(float mag) +returns random number in range [0,mag) + </string> + <string name="LSLTipText_llFloor"> +integer llFloor(float val) +returns largest integer value <= val + </string> + <string name="LSLTipText_llCeil"> +integer llCeil(float val) +returns smallest integer value >= val + </string> + <string name="LSLTipText_llRound"> +integer llRound(float val) +returns val rounded to the nearest integer + </string> + <string name="LSLTipText_llVecMag"> +float llVecMag(vector v) +returns the magnitude of v + </string> + <string name="LSLTipText_llVecNorm"> +vector llVecNorm(vector v) +returns the v normalized + </string> + <string name="LSLTipText_llVecDist"> +float llVecDist(vector v1, vector v2) +returns the 3D distance between v1 and v2 + </string> + <string name="LSLTipText_llRot2Euler"> +vector llRot2Euler(rotation q) +returns the Euler representation (roll, pitch, yaw) of q + </string> + <string name="LSLTipText_llEuler2Rot"> +rotation llEuler2Rot(vector v) +returns the rotation representation of Euler Angles v + </string> + <string name="LSLTipText_llAxes2Rot"> +rotation llAxes2Rot(vector fwd, vector left, vector up) +returns the rotation defined by the coordinate axes + </string> + <string name="LSLTipText_llRot2Fwd"> +vector llRot2Fwd(rotation q) +returns the forward vector defined by q + </string> + <string name="LSLTipText_llRot2Left"> +vector llRot2Left(rotation q) +returns the left vector defined by q + </string> + <string name="LSLTipText_llRot2Up"> +vector llRot2Up(rotation q) +returns the up vector defined by q + </string> + <string name="LSLTipText_llRotBetween"> +rotation llRotBetween(vector v1, vector v2) +returns the rotation to rotate v1 to v2 + </string> + <string name="LSLTipText_llWhisper"> +llWhisper(integer channel, string msg) +whispers msg on channel + </string> + <string name="LSLTipText_llSay"> +llSay(integer channel, string msg) +says msg on channel + </string> + <string name="LSLTipText_llShout"> +llShout(integer channel, string msg) +shouts msg on channel + </string> + <string name="LSLTipText_llListen"> +integer llListen(integer channel, string name, key id, string msg) +sets a callback for msg on channel from name and id (name, id, and/or msg can be empty) and returns an identifier that can be used to deactivate or remove the listen + </string> + <string name="LSLTipText_llListenControl"> +llListenControl(integer number, integer active) +makes a listen event callback active or inactive + </string> + <string name="LSLTipText_llListenRemove"> +llListenRemove(integer number) +removes listen event callback number + </string> + <string name="LSLTipText_llSensor"> +llSensor(string name, key id, integer type, float range, float arc) +Performs a single scan for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) + </string> + <string name="LSLTipText_llSensorRepeat"> +llSensorRepeat(string name, key id, integer type, float range, float arc, float rate) +sets a callback for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) and repeats every rate seconds + </string> + <string name="LSLTipText_llSensorRemove"> +llSensorRemove() +removes sensor + </string> + <string name="LSLTipText_llDetectedName"> +string llDetectedName(integer number) +returns the name of detected object number (returns empty string if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedKey"> +key llDetectedKey(integer number) +returns the key of detected object number (returns empty key if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedOwner"> +key llDetectedOwner(integer number) +returns the key of detected object's owner (returns empty key if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedType"> +integer llDetectedType(integer number) +returns the type (AGENT, ACTIVE, PASSIVE, SCRIPTED) of detected object (returns 0 if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedPos"> +vector llDetectedPos(integer number) +returns the position of detected object number (returns <0,0,0> if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedVel"> +vector llDetectedVel(integer number) +returns the velocity of detected object number (returns <0,0,0> if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedGrab"> +vector llDetectedGrab(integer number) +returns the grab offset of the user touching object (returns <0,0,0> if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedRot"> +rotation llDetectedRot(integer number) +returns the rotation of detected object number (returns <0,0,0,1> if number is not valid sensed object) + </string> + <string name="LSLTipText_llDetectedGroup"> +integer llDetectedGroup(integer number) +Returns TRUE if detected object is part of same group as owner + </string> + <string name="LSLTipText_llDetectedLinkNumber"> +integer llDetectedLinkNumber(integer number) +returns the link position of the triggered event for touches and collisions only + </string> + <string name="LSLTipText_llDie"> +llDie() +deletes the object + </string> + <string name="LSLTipText_llGround"> +float llGround(vector v) +returns the ground height below the object position + v + </string> + <string name="LSLTipText_llCloud"> +float llCloud(vector v) +returns the cloud density at the object position + v + </string> + <string name="LSLTipText_llWind"> +vector llWind(vector v) +returns the wind velocity at the object position + v + </string> + <string name="LSLTipText_llSetStatus"> +llSetStatus(integer status, integer value) +sets status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) to value + </string> + <string name="LSLTipText_llGetStatus"> +integer llGetStatus(integer status) +gets value of status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB, STATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) + </string> + <string name="LSLTipText_llSetScale"> +llSetScale(vector scale) +sets the scale + </string> + <string name="LSLTipText_llGetScale"> +vector llGetScale() +gets the scale + </string> + <string name="LSLTipText_llSetColor"> +llSetColor(vector color, integer face) +sets the color + </string> + <string name="LSLTipText_llGetAlpha"> +float llGetAlpha(integer face) +gets the alpha + </string> + <string name="LSLTipText_llSetAlpha"> +llSetAlpha(float alpha, integer face) +sets the alpha + </string> + <string name="LSLTipText_llGetColor"> +vector llGetColor(integer face) +gets the color + </string> + <string name="LSLTipText_llSetTexture"> +llSetTexture(string texture, integer face) +sets the texture of face + </string> + <string name="LSLTipText_llScaleTexture"> +llScaleTexture(float scales, float scalet, integer face) +sets the texture s, t scales for the chosen face + </string> + <string name="LSLTipText_llOffsetTexture"> +llOffsetTexture(float offsets, float offsett, integer face) +sets the texture s, t offsets for the chosen face + </string> + <string name="LSLTipText_llRotateTexture"> +llRotateTexture(float rotation, integer face) +sets the texture rotation for the chosen face + </string> + <string name="LSLTipText_llGetTexture"> +string llGetTexture(integer face) +gets the texture of face (if it's a texture in the object inventory, otherwise the key in a string) + </string> + <string name="LSLTipText_llSetPos"> +llSetPos(vector pos) +sets the position (if the script isn't physical) + </string> + <string name="LSLTipText_llGetPos"> +vector llGetPos() +gets the position (if the script isn't physical) + </string> + <string name="LSLTipText_llGetLocalPos"> +vector llGetLocalPos() +gets the position relative to the root (if the script isn't physical) + </string> + <string name="LSLTipText_llSetRot"> +llSetRot(rotation rot) +sets the rotation (if the script isn't physical) + </string> + <string name="LSLTipText_llGetRot"> +rotation llGetRot() +gets the rotation (if the script isn't physical) + </string> + <string name="LSLTipText_llGetLocalRot"> +rotation llGetLocalRot() +gets the rotation local to the root (if the script isn't physical) + </string> + <string name="LSLTipText_llSetForce"> +llSetForce(vector force, integer local) +sets force on object, in local coords if local == TRUE (if the script is physical) + </string> + <string name="LSLTipText_llGetForce"> +vector llGetForce() +gets the force (if the script is physical) + </string> + <string name="LSLTipText_llTarget"> +integer llTarget(vector position, float range) +set positions within range of position as a target and return an ID for the target + </string> + <string name="LSLTipText_llTargetRemove"> +llTargetRemove(integer number) +removes target number + </string> + <string name="LSLTipText_llRotTarget"> +integer llRotTarget(rotation rot, float error) +set rotations with error of rot as a rotational target and return an ID for the rotational target + </string> + <string name="LSLTipText_llRotTargetRemove"> +llRotTargetRemove(integer number) +removes rotational target number + </string> + <string name="LSLTipText_llMoveToTarget"> +llMoveToTarget(vector target, float tau) +critically damp to target in tau seconds (if the script is physical) + </string> + <string name="LSLTipText_llStopMoveToTarget"> +llStopMoveToTarget() +Stops critically damped motion + </string> + <string name="LSLTipText_llApplyImpulse"> +llApplyImpulse(vector force, integer local) +applies impulse to object, in local coords if local == TRUE (if the script is physical) + </string> + <string name="LSLTipText_llApplyRotationalImpulse"> +llApplyRotationalImpulse(vector force, integer local) +applies rotational impulse to object, in local coords if local == TRUE (if the script is physical) + </string> + <string name="LSLTipText_llSetTorque"> +llSetTorque(vector torque, integer local) +sets the torque of object, in local coords if local == TRUE (if the script is physical) + </string> + <string name="LSLTipText_llGetTorque"> +vector llGetTorque() +gets the torque (if the script is physical) + </string> + <string name="LSLTipText_llSetForceAndTorque"> +llSetForceAndTorque(vector force, vector torque, integer local) +sets the force and torque of object, in local coords if local == TRUE (if the script is physical) + </string> + <string name="LSLTipText_llGetVel"> +vector llGetVel() +gets the velocity + </string> + <string name="LSLTipText_llGetAccel"> +vector llGetAccel() +gets the acceleration + </string> + <string name="LSLTipText_llGetOmega"> +vector llGetOmega() +gets the omega + </string> + <string name="LSLTipText_llGetTimeOfDay"> +float llGetTimeOfDay() +gets the time in seconds since [SECOND_LIFE] server midnight (or since server up-time; whichever is smaller) + </string> + <string name="LSLTipText_llGetWallclock"> +float llGetWallclock() +gets the time in seconds since midnight + </string> + <string name="LSLTipText_llGetTime"> +float llGetTime() +gets the time in seconds since creation + </string> + <string name="LSLTipText_llResetTime"> +llResetTime() +sets the time to zero + </string> + <string name="LSLTipText_llGetAndResetTime"> +float llGetAndResetTime() +gets the time in seconds since creation and sets the time to zero + </string> + <string name="LSLTipText_llSound"> +llSound(string sound, float volume, integer queue, integer loop) +plays sound at volume and whether it should loop or not + </string> + <string name="LSLTipText_llPlaySound"> +llPlaySound(string sound, float volume) +plays attached sound once at volume (0.0 - 1.0) + </string> + <string name="LSLTipText_llLoopSound"> +llLoopSound(string sound, float volume) +plays attached sound looping indefinitely at volume (0.0 - 1.0) + </string> + <string name="LSLTipText_llLoopSoundMaster"> +llLoopSoundMaster(string sound, float volume) +plays attached sound looping at volume (0.0 - 1.0), declares it a sync master + </string> + <string name="LSLTipText_llLoopSoundSlave"> +llLoopSoundSlave(string sound, float volume) +plays attached sound looping at volume (0.0 - 1.0), synced to most audible sync master + </string> + <string name="LSLTipText_llPlaySoundSlave"> +llPlaySoundSlave(string sound, float volume) +plays attached sound once at volume (0.0 - 1.0), synced to next loop of most audible sync master + </string> + <string name="LSLTipText_llTriggerSound"> +llTriggerSound(string sound, float volume) +plays sound at volume (0.0 - 1.0), centered at but not attached to object + </string> + <string name="LSLTipText_llStopSound"> +llStopSound() +Stops currently attached sound + </string> + <string name="LSLTipText_llPreloadSound"> +llPreloadSound(string sound) +preloads a sound on viewers within range + </string> + <string name="LSLTipText_llGetSubString"> +string llGetSubString(string src, integer start, integer end) +returns the indicated substring + </string> + <string name="LSLTipText_llDeleteSubString"> +string llDeleteSubString(string src, integer start, integer end) +removes the indicated substring and returns the result + </string> + <string name="LSLTipText_llInsertString"> +string llInsertString(string dst, integer position, string src) +inserts src into dst at position and returns the result + </string> + <string name="LSLTipText_llToUpper"> +string llToUpper(string src) +convert src to all upper case and returns the result + </string> + <string name="LSLTipText_llToLower"> +string llToLower(string src) +convert src to all lower case and returns the result + </string> + <string name="LSLTipText_llGiveMoney"> +llGiveMoney(key destination, integer amount) +transfer amount of money from script owner to destination + </string> + <string name="LSLTipText_llMakeExplosion"> +llMakeExplosion(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) +Make a round explosion of particles + </string> + <string name="LSLTipText_llMakeFountain"> +llMakeFountain(integer particles, float scale, float vel, float lifetime, float arc, integer bounce, string texture, vector offset, float bounce_offset) +Make a fountain of particles + </string> + <string name="LSLTipText_llMakeSmoke"> +llMakeSmoke(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) +Make smoke like particles + </string> + <string name="LSLTipText_llMakeFire"> +llMakeFire(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset) +Make fire like particles + </string> + <string name="LSLTipText_llRezObject"> +llRezObject(string inventory, vector pos, vector vel, rotation rot, integer param) +Instanciate owners inventory object at pos with velocity vel and rotation rot with start parameter param + </string> + <string name="LSLTipText_llLookAt"> +llLookAt(vector target, F32 strength, F32 damping) +Cause object name to point it's forward axis towards target + </string> + <string name="LSLTipText_llStopLookAt"> +llStopLookAt() +Stop causing object name to point at a target + </string> + <string name="LSLTipText_llSetTimerEvent"> +llSetTimerEvent(float sec) +Cause the timer event to be triggered every sec seconds + </string> + <string name="LSLTipText_llSleep"> +llSleep(float sec) +Put script to sleep for sec seconds + </string> + <string name="LSLTipText_llGetMass"> +float llGetMass() +Get the mass of task name that script is attached to + </string> + <string name="LSLTipText_llCollisionFilter"> +llCollisionFilter(string name, key id, integer accept) +if accept == TRUE, only accept collisions with objects name and id (either is optional), otherwise with objects not name or id + </string> + <string name="LSLTipText_llTakeControls"> +llTakeControls(integer controls, integer accept, integer pass_on) +Take controls from agent task has permissions for. If (accept == (controls & input)), send input to task. If pass_on send to agent also. + </string> + <string name="LSLTipText_llReleaseControls"> +llReleaseControls() +Stop taking inputs + </string> + <string name="LSLTipText_llAttachToAvatar"> +llAttachToAvatar(integer attachment) +Attach to avatar task has permissions for at point attachment + </string> + <string name="LSLTipText_llDetachFromAvatar"> +llDetachFromAvatar() +Drop off of avatar + </string> + <string name="LSLTipText_llTakeCamera"> +llTakeCamera(key avatar) +Move avatar's viewpoint to task + </string> + <string name="LSLTipText_llReleaseCamera"> +llReleaseCamera(key avatar) +Return camera to agent + </string> + <string name="LSLTipText_llGetOwner"> +key llGetOwner() +Returns the owner of the task + </string> + <string name="LSLTipText_llInstantMessage"> +llInstantMessage(key user, string message) +IMs message to the user + </string> + <string name="LSLTipText_llEmail"> +llEmail(string address, string subject, string message) +Sends email to address with subject and message + </string> + <string name="LSLTipText_llGetNextEmail"> +llGetNextEmail(string address, string subject) +Get the next waiting email with appropriate address and/or subject (if blank they are ignored) + </string> + <string name="LSLTipText_llGetKey"> +key llGetKey() +Get the key for the task the script is attached to + </string> + <string name="LSLTipText_llSetBuoyancy"> +llSetBuoyancy(float buoyancy) +Set the tasks buoyancy (0 is none, < 1.0 sinks, 1.0 floats, > 1.0 rises) + </string> + <string name="LSLTipText_llSetHoverHeight"> +llSetHoverHeight(float height, integer water, float tau) +Critically damps to a height (either above ground level or above the higher of land and water if water == TRUE) + </string> + <string name="LSLTipText_llStopHover"> +llStopHover() +Stop hovering to a height + </string> + <string name="LSLTipText_llMinEventDelay"> +llMinEventDelay(float delay) +Set the minimum time between events being handled + </string> + <string name="LSLTipText_llSoundPreload"> +llSoundPreload(string sound) +preloads a sound on viewers within range + </string> + <string name="LSLTipText_llRotLookAt"> +llRotLookAt(rotation target, F32 strength, F32 damping) +Cause object name to point it's forward axis towards target + </string> + <string name="LSLTipText_llStringLength"> +integer llStringLength(string str) +Returns the length of string + </string> + <string name="LSLTipText_llStartAnimation"> +llStartAnimation(string anim) +Start animation anim for agent that owns object + </string> + <string name="LSLTipText_llStopAnimation"> +llStopAnimation(string anim) +Stop animation anim for agent that owns object + </string> + <string name="LSLTipText_llPointAt"> +llPointAt(vector pos) +Make agent that owns object point at pos + </string> + <string name="LSLTipText_llStopPointAt"> +llStopPointAt() +Stop agent that owns object pointing + </string> + <string name="LSLTipText_llTargetOmega"> +llTargetOmega(vector axis, float spinrate, float gain) +Attempt to spin at spinrate with strength gain + </string> + <string name="LSLTipText_llGetStartParameter"> +integer llGetStartParameter() +Get's the start paramter passed to llRezObject + </string> + <string name="LSLTipText_llGodLikeRezObject"> +llGodLikeRezObject(key inventory, vector pos) +rez directly off of a UUID if owner has dog-bit set + </string> + <string name="LSLTipText_llRequestPermissions"> +llRequestPermissions(key agent, integer perm) +ask agent to allow the script to do perm (NB: Debit, ownership, link, joint, and permission requests can only go to the task's owner) + </string> + <string name="LSLTipText_llGetPermissionsKey"> +key llGetPermissionsKey() +Return agent that permissions are enabled for. NULL_KEY if not enabled + </string> + <string name="LSLTipText_llGetPermissions"> +integer llGetPermissions() +return what permissions have been enabled + </string> + <string name="LSLTipText_llGetLinkNumber"> +integer llGetLinkNumber() +Returns what number in a link set the script is attached to (0 means no link, 1 the root, 2 for first child, etc) + </string> + <string name="LSLTipText_llSetLinkColor"> +llSetLinkColor(integer linknumber, vector color, integer face) +If a task exists in the link chain at linknumber, set face to color + </string> + <string name="LSLTipText_llCreateLink"> +llCreateLink(key target, integer parent) +Attempt to link task script is attached to and target (requires permission PERMISSION_CHANGE_LINKS be set). If parent == TRUE, task script is attached to is the root + </string> + <string name="LSLTipText_llBreakLink"> +llBreakLink(integer linknum) +Delinks the task with the given link number (requires permission PERMISSION_CHANGE_LINKS be set) + </string> + <string name="LSLTipText_llBreakAllLinks"> +llBreakAllLinks() +Delinks all tasks in the link set (requires permission PERMISSION_CHANGE_LINKS be set) + </string> + <string name="LSLTipText_llGetLinkKey"> +key llGetLinkKey(integer linknum) +Get the key of linknumber in link set + </string> + <string name="LSLTipText_llGetLinkName"> +string llGetLinkName(integer linknum) +Get the name of linknumber in link set + </string> + <string name="LSLTipText_llGetInventoryNumber"> +integer llGetInventoryNumber(integer type) +Get the number of items of a given type in the task's inventory. +Valid types: INVENTORY_TEXTURE, INVENTORY_SOUND, INVENTORY_OBJECT, INVENTORY_SCRIPT, INVENTORY_CLOTHING, INVENTORY_BODYPART, INVENTORY_NOTECARD, INVENTORY_LANDMARK, INVENTORY_ALL + </string> + <string name="LSLTipText_llGetInventoryName"> +string llGetInventoryName(integer type, integer number) +Get the name of the inventory item number of type + </string> + <string name="LSLTipText_llSetScriptState"> +llSetScriptState(string name, integer run) +Control the state of a script name. + </string> + <string name="LSLTipText_llGetEnergy"> +float llGetEnergy() +Returns how much energy is in the object as a percentage of maximum + </string> + <string name="LSLTipText_llGiveInventory"> +llGiveInventory(key destination, string inventory) +Give inventory to destination + </string> + <string name="LSLTipText_llRemoveInventory"> +llRemoveInventory(string inventory) +Remove the named inventory item + </string> + <string name="LSLTipText_llSetText"> +llSetText(string text, vector color, float alpha) +Set text floating over object + </string> + <string name="LSLTipText_llWater"> +float llWater(vector v) +returns the water height below the object position + v + </string> + <string name="LSLTipText_llPassTouches"> +llPassTouches(integer pass) +if pass == TRUE, touches are passed from children on to parents (default is FALSE) + </string> + <string name="LSLTipText_llRequestAgentData"> +key llRequestAgentData(key id, integer data) +Requests data about agent id. When data is available the dataserver event will be raised + </string> + <string name="LSLTipText_llRequestInventoryData"> +key llRequestInventoryData(string name) +Requests data from object's inventory object. When data is available the dataserver event will be raised + </string> + <string name="LSLTipText_llSetDamage"> +llSetDamage(float damage) +Sets the amount of damage that will be done to an object that this task hits. Task will be killed. + </string> + <string name="LSLTipText_llTeleportAgentHome"> +llTeleportAgentHome(key id) +Teleports agent on owner's land to agent's home location + </string> + <string name="LSLTipText_llModifyLand"> +llModifyLand(integer action, integer size) +Modify land with action (LAND_LEVEL, LAND_RAISE, LAND_LOWER, LAND_SMOOTH, LAND_NOISE, LAND_REVERT) +on size (LAND_SMALL_BRUSH, LAND_MEDIUM_BRUSH, LAND_LARGE_BRUSH) + </string> + <string name="LSLTipText_llCollisionSound"> +llCollisionSound(string impact_sound, float impact_volume) +Suppress default collision sounds, replace default impact sounds with impact_sound (empty string to just suppress) + </string> + <string name="LSLTipText_llCollisionSprite"> +llCollisionSprite(string impact_sprite) +Suppress default collision sprites, replace default impact sprite with impact_sprite (empty string to just suppress) + </string> + <string name="LSLTipText_llGetAnimation"> +string llGetAnimation(key id) +Get the currently playing locomotion animation for avatar id + </string> + <string name="LSLTipText_llResetScript"> +llResetScript() +Resets the script + </string> + <string name="LSLTipText_llMessageLinked"> +llMessageLinked(integer linknum, integer num, string str, key id) +Sends num, str, and id to members of the link set +(LINK_ROOT sends to root task in a linked set, +LINK_SET sends to all tasks, +LINK_ALL_OTHERS to all other tasks, +LINK_ALL_CHILDREN to all children, +LINK_THIS to the task the script it is in) + </string> + <string name="LSLTipText_llPushObject"> +llPushObject(key id, vector impulse, vector ang_impulse, integer local) +Applies impulse and ang_impulse to object id + </string> + <string name="LSLTipText_llPassCollisions"> +llPassCollisions(integer pass) +if pass == TRUE, collisions are passed from children on to parents (default is FALSE) + </string> + <string name="LSLTipText_llGetScriptName"> +llGetScriptName() +Returns the script name + </string> + <string name="LSLTipText_llGetNumberOfSides"> +integer llGetNumberOfSides() +Returns the number of sides + </string> + <string name="LSLTipText_llAxisAngle2Rot"> +rotation llAxisAngle2Rot(vector axis, float angle) +Returns the rotation generated angle about axis + </string> + <string name="LSLTipText_llRot2Axis"> +vector llRot2Axis(rotation rot) +Returns the rotation axis represented by rot + </string> + <string name="LSLTipText_llRot2Angle"> +float llRot2Angle(rotation rot) +Returns the rotation angle represented by rot + </string> + <string name="LSLTipText_llAcos"> +float llAcos(float val) +Returns the arccosine in radians of val + </string> + <string name="LSLTipText_llAsin"> +float llAsin(float val) +Returns the arcsine in radians of val + </string> + <string name="LSLTipText_llAngleBetween"> +float llAngleBetween(rotation a, rotation b) +Returns angle between rotation a and b + </string> + <string name="LSLTipText_llGetInventoryKey"> +key llGetInventoryKey(string name) +Returns the key of the inventory name + </string> + <string name="LSLTipText_llAllowInventoryDrop"> +llAllowInventoryDrop(integer add) +If add == TRUE, users without permissions can still drop inventory items onto task + </string> + <string name="LSLTipText_llGetSunDirection"> +vector llGetSunDirection() +Returns the sun direction on the simulator + </string> + <string name="LSLTipText_llGetTextureOffset"> +vector llGetTextureOffset(integer side) +Returns the texture offset of side in the x and y components of a vector + </string> + <string name="LSLTipText_llGetTextureScale"> +vector llGetTextureScale(integer side) +Returns the texture scale of side in the x and y components of a vector + </string> + <string name="LSLTipText_llGetTextureRot"> +float llGetTextureRot(integer side) +Returns the texture rotation of side + </string> + <string name="LSLTipText_llSubStringIndex"> +integer llSubStringIndex(string source, string pattern) +Finds index in source where pattern first appears (returns -1 if not found) + </string> + <string name="LSLTipText_llGetOwnerKey"> +key llGetOwnerKey(key id) +Find the owner of id + </string> + <string name="LSLTipText_llGetCenterOfMass"> +vector llGetCenterOfMass() +Get the object's center of mass + </string> + <string name="LSLTipText_llListSort"> +list llListSort(list src, integer stride, integer ascending) +Sort the list into blocks of stride in ascending order if ascending == TRUE. Note that sort only works between same types. + </string> + <string name="LSLTipText_llGetListLength"> +integer llGetListLength(list src) +Get the number of elements in the list + </string> + <string name="LSLTipText_llList2Integer"> +integer llList2Integer(list src, integer index) +Copy the integer at index in the list + </string> + <string name="LSLTipText_llList2Float"> +float llList2Float(list src, integer index) +Copy the float at index in the list + </string> + <string name="LSLTipText_llList2String"> +string llList2String(list src, integer index) +Copy the string at index in the list + </string> + <string name="LSLTipText_llList2Key"> +key llList2Key(list src, integer index) +Copy the key at index in the list + </string> + <string name="LSLTipText_llList2Vector"> +vector llList2Vector(list src, integer index) +Copy the vector at index in the list + </string> + <string name="LSLTipText_llList2Rot"> +rotation llList2Rot(list src, integer index) +Copy the rotation at index in the list + </string> + <string name="LSLTipText_llList2List"> +list llList2List(list src, integer start, integer end) +Copy the slice of the list from start to end + </string> + <string name="LSLTipText_llDeleteSubList"> +list llDeleteSubList(list src, integer start, integer end) +Remove the slice from the list and return the remainder + </string> + <string name="LSLTipText_llGetListEntryType"> +integer llGetListEntryType(list src, integer index) +Returns the type of the index entry in the list +(TYPE_INTEGER, TYPE_FLOAT, TYPE_STRING, TYPE_KEY, TYPE_VECTOR, TYPE_ROTATION, or TYPE_INVALID if index is off list) + </string> + <string name="LSLTipText_llList2CSV"> +string llList2CSV(list src) +Create a string of comma separated values from list + </string> + <string name="LSLTipText_llCSV2List"> +list llCSV2List(string src) +Create a list from a string of comma separated values + </string> + <string name="LSLTipText_llListRandomize"> +list llListRandomize(list src, integer stride) +Returns a randomized list of blocks of size stride + </string> + <string name="LSLTipText_llList2ListStrided"> +list llList2ListStrided(list src, integer start, integer end, integer stride) +Copy the strided slice of the list from start to end + </string> + <string name="LSLTipText_llGetRegionCorner"> +vector llGetRegionCorner() +Returns a vector with the south west corner x,y position of the region the object is in + </string> + <string name="LSLTipText_llListInsertList"> +list llListInsertList(list dest, list src, integer start) +Inserts src into dest at position start + </string> + <string name="LSLTipText_llListFindList"> +integer llListFindList(list src, list test) +Returns the start of the first instance of test in src, -1 if not found + </string> + <string name="LSLTipText_llGetObjectName"> +string llGetObjectName() +Returns the name of the object script is attached to + </string> + <string name="LSLTipText_llSetObjectName"> +llSetObjectName(string name) +Sets the objects name + </string> + <string name="LSLTipText_llGetDate"> +string llGetDate() +Gets the date as YYYY-MM-DD + </string> + <string name="LSLTipText_llEdgeOfWorld"> +integer llEdgeOfWorld(vector pos, vector dir) +Checks to see whether the border hit by dir from pos is the edge of the world (has no neighboring simulator) + </string> + <string name="LSLTipText_llGetAgentInfo"> +integer llGetAgentInfo(key id) +Gets information about agent ID. +Returns AGENT_FLYING, AGENT_ATTACHMENTS, AGENT_SCRIPTED, AGENT_SITTING, AGENT_ON_OBJECT, AGENT_MOUSELOOK, AGENT_AWAY, AGENT_BUSY, AGENT_TYPING, AGENT_CROUCHING, AGENT_ALWAYS_RUN, AGENT_WALKING and/or AGENT_IN_AIR. + </string> + <string name="LSLTipText_llAdjustSoundVolume"> +llAdjustSoundVolume(float volume) +adjusts volume of attached sound (0.0 - 1.0) + </string> + <string name="LSLTipText_llSetSoundQueueing"> +llSetSoundQueueing(integer queue) +determines whether attached sound calls wait for the current sound to finish (0 = no [default], nonzero = yes) + </string> + <string name="LSLTipText_llSetSoundRadius"> +llSetSoundRadius(float radius) +establishes a hard cut-off radius for audibility of scripted sounds (both attached and triggered) + </string> + <string name="LSLTipText_llKey2Name"> +string llKey2Name(key id) +Returns the name of the object key, iff the object is in the current simulator, otherwise the empty string + </string> + <string name="LSLTipText_llSetTextureAnim"> +llSetTextureAnim(integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate) +Animate the texture on the specified face/faces + </string> + <string name="LSLTipText_llTriggerSoundLimited"> +llTriggerSoundLimited(string sound, float volume, vector tne, vector bsw) +plays sound at volume (0.0 - 1.0), centered at but not attached to object, limited to AABB defined by vectors top-north-east and bottom-south-west + </string> + <string name="LSLTipText_llEjectFromLand"> +llEjectFromLand(key pest) +Ejects pest from land that you own + </string> + <string name="LSLTipText_llParseString2List"> +list llParseString2List(string src, list separators, list spacers) +Breaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each) + </string> + <string name="LSLTipText_llOverMyLand"> +integer llOverMyLand(key id) +Returns TRUE if id is over land owner of object owns, FALSE otherwise + </string> + <string name="LSLTipText_llGetLandOwnerAt"> +key llGetLandOwnerAt(vector pos) +Returns the key of the land owner, NULL_KEY if public + </string> + <string name="LSLTipText_llGetNotecardLine"> +key llGetNotecardLine(string name, integer line) +Returns line line of notecard name via the dataserver event + </string> + <string name="LSLTipText_llGetAgentSize"> +vector llGetAgentSize(key id) +If the agent is in the same sim as the object, returns the size of the avatar + </string> + <string name="LSLTipText_llSameGroup"> +integer llSameGroup(key id) +Returns TRUE if ID is in the same sim and has the same active group, otherwise FALSE + </string> + <string name="LSLTipText_llUnSit"> +key llUnSit(key id) +If agent identified by id is sitting on the object the script is attached to or is over land owned by the objects owner, the agent is forced to stand up + </string> + <string name="LSLTipText_llGroundSlope"> +vector llGroundSlope(vector v) +returns the ground slope below the object position + v + </string> + <string name="LSLTipText_llGroundNormal"> +vector llGroundNormal(vector v) +returns the ground normal below the object position + v + </string> + <string name="LSLTipText_llGroundContour"> +vector llGroundCountour(vector v) +returns the ground contour below the object position + v + </string> + <string name="LSLTipText_llGetAttached"> +integer llGetAttached() +returns the object attachment point or 0 if not attached + </string> + <string name="LSLTipText_llGetFreeMemory"> +integer llGetFreeMemory() +returns the available heap space for the current script + </string> + <string name="LSLTipText_llGetRegionName"> +string llGetRegionName() +returns the current region name + </string> + <string name="LSLTipText_llGetRegionTimeDilation"> +float llGetRegionTimeDilation() +returns the current time dilation as a float between 0 and 1 + </string> + <string name="LSLTipText_llGetRegionFPS"> +float llGetRegionFPS() +returns the mean region frames per second + </string> + <string name="LSLTipText_llParticleSystem"> +llParticleSystem(list rules) +Creates a particle system based on rules. Empty list removes particle system from object. +List format is [ rule1, data1, rule2, data2 . . . rulen, datan ] + </string> + <string name="LSLTipText_llGroundRepel"> +llGroundRepel(float height, integer water, float tau) +Critically damps to height if within height*0.5 of level (either above ground level or above the higher of land and water if water == TRUE) + </string> + <string name="LSLTipText_llGiveInventoryList"> +llGiveInventoryList(key destination, string category, list inventory) +Give inventory to destination in a new category + </string> + <string name="LSLTipText_llSetVehicleType"> +llSetVehicleType(integer type) +sets vehicle to one of the default types + </string> + <string name="LSLTipText_llSetVehicleFloatParam"> +llSetVehicleFloatParam(integer param, float value) +sets the specified vehicle float parameter + </string> + <string name="LSLTipText_llSetVehicleVectorParam"> +llSetVehicleVectorParam(integer param, vector vec) +sets the specified vehicle vector parameter + </string> + <string name="LSLTipText_llSetVehicleRotationParam"> +llSetVehicleVectorParam(integer param, rotation rot) +sets the specified vehicle rotation parameter + </string> + <string name="LSLTipText_llSetVehicleFlags"> +llSetVehicleFlags(integer flags) +sets the enabled bits in 'flags' + </string> + <string name="LSLTipText_llRemoveVehicleFlags"> +llRemoveVehicleFlags(integer flags) +removes the enabled bits in 'flags' + </string> + <string name="LSLTipText_llSitTarget"> +llSitTarget(vector offset, rotation rot) +Set the sit location for this object (if offset == <0,0,0> clear it) + </string> + <string name="LSLTipText_llAvatarOnSitTarget"> +key llAvatarOnSitTarget() +If an avatar is sitting on the sit target, return the avatar's key, NULL_KEY otherwise + </string> + <string name="LSLTipText_llAddToLandPassList"> +llAddToLandPassList(key avatar, float hours) +Add avatar to the land pass list for hours + </string> + <string name="LSLTipText_llSetTouchText"> +llSetTouchText(string text) +Displays text in pie menu that acts as a touch + </string> + <string name="LSLTipText_llSetSitText"> +llSetSitText(string text) +Displays text rather than sit in pie menu + </string> + <string name="LSLTipText_llSetCameraEyeOffset"> +llSetCameraEyeOffset(vector offset) +Sets the camera eye offset used in this object if an avatar sits on it + </string> + <string name="LSLTipText_llSetCameraAtOffset"> +llSetCameraAtOffset(vector offset) +Sets the camera at offset used in this object if an avatar sits on it + </string> + <string name="LSLTipText_llDumpList2String"> +string llDumpList2String(list src, string separator) +Write the list out in a single string using separator between values + </string> + <string name="LSLTipText_llScriptDanger"> +integer llScriptDanger(vector pos) +Returns true if pos is over public land, sandbox land, land that doesn't allow everyone to edit and build, or land that doesn't allow outside scripts + </string> + <string name="LSLTipText_llDialog"> +llDialog(key avatar, string message, list buttons, integer chat_channel +Shows a dialog box on the avatar's screen with the message. +Up to 12 strings in the list form buttons. +If a button is clicked, the name is chatted on chat_channel. + </string> + <string name="LSLTipText_llVolumeDetect"> +llVolumeDetect(integer detect) +If detect = TRUE, object becomes phantom but triggers collision_start and collision_end events when other objects start and stop interpenetrating. +Must be applied to the root object. + </string> + <string name="LSLTipText_llResetOtherScript"> +llResetOtherScript(string name) +Resets script name + </string> + <string name="LSLTipText_llGetScriptState"> +integer llGetScriptState(string name) +Resets TRUE if script name is running + </string> + <string name="LSLTipText_llRemoteLoadScript"> +Deprecated. Please use llRemoteLoadScriptPin instead. + </string> + <string name="LSLTipText_llSetRemoteScriptAccessPin"> +llSetRemoteScriptAccessPin(integer pin) +If pin is set to a non-zero number, the task will accept remote script loads via llRemoteLoadScriptPin if it passes in the correct pin. +Othersise, llRemoteLoadScriptPin is ignored. + </string> + <string name="LSLTipText_llRemoteLoadScriptPin"> +llRemoteLoadScriptPin(key target, string name, integer pin, integer running, integer start_param) +If the owner of the object this script is attached can modify target, +they are in the same region, and the matching pin is used, +copy script name onto target, +if running == TRUE, start the script with param. + </string> + <string name="LSLTipText_llOpenRemoteDataChannel"> +llOpenRemoteDataChannel() +Creates a channel to listen for XML-RPC calls. Will trigger a remote_data event with channel id once it is available. + </string> + <string name="LSLTipText_llSendRemoteData"> +key llSendRemoteData(key channel, string dest, integer idata, string sdata) +Send an XML-RPC request to dest through channel with payload of channel (in a string), integer idata and string sdata. +A message identifier key is returned. +An XML-RPC reply will trigger a remote_data event and reference the message id. +The message_id is returned. + </string> + <string name="LSLTipText_llRemoteDataReply"> +llRemoteDataReply(key channel, key message_id, string sdata, integer idata) +Send an XML-RPC reply to message_id on channel with payload of string sdata and integer idata + </string> + <string name="LSLTipText_llCloseRemoteDataChannel"> +llCloseRemoteDataChannel(key channel) +Closes XML-RPC channel. + </string> + <string name="LSLTipText_llMD5String"> +string llMD5String(string src, integer nonce) +Performs a RSA Data Security, Inc. MD5 Message-Digest Algorithm on string with nonce. Returns a 32 character hex string. + </string> + <string name="LSLTipText_llSetPrimitiveParams"> +llSetPrimitiveParams(list rules) +Set primitive parameters based on rules. + </string> + <string name="LSLTipText_llStringToBase64"> +string llStringToBase64(string str) +Converts a string to the Base 64 representation of the string. + </string> + <string name="LSLTipText_llBase64ToString"> +string llBase64ToString(string str) +Converts a Base 64 string to a conventional string. If the conversion creates any unprintable characters, they are converted to spaces. + </string> + <string name="LSLTipText_llXorBase64Strings"> +string llXorBase64Strings(string s1, string s2) +DEPRECATED! Please use llXorBase64StringsCorrect instead!! Incorrectly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. Retained for backwards compatability. + </string> + <string name="LSLTipText_llRemoteDataSetRegion"> +llRemoteDataSetRegion() +If an object using remote data channels changes regions, you must call this function to reregister the remote data channels. +You do not need to make this call if you don't change regions. + </string> + <string name="LSLTipText_llLog10"> +float llLog10(float val) +Returns the base 10 log of val if val > 0, otherwise returns 0. + </string> + <string name="LSLTipText_llLog"> +float llLog(float val) +Returns the base e log of val if val > 0, otherwise returns 0. + </string> + <string name="LSLTipText_llGetAnimationList"> +list llGetAnimationList(key id) +Gets a list of all playing animations for avatar id + </string> + <string name="LSLTipText_llSetParcelMusicURL"> +llSetParcelMusicURL(string url) +Sets the streaming audio URL for the parcel object is on + </string> + <string name="LSLTipText_llGetRootPosition"> +vector llGetRootPosition() +Gets the global position of the root object of the object script is attached to + </string> + <string name="LSLTipText_llGetRootRotation"> +rotation llGetRootRotation() +Gets the global rotation of the root object of the object script is attached to + </string> + <string name="LSLTipText_llGetObjectDesc"> +string llGetObjectDesc() +Returns the description of the object the script is attached to + </string> + <string name="LSLTipText_llSetObjectDesc"> +llSetObjectDesc(string name) +Sets the object's description + </string> + <string name="LSLTipText_llGetCreator"> +key llGetCreator() +Returns the creator of the object + </string> + <string name="LSLTipText_llGetTimestamp"> +string llGetTimestamp() +Gets the timestamp in the format: YYYY-MM-DDThh:mm:ss.ff..fZ + </string> + <string name="LSLTipText_llSetLinkAlpha"> +llSetLinkAlpha(integer linknumber, float alpha, integer face) +If a prim exists in the link chain at linknumber, set face to alpha + </string> + <string name="LSLTipText_llGetNumberOfPrims"> +integer llGetNumberOfPrims() +Returns the number of prims in a link set the script is attached to + </string> + <string name="LSLTipText_llGetNumberOfNotecardLines"> +key llGetNumberOfNotecardLines(string name) +Returns number of lines in notecard 'name' via the dataserver event (cast return value to integer) + </string> + <string name="LSLTipText_llGetBoundingBox"> +list llGetBoundingBox(key object) +Returns the bounding box around an object (including any linked prims) relative to the root prim, in a list: [ (vector) min_corner, (vector) max_corner ] + </string> + <string name="LSLTipText_llGetGeometricCenter"> +vector llGetGeometricCenter() +Returns the geometric center of the linked set the script is attached to. + </string> + <string name="LSLTipText_llGetPrimitiveParams"> +list llGetPrimitiveParams(list params) +Gets primitive parameters specified in the params list. + </string> + <string name="LSLTipText_llIntegerToBase64"> +string llIntegerToBase64(integer number) +Big endian encode of of integer as a Base64 string. + </string> + <string name="LSLTipText_llBase64ToInteger"> +integer llBase64ToInteger(string str) +Big endian decode of a Base64 string into an integer. + </string> + <string name="LSLTipText_llGetGMTclock"> +float llGetGMTclock() +Gets the time in seconds since midnight in GMT + </string> + <string name="LSLTipText_llGetSimulatorHostname"> +string llGetSimulatorHostname() +Gets the hostname of the machine script is running on (same as string in viewer Help dialog) + </string> + <string name="LSLTipText_llSetLocalRot"> +llSetLocalRot(rotation rot) +sets the rotation of a child prim relative to the root prim + </string> + <string name="LSLTipText_llParseStringKeepNulls"> +list llParseStringKeepNulls(string src, list separators, list spacers) +Breaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each), keeping any null values generated. + </string> + <string name="LSLTipText_llRezAtRoot"> +llRezAtRoot(string inventory, vector pos, vector vel, rotation rot, integer param) +Instantiate owner's inventory object at pos with velocity vel and rotation rot with start parameter param. +The last selected root object's location will be set to pos + </string> + <string name="LSLTipText_llGetObjectPermMask"> +integer llGetObjectPermMask(integer mask) +Returns the requested permission mask for the root object the task is attached to. + </string> + <string name="LSLTipText_llSetObjectPermMask"> +llSetObjectPermMask(integer mask, integer value) +Sets the given permission mask to the new value on the root object the task is attached to. + </string> + <string name="LSLTipText_llGetInventoryPermMask"> +integer llGetInventoryPermMask(string item, integer mask) +Returns the requested permission mask for the inventory item. + </string> + <string name="LSLTipText_llSetInventoryPermMask"> +llSetInventoryPermMask(string item, integer mask, integer value) +Sets the given permission mask to the new value on the inventory item. + </string> + <string name="LSLTipText_llGetInventoryCreator"> +key llGetInventoryCreator(string item) +Returns the key for the creator of the inventory item. + </string> + <string name="LSLTipText_llOwnerSay"> +llOwnerSay(string msg) +says msg to owner only (if owner in sim) + </string> + <string name="LSLTipText_llRequestSimulatorData"> +key llRequestSimulatorData(string simulator, integer data) +Requests data about simulator. When data is available the dataserver event will be raised + </string> + <string name="LSLTipText_llForceMouselook"> +llForceMouselook(integer mouselook) +If mouselook is TRUE any avatar that sits on this object is forced into mouselook mode + </string> + <string name="LSLTipText_llGetObjectMass"> +float llGetObjectMass(key id) +Get the mass of the object with key id + </string> + <string name="LSLTipText_llListReplaceList"> +list llListReplaceList(list dest, list src, integer start, integer end) +Replaces start through end of dest with src. + </string> + <string name="LSLTipText_llLoadURL"> +llLoadURL(key avatar_id, string message, string url) +Shows dialog to avatar avatar_id offering to load web page at URL. If user clicks yes, launches their web browser. + </string> + <string name="LSLTipText_llParcelMediaCommandList"> +llParcelMediaCommandList(list command) +Sends a list of commands, some with arguments, to a parcel. + </string> + <string name="LSLTipText_llParcelMediaQuery"> +list llParcelMediaQuery(list query) +Sends a list of queries, returns a list of results. + </string> + <string name="LSLTipText_llModPow"> +integer llModPow(integer a, integer b, integer c) +Returns a raised to the b power, mod c. ( (a**b)%c ). b is capped at 0xFFFF (16 bits). + </string> + <string name="LSLTipText_llGetInventoryType"> +integer llGetInventoryType(string name) +Returns the type of the inventory name + </string> + <string name="LSLTipText_llSetPayPrice"> +llSetPayPrice(integer price, list quick_pay_buttons) +Sets the default amount when someone chooses to pay this object. + </string> + <string name="LSLTipText_llGetCameraPos"> +vector llGetCameraPos() +Gets current camera position for agent task has permissions for. + </string> + <string name="LSLTipText_llGetCameraRot"> +rotation llGetCameraRot() +Gets current camera orientation for agent task has permissions for. + </string> + <string name="LSLTipText_llSetPrimURL"> +llSetPrimURL(string url) +Updates the URL for the web page shown on the sides of the object. + </string> + <string name="LSLTipText_llRefreshPrimURL"> +llRefreshPrimURL() +Reloads the web page shown on the sides of the object. + </string> + <string name="LSLTipText_llEscapeURL"> +string llEscapeURL(string url) +Returns and escaped/encoded version of url, replacing spaces with %20 etc. + </string> + <string name="LSLTipText_llUnescapeURL"> +string llUnescapeURL(string url) +Returns and unescaped/unencoded version of url, replacing %20 with spaces etc. + </string> + <string name="LSLTipText_llMapDestination"> +llMapDestination(string simname, vector pos, vector look_at) +Opens world map centered on region with pos highlighted. +Only works for scripts attached to avatar, or during touch events. +(NOTE: look_at currently does nothing) + </string> + <string name="LSLTipText_llAddToLandBanList"> +llAddToLandBanList(key avatar, float hours) +Add avatar to the land ban list for hours + </string> + <string name="LSLTipText_llRemoveFromLandPassList"> +llRemoveFromLandPassList(key avatar) +Remove avatar from the land pass list + </string> + <string name="LSLTipText_llRemoveFromLandBanList"> +llRemoveFromLandBanList(key avatar) +Remove avatar from the land ban list + </string> + <string name="LSLTipText_llSetCameraParams"> +llSetCameraParams(list rules) +Sets multiple camera parameters at once. +List format is [ rule1, data1, rule2, data2 . . . rulen, datan ] + </string> + <string name="LSLTipText_llClearCameraParams"> +llClearCameraParams() +Resets all camera parameters to default values and turns off scripted camera control. + </string> + <string name="LSLTipText_llListStatistics"> +float llListStatistics(integer operation, list l) +Perform statistical aggregate functions on list l using LIST_STAT_* operations. + </string> + <string name="LSLTipText_llGetUnixTime"> +integer llGetUnixTime() +Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC from the system clock. + </string> + <string name="LSLTipText_llGetParcelFlags"> +integer llGetParcelFlags(vector pos) +Get the parcel flags (PARCEL_FLAG_*) for the parcel including the point pos. + </string> + <string name="LSLTipText_llGetRegionFlags"> +integer llGetRegionFlags() +Get the region flags (REGION_FLAG_*) for the region the object is in. + </string> + <string name="LSLTipText_llXorBase64StringsCorrect"> +string llXorBase64StringsCorrect(string s1, string s2) +Correctly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. + </string> + <string name="LSLTipText_llHTTPRequest"> +llHTTPRequest(string url, list parameters, string body) +Send an HTTP request. + </string> + <string name="LSLTipText_llResetLandBanList"> +llResetLandBanList() +Removes all residents from the land ban list. + </string> + <string name="LSLTipText_llResetLandPassList"> +llResetLandPassList() +Removes all residents from the land access/pass list. + </string> + <string name="LSLTipText_llGetObjectPrimCount"> +integer llGetObjectPrimCount(key object_id) +Returns the total number of prims for an object. + </string> + <string name="LSLTipText_llGetParcelPrimOwners"> +list llGetParcelPrimOwners(vector pos) +Returns a list of all residents who own objects on the parcel and the number of objects they own. +Requires owner-like permissions for the parcel. + </string> + <string name="LSLTipText_llGetParcelPrimCount"> +integer llGetParcelPrimCount(vector pos, integer category, integer sim_wide) +Gets the number of prims on the parcel of the given category. +Categories: PARCEL_COUNT_TOTAL, _OWNER, _GROUP, _OTHER, _SELECTED, _TEMP. + </string> + <string name="LSLTipText_llGetParcelMaxPrims"> +integer llGetParcelMaxPrims(vector pos, integer sim_wide) +Gets the maximum number of prims allowed on the parcel at pos. + </string> + <string name="LSLTipText_llGetParcelDetails"> +list llGetParcelDetails(vector pos, list params) +Gets the parcel details specified in params for the parcel at pos. +Params is one or more of: PARCEL_DETAILS_NAME, _DESC, _OWNER, _GROUP, _AREA + </string> + <string name="LSLTipText_llSetLinkPrimitiveParams"> +llSetLinkPrimitiveParams(integer linknumber, list rules) +Set primitive parameters for linknumber based on rules. + </string> + <string name="LSLTipText_llSetLinkTexture"> +llSetLinkTexture(integer link_pos, string texture, integer face) +Sets the texture of face for link_pos + </string> + <string name="LSLTipText_llStringTrim"> +string llStringTrim(string src, integer trim_type) +Trim leading and/or trailing spaces from a string. +Uses trim_type of STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL. + </string> + <string name="LSLTipText_llRegionSay"> +llRegionSay(integer channel, string msg) +broadcasts msg to entire region on channel (not 0.) + </string> + <string name="LSLTipText_llGetObjectDetails"> +list llGetObjectDetails(key id, list params) +Gets the object details specified in params for the object with key id. +Details are OBJECT_NAME, _DESC, _POS, _ROT, _VELOCITY, _OWNER, _GROUP, _CREATOR. + </string> + <string name="LSLTipText_llSetClickAction"> +llSetClickAction(integer action) +Sets the action performed when a prim is clicked upon. + </string> + <string name="LSLTipText_llGetRegionAgentCount"> +int llGetRegionAgentCount() +returns the number of agents in a region + </string> + <string name="LSLTipText_llTextBox"> +llTextBox(key avatar, string message, integer chat_channel +Shows a dialog box on the avatar's screen with the message. +A text box asks for input, and if entered the text is chatted on chat_channel. + </string> + <string name="LSLTipText_llGetAgentLanguage"> +string llGetAgentLanguage(key id) +Gets the agents preferred language.. + </string> + <string name="LSLTipText_llDetectedTouchUV"> +vector llDetectedTouchUV(integer number) +returns the u and v coordinates in the first two components of a vector, for a triggered touch event + </string> + <string name="LSLTipText_llDetectedTouchFace"> +integer llDetectedTouchFace(integer number) +returns the index of the face on the object for a triggered touch event + </string> + <string name="LSLTipText_llDetectedTouchPos"> +vector llDetectedTouchPos(integer number) +returns the position touched for a triggered touch event + </string> + <string name="LSLTipText_llDetectedTouchNormal"> +vector llDetectedTouchNormal(integer number) +returns the surface normal for a triggered touch event + </string> + <string name="LSLTipText_llDetectedTouchBinormal"> +vector llDetectedTouchBinormal(integer number) +returns the surface binormal for a triggered touch event + </string> + <string name="LSLTipText_llDetectedTouchST"> +vector llDetectedTouchST(integer number) +returns the s and t coordinates in the first two components of a vector, for a triggered touch event + </string> + <string name="LSLTipText_llSHA1String"> +string llSHA1String(string sr) +Performs a SHA1 security Hash. Returns a 40 character hex string. + </string> + <string name="LSLTipText_llGetFreeURLs"> +integer llGetFreeURLs() +returns the available urls for the current script + </string> + <string name="LSLTipText_llRequestURL"> +key llRequestURL() +Requests one HTTP:// url for use by this object +Triggers an http_server event with results. + </string> + <string name="LSLTipText_llRequestSecureURL"> +key llRequestSecureURL() +Requests one HTTPS:// (SSL) url for use by this object +Triggers an http_server event with results. + </string> + <string name="LSLTipText_llReleaseURL"> +llReleaseURL(string url) +Releases the specified URL, it will no longer be usable. + </string> + <string name="LSLTipText_llHTTPResponse"> +llHTTPResponse(key id, integer status, string body) +Responds to request id with status and body. + </string> + <string name="LSLTipText_llGetHTTPHeader"> +string llGetHTTPHeader(key id, string header) +Get the value for header for request id. + </string> <!-- Avatar busy/away mode --> <string name="AvatarSetNotAway">Set Not Away</string> diff --git a/indra/newview/skins/default/xui/en/widgets/accordion_tab.xml b/indra/newview/skins/default/xui/en/widgets/accordion_tab.xml new file mode 100644 index 0000000000..eabacbecb2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/accordion_tab.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<accordion_tab + header_collapse_img="accordion_collapsed.tga" + header_collapse_img_pressed="accordion_collapsed.tga" + header_expand_img="accordion_expanded.tga" + header_expand_img_pressed="accordion_expanded.tga" /> diff --git a/indra/newview/skins/default/xui/en/widgets/list.xml b/indra/newview/skins/default/xui/en/widgets/list.xml new file mode 100644 index 0000000000..4a59716464 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/list.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<list + allow_select="true" + bg_opaque_color="PanelFocusBackgroundColor" + bg_alpha_color="PanelDefaultBackgroundColor" + background_visible="false" + background_opaque="false" + item_pad="5" + keep_one_selected="true" + multi_select="false" />
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/location_input.xml b/indra/newview/skins/default/xui/en/widgets/location_input.xml index 8f4d0edf95..297a3762f6 100644 --- a/indra/newview/skins/default/xui/en/widgets/location_input.xml +++ b/indra/newview/skins/default/xui/en/widgets/location_input.xml @@ -43,7 +43,7 @@ label="" pad_right="0" tool_tip="My Location History"/> - <combo_list bg_writeable_color="MenuDefaultBgColor"/> + <combo_list bg_writeable_color="MenuDefaultBgColor" page_lines="10"/> <combo_editor name="Combo Text Entry" text_pad_left="20" select_on_focus="false" diff --git a/indra/newview/skins/default/xui/en/widgets/search_combo_box.xml b/indra/newview/skins/default/xui/en/widgets/search_combo_box.xml new file mode 100644 index 0000000000..1d43b25f1d --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/search_combo_box.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<search_combo_box + allow_text_entry="true" + list_position="BELOW" + show_text_as_tentative="false" + dropdown_button_visible="false" + background_image="TextField_Search_Off" + background_image_disabled="TextField_Search_Disabled" + background_image_focused="TextField_Search_Active"> + <combo_editor + select_on_focus="true" + text_pad_left="20" + background_image="TextField_Search_Off" + background_image_disabled="TextField_Search_Disabled" + background_image_focused="TextField_Search_Active"/> + <combo_list + multi_select="false" + page_lines="10" /> + <search_button label="" + top_pad="4" + left_pad="4" + width="13" + height="13" + image_unselected="Search" + image_selected="Search" /> +</search_combo_box>
\ No newline at end of file diff --git a/indra/test/llsdmessagebuilder_tut.cpp b/indra/test/llsdmessagebuilder_tut.cpp index 27ab127772..34f3530308 100755 --- a/indra/test/llsdmessagebuilder_tut.cpp +++ b/indra/test/llsdmessagebuilder_tut.cpp @@ -353,7 +353,7 @@ namespace tut { char binData[] = "abcdefghijklmnop"; - addValue(messageBlockData, "testBinData", &binData, MVT_FIXED, sizeof(binData)); + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_FIXED, sizeof(binData)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -393,7 +393,7 @@ namespace tut { U16 binData[] = {1,2,3,4,5,6,7,8,9}; //9 shorts - addValue(messageBlockData, "testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 1, 2); + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 1, 2); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -413,7 +413,7 @@ namespace tut { U32 binData[] = {9,8,7,6,5,4,3,2,1}; - addValue(messageBlockData, "testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 2, 4); + addValue(messageBlockData, (char *)"testBinData", &binData, MVT_VARIABLE, sizeof(binData) >> 2, 4); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -433,7 +433,7 @@ namespace tut { U8 data = 0xa5; - addValue(messageBlockData, "testBinData", &data, MVT_U8, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U8, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -450,7 +450,7 @@ namespace tut { U16 data = 0xa55a; - addValue(messageBlockData, "testBinData", &data, MVT_U16, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -467,7 +467,7 @@ namespace tut { U32 data = 0xa55a7117; - addValue(messageBlockData, "testBinData", &data, MVT_U32, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U32, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -483,7 +483,7 @@ namespace tut void LLSDMessageBuilderTestObject::test<27>() { U64 data = U64L(0xa55a711711223344); - addValue(messageBlockData, "testBinData", &data, MVT_U64, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U64, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -500,7 +500,7 @@ namespace tut { S8 data = -31; - addValue(messageBlockData, "testBinData", &data, MVT_S8, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S8, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -517,7 +517,7 @@ namespace tut { S16 data = -31; - addValue(messageBlockData, "testBinData", &data, MVT_S16, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S16, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -534,7 +534,7 @@ namespace tut { S32 data = -3100; - addValue(messageBlockData, "testBinData", &data, MVT_S32, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S32, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -551,7 +551,7 @@ namespace tut { S64 data = -31003100; - addValue(messageBlockData, "testBinData", &data, MVT_S64, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S64, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -568,7 +568,7 @@ namespace tut { F32 data = 1234.1234f; - addValue(messageBlockData, "testBinData", &data, MVT_F32, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_F32, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -585,7 +585,7 @@ namespace tut { F64 data = 1234.1234; - addValue(messageBlockData, "testBinData", &data, MVT_F64, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_F64, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -602,7 +602,7 @@ namespace tut { LLVector3 data(1,2,3); - addValue(messageBlockData, "testBinData", &data, MVT_LLVector3, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector3, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -619,7 +619,7 @@ namespace tut { LLVector3d data(1,2,3); - addValue(messageBlockData, "testBinData", &data, MVT_LLVector3d, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector3d, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -637,7 +637,7 @@ namespace tut LLVector4 data(1,2,3,4); LLSD v = ll_sd_from_vector4(data); - addValue(messageBlockData, "testBinData", &data, MVT_LLVector4, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLVector4, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -657,7 +657,7 @@ namespace tut //we send a quaternion packed into a vec3 (w is infered) - so sizeof(vec) == 12 bytes not 16. LLVector3 vec = data.packToVector3(); - addValue(messageBlockData, "testBinData", &vec, MVT_LLQuaternion, sizeof(vec)); + addValue(messageBlockData, (char *)"testBinData", &vec, MVT_LLQuaternion, sizeof(vec)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -674,7 +674,7 @@ namespace tut { LLUUID data("01234567-0123-0123-0123-234567abcdef"); - addValue(messageBlockData, "testBinData", &data, MVT_LLUUID, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_LLUUID, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -696,8 +696,8 @@ namespace tut LLMsgData* md = new LLMsgData("testMessage"); LLMsgBlkData* mbd = new LLMsgBlkData("testBlock", 0); - addValue(mbd, "testBoolFalse", &valueFalse, MVT_BOOL, sizeof(BOOL)); - addValue(mbd, "testBoolTrue", &valueTrue, MVT_BOOL, sizeof(BOOL)); + addValue(mbd, (char *)"testBoolFalse", &valueFalse, MVT_BOOL, sizeof(BOOL)); + addValue(mbd, (char *)"testBoolTrue", &valueTrue, MVT_BOOL, sizeof(BOOL)); md->addBlock(mbd); LLSDMessageBuilder builder = defaultBuilder(); @@ -715,7 +715,7 @@ namespace tut U32 data(0xff887766); LLSD v = ll_sd_from_ipaddr(data); - addValue(messageBlockData, "testBinData", &data, MVT_IP_ADDR, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_IP_ADDR, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -732,7 +732,7 @@ namespace tut { U16 data = 0xff88; - addValue(messageBlockData, "testBinData", &data, MVT_IP_PORT, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_IP_PORT, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -749,7 +749,7 @@ namespace tut { U16 data[3] = {0,1,2}; - addValue(messageBlockData, "testBinData", &data, MVT_U16Vec3, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16Vec3, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -769,7 +769,7 @@ namespace tut { U16 data[4] = {0,1,2,4}; - addValue(messageBlockData, "testBinData", &data, MVT_U16Quat, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_U16Quat, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); @@ -789,7 +789,7 @@ namespace tut { S16 data[19] = {0,-1,2,-4,5,-6,7,-8,9,-10,11,-12,13,-14,15,16,17,18}; - addValue(messageBlockData, "testBinData", &data, MVT_S16Array, sizeof(data)); + addValue(messageBlockData, (char *)"testBinData", &data, MVT_S16Array, sizeof(data)); messageData->addBlock(messageBlockData); LLSDMessageBuilder builder = defaultBuilder(); diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp index f668867a02..7869763302 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.cpp +++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp @@ -283,7 +283,7 @@ void LLMediaPluginTest::bindTexture(GLuint texture, GLint row_length, GLint alig //////////////////////////////////////////////////////////////////////////////// // -bool LLMediaPluginTest::checkGLError(char *name) +bool LLMediaPluginTest::checkGLError(const char *name) { bool result = false; GLenum error = glGetError(); diff --git a/indra/test_apps/llplugintest/llmediaplugintest.h b/indra/test_apps/llplugintest/llmediaplugintest.h index 2d0ba0e3f6..095a2ea3b3 100644 --- a/indra/test_apps/llplugintest/llmediaplugintest.h +++ b/indra/test_apps/llplugintest/llmediaplugintest.h @@ -87,7 +87,7 @@ class LLMediaPluginTest : public LLPluginClassMediaOwner void mouseMove( int x, int y ); void bindTexture(GLuint texture, GLint row_length = 0, GLint alignment = 1); - bool checkGLError(char *name = "OpenGL"); + bool checkGLError(const char *name = "OpenGL"); void drawGeometry( int panel ); void startPanelHighlight( float red, float green, float blue, float line_width ); void endPanelHighlight(); |