diff options
28 files changed, 416 insertions, 125 deletions
diff --git a/doc/contributions.txt b/doc/contributions.txt index 16327d0917..96ee446a0c 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -72,6 +72,7 @@ Aleric Inglewood VWR-13996 VWR-14426 SNOW-84 + SNOW-477 SNOW-766 STORM-163 Ales Beaumont @@ -174,6 +175,7 @@ Boroondas Gupte VWR-233 VWR-20583 VWR-20891 + VWR-23455 WEB-262 Bulli Schumann CT-218 diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake index 96434e38fa..dcf44cd642 100644 --- a/indra/cmake/FMOD.cmake +++ b/indra/cmake/FMOD.cmake @@ -7,8 +7,10 @@ if (FMOD) set(FMOD_FIND_REQUIRED ON) include(FindFMOD) else (STANDALONE) - include(Prebuilt) - use_prebuilt_binary(fmod) + if (INSTALL_PROPRIETARY) + include(Prebuilt) + use_prebuilt_binary(fmod) + endif (INSTALL_PROPRIETARY) if (WINDOWS) set(FMOD_LIBRARY fmod) diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index e869b9717c..21ec622819 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -14,7 +14,6 @@ include(LLVFS) include_directories( ${LLAUDIO_INCLUDE_DIRS} - ${FMOD_INCLUDE_DIR} ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} @@ -45,6 +44,10 @@ set(llaudio_HEADER_FILES ) if (FMOD) + include_directories( + ${FMOD_INCLUDE_DIR} + ) + list(APPEND llaudio_SOURCE_FILES llaudioengine_fmod.cpp lllistener_fmod.cpp diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 4a66a31c35..522b99bc02 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -38,6 +38,8 @@ #include "message.h" #include "llmemtype.h" +#include <boost/regex.hpp> + // llsd serialization constants static const std::string AGENTS("agents"); static const std::string GROUPS("groups"); @@ -551,6 +553,31 @@ std::string LLCacheName::buildUsername(const std::string& full_name) return full_name; } +//static +std::string LLCacheName::buildLegacyName(const std::string& complete_name) +{ + boost::regex complete_name_regex("(.+)( \\()([A-Za-z]+)(.[A-Za-z]+)*(\\))"); + boost::match_results<std::string::const_iterator> name_results; + if (!boost::regex_match(complete_name, name_results, complete_name_regex)) return complete_name; + + std::string legacy_name = name_results[3]; + // capitalize the first letter + std::string cap_letter = legacy_name.substr(0, 1); + LLStringUtil::toUpper(cap_letter); + legacy_name = cap_letter + legacy_name.substr(1); + + if (name_results[4].matched) + { + std::string last_name = name_results[4]; + std::string cap_letter = last_name.substr(1, 1); + LLStringUtil::toUpper(cap_letter); + last_name = cap_letter + last_name.substr(2); + legacy_name = legacy_name + " " + last_name; + } + + return legacy_name; +} + // This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer. // The reason it is a slot is so that the legacy get() function below can bind an old callback // and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index b469803060..b108e37157 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -90,6 +90,12 @@ public: // "Random Linden" -> "random.linden" static std::string buildUsername(const std::string& name); + // Converts a complete display name to a legacy name + // if possible, otherwise returns the input + // "Alias (random.linden)" -> "Random Linden" + // "Something random" -> "Something random" + static std::string buildLegacyName(const std::string& name); + // If available, this method copies the group name into the string // provided. The caller must allocate at least // DB_GROUP_NAME_BUF_SIZE characters. If not available, this diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index f58c07754f..f49dfec82b 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -972,7 +972,7 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const // LLUrlEntryNoLink::LLUrlEntryNoLink() { - mPattern = boost::regex("<nolink>[^<]*</nolink>", + mPattern = boost::regex("<nolink>.*</nolink>", boost::regex::perl|boost::regex::icase); } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e161b67184..5ac076ae1b 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3874,7 +3874,7 @@ <key>Type</key> <string>String</string> <key>Value</key> - <string>http://search.secondlife.com/viewer/[CATEGORY]?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD]</string> + <string>http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD]</string> </map> <key>HighResSnapshot</key> <map> @@ -12330,5 +12330,16 @@ <key>Value</key> <real>300.0</real> </map> + <key>GroupMembersSortOrder</key> + <map> + <key>Comment</key> + <string>The order by which group members will be sorted (name|donated|online)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>name</string> + </map> </map> </llsd> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 21dfc0d5e2..8dd4b62a37 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 24 +version 25 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -149,7 +149,7 @@ WLSkyDetail 1 48 RenderDeferred 1 0 RenderDeferredSSAO 1 0 RenderShadowDetail 1 0 -RenderUseFBO 1 1 +RenderUseFBO 1 0 // // Ultra graphics (REALLY PURTY!) @@ -177,7 +177,7 @@ WLSkyDetail 1 128 RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderShadowDetail 1 2 -RenderUseFBO 1 1 +RenderUseFBO 1 0 // // Class Unknown Hardware (unknown) diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt index 9603921e94..a6807e6dc1 100644 --- a/indra/newview/featuretable_xp.txt +++ b/indra/newview/featuretable_xp.txt @@ -1,4 +1,4 @@ -version 24 +version 25 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -144,7 +144,7 @@ WLSkyDetail 1 48 RenderDeferred 1 0 RenderDeferredSSAO 1 0 RenderShadowDetail 1 0 -RenderUseFBO 1 1 +RenderUseFBO 1 0 // // Ultra graphics (REALLY PURTY!) @@ -171,7 +171,7 @@ WLSkyDetail 1 128 RenderDeferred 1 0 RenderDeferredSSAO 1 0 RenderShadowDetail 1 0 -RenderUseFBO 1 1 +RenderUseFBO 1 0 // // Class Unknown Hardware (unknown) diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index d1cd335783..d5712f80cf 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -52,7 +52,7 @@ LangString LanguageCode ${LANG_JAPANESE} "ja" LangString LanguageCode ${LANG_ITALIAN} "it" LangString LanguageCode ${LANG_KOREAN} "ko" LangString LanguageCode ${LANG_DUTCH} "nl" -LangString LanguageCode ${LANG_POLISH} "da" +LangString LanguageCode ${LANG_POLISH} "pl" LangString LanguageCode ${LANG_PORTUGUESEBR} "pt" LangString LanguageCode ${LANG_SIMPCHINESE} "zh" diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 378c4358b3..cb5cf4a61d 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -54,6 +54,7 @@ #include "llviewertexteditor.h" #include "llworld.h" #include "lluiconstants.h" +#include "llstring.h" #include "llviewercontrol.h" @@ -260,7 +261,7 @@ public: if((chat.mFromID.isNull() && chat.mFromName.empty()) || chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull()) { mSourceType = CHAT_SOURCE_SYSTEM; - } + } mUserNameFont = style_params.font(); LLTextBox* user_name = getChild<LLTextBox>("user_name"); @@ -268,14 +269,14 @@ public: user_name->setColor(style_params.color()); if (chat.mFromName.empty() - || mSourceType == CHAT_SOURCE_SYSTEM - || mAvatarID.isNull()) + || mSourceType == CHAT_SOURCE_SYSTEM) { mFrom = LLTrans::getString("SECOND_LIFE"); user_name->setValue(mFrom); updateMinUserNameWidth(); } else if (mSourceType == CHAT_SOURCE_AGENT + && !mAvatarID.isNull() && chat.mChatStyle != CHAT_STYLE_HISTORY) { // ...from a normal user, lookup the name and fill in later. @@ -288,7 +289,41 @@ public: LLAvatarNameCache::get(mAvatarID, boost::bind(&LLChatHistoryHeader::onAvatarNameCache, this, _1, _2)); } - else { + else if (chat.mChatStyle == CHAT_STYLE_HISTORY || + mSourceType == CHAT_SOURCE_AGENT) + { + //if it's an avatar name with a username add formatting + S32 username_start = chat.mFromName.rfind(" ("); + S32 username_end = chat.mFromName.rfind(')'); + + if (username_start != std::string::npos && + username_end == (chat.mFromName.length() - 1)) + { + mFrom = chat.mFromName.substr(0, username_start); + user_name->setValue(mFrom); + + if (gSavedSettings.getBOOL("NameTagShowUsernames")) + { + std::string username = chat.mFromName.substr(username_start + 2); + username = username.substr(0, username.length() - 1); + LLStyle::Params style_params_name; + LLColor4 userNameColor = LLUIColorTable::instance().getColor("EmphasisColor"); + style_params_name.color(userNameColor); + style_params_name.font.name("SansSerifSmall"); + style_params_name.font.style("NORMAL"); + style_params_name.readonly_color(userNameColor); + user_name->appendText(" - " + username, FALSE, style_params_name); + } + } + else + { + mFrom = chat.mFromName; + user_name->setValue(mFrom); + updateMinUserNameWidth(); + } + } + else + { // ...from an object, just use name as given mFrom = chat.mFromName; user_name->setValue(mFrom); @@ -367,7 +402,9 @@ public: user_name->setValue( LLSD(av_name.mDisplayName ) ); user_name->setToolTip( av_name.mUsername ); - if (gSavedSettings.getBOOL("NameTagShowUsernames") && LLAvatarNameCache::useDisplayNames()) + if (gSavedSettings.getBOOL("NameTagShowUsernames") && + LLAvatarNameCache::useDisplayNames() && + !av_name.mIsDisplayNameDefault) { LLStyle::Params style_params_name; LLColor4 userNameColor = LLUIColorTable::instance().getColor("EmphasisColor"); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index fe8a46e908..914e7a3df0 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -430,8 +430,9 @@ void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& histo } else { - // Legacy chat logs only wrote the legacy name, not the agent_id - gCacheName->getUUID(from, from_id); + // convert it to a legacy name if we have a complete name + std::string legacy_name = gCacheName->buildLegacyName(from); + gCacheName->getUUID(legacy_name, from_id); } std::string timestamp = msg[IM_TIME]; @@ -526,8 +527,16 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline() void LLIMModel::LLIMSession::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name) { - // if username is empty, display names isn't enabled, use the display name - mHistoryFileName = av_name.mUsername.empty() ? av_name.mDisplayName : av_name.mUsername; + if (av_name.mLegacyFirstName.empty()) + { + // if mLegacyFirstName is empty it means display names is off and the + // data came from the gCacheName, mDisplayName will be the legacy name + mHistoryFileName = LLCacheName::cleanFullName(av_name.mDisplayName); + } + else + { + mHistoryFileName = LLCacheName::cleanFullName(av_name.getLegacyName()); + } } void LLIMModel::LLIMSession::buildHistoryFileName() @@ -737,8 +746,18 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) - { - LLLogChat::saveHistory(file_name, from, from_id, utf8_text); + { + std::string from_name = from; + + LLAvatarName av_name; + if (!from_id.isNull() && + LLAvatarNameCache::get(from_id, &av_name) && + !av_name.mIsDisplayNameDefault) + { + from_name = av_name.getCompleteName(); + } + + LLLogChat::saveHistory(file_name, from_name, from_id, utf8_text); return true; } else diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index c8fd1e1d9a..8c70b1e973 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -26,18 +26,13 @@ #include "llviewerprecompiledheaders.h" -#include "lllogchat.h" - -// viewer includes #include "llagent.h" #include "llagentui.h" +#include "lllogchat.h" #include "lltrans.h" #include "llviewercontrol.h" -// library includes -#include "llchat.h" #include "llinstantmessage.h" -#include "llsdserialize.h" #include "llsingleton.h" // for LLSingleton #include <boost/algorithm/string/trim.hpp> @@ -65,7 +60,6 @@ const std::string IM_TIME("time"); const std::string IM_TEXT("message"); const std::string IM_FROM("from"); const std::string IM_FROM_ID("from_id"); -const std::string IM_SOURCE_TYPE("source_type"); const static std::string IM_SEPARATOR(": "); const static std::string NEW_LINE("\n"); @@ -93,7 +87,7 @@ const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+ * Regular expression suitable to match names like * "You", "Second Life", "Igor ProductEngine", "Object", "Mega House" */ -const static boost::regex NAME_AND_TEXT("(You:|Second Life:|[^\\s:]+\\s*[:]{1}|\\S+\\s+[^\\s:]+[:]{1})?(\\s*)(.*)"); +const static boost::regex NAME_AND_TEXT("([^:]+[:]{1})?(\\s*)(.*)"); //is used to parse complex object names like "Xstreet SL Terminal v2.2.5 st" const static std::string NAME_TEXT_DIVIDER(": "); @@ -190,8 +184,7 @@ std::string LLLogChat::makeLogFileName(std::string filename) { filename = cleanFileName(filename); filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS,filename); - // new files are llsd notation format - filename += ".llsd"; + filename += ".txt"; return filename; } @@ -241,18 +234,6 @@ void LLLogChat::saveHistory(const std::string& filename, const LLUUID& from_id, const std::string& line) { - LLChat chat; - chat.mText = line; - chat.mFromName = from; - chat.mFromID = from_id; - // default to being from an agent - chat.mSourceType = CHAT_SOURCE_AGENT; - saveHistory(filename, chat); -} - -//static -void LLLogChat::saveHistory(const std::string& filename, const LLChat& chat) -{ std::string tmp_filename = filename; LLStringUtil::trim(tmp_filename); if (tmp_filename.empty()) @@ -273,27 +254,89 @@ void LLLogChat::saveHistory(const std::string& filename, const LLChat& chat) LLSD item; if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) - item[IM_TIME] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")); + item["time"] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")); - item[IM_FROM_ID] = chat.mFromID; - item[IM_TEXT] = chat.mText; - item[IM_SOURCE_TYPE] = chat.mSourceType; + item["from_id"] = from_id; + item["message"] = line; //adding "Second Life:" for all system messages to make chat log history parsing more reliable - if (chat.mFromName.empty() && chat.mFromID.isNull()) + if (from.empty() && from_id.isNull()) { - item[IM_FROM] = SYSTEM_FROM; + item["from"] = SYSTEM_FROM; } else { - item[IM_FROM] = chat.mFromName; + item["from"] = from; } - file << LLSDOStreamer<LLSDNotationFormatter>(item) << std::endl; + file << LLChatLogFormatter(item) << std::endl; file.close(); } +void LLLogChat::loadHistory(const std::string& filename, void (*callback)(ELogLineType, const LLSD&, void*), void* userdata) +{ + if(!filename.size()) + { + llwarns << "Filename is Empty!" << llendl; + return ; + } + + LLFILE* fptr = LLFile::fopen(makeLogFileName(filename), "r"); /*Flawfinder: ignore*/ + if (!fptr) + { + callback(LOG_EMPTY, LLSD(), userdata); + return; //No previous conversation with this name. + } + else + { + char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ + char *bptr; + S32 len; + bool firstline=TRUE; + + if ( fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END) ) + { //File is smaller than recall size. Get it all. + firstline = FALSE; + if ( fseek(fptr, 0, SEEK_SET) ) + { + fclose(fptr); + return; + } + } + + while ( fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr) ) + { + len = strlen(buffer) - 1; /*Flawfinder: ignore*/ + for ( bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; + + if (!firstline) + { + LLSD item; + std::string line(buffer); + std::istringstream iss(line); + + if (!LLChatLogParser::parse(line, item)) + { + item["message"] = line; + callback(LOG_LINE, item, userdata); + } + else + { + callback(LOG_LLSD, item, userdata); + } + } + else + { + firstline = FALSE; + } + } + callback(LOG_END, LLSD(), userdata); + + fclose(fptr); + } +} + void append_to_last_message(std::list<LLSD>& messages, const std::string& line) { if (!messages.size()) return; @@ -367,24 +410,52 @@ void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& me fclose(fptr); } -// static -bool LLChatLogParser::parse(const std::string& raw, LLSD& im) +//*TODO mark object's names in a special way so that they will be distinguishable form avatar name +//which are more strict by its nature (only firstname and secondname) +//Example, an object's name can be writen like "Object <actual_object's_name>" +void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const { - if (!raw.length()) return false; + if (!im.isMap()) + { + llwarning("invalid LLSD type of an instant message", 0); + return; + } + + if (im[IM_TIME].isDefined()) +{ + std::string timestamp = im[IM_TIME].asString(); + boost::trim(timestamp); + ostr << '[' << timestamp << ']' << TWO_SPACES; + } - im = LLSD::emptyMap(); + //*TODO mark object's names in a special way so that they will be distinguishable form avatar name + //which are more strict by its nature (only firstname and secondname) + //Example, an object's name can be writen like "Object <actual_object's_name>" + if (im[IM_FROM].isDefined()) + { + std::string from = im[IM_FROM].asString(); + boost::trim(from); + if (from.size()) + { + ostr << from << IM_SEPARATOR; + } + } - // In Viewer 2.1 we added UUID to chat/IM logging so we can look up - // display names - if (raw[0] == '{') + if (im[IM_TEXT].isDefined()) { - // ...this is a viewer 2.1, new-style LLSD notation format log - std::istringstream raw_stream(raw); - LLPointer<LLSDParser> parser = new LLSDNotationParser(); - S32 count = parser->parse(raw_stream, im, raw.length()); - // expect several map items per parsed line - return (count != LLSDParser::PARSE_FAILURE); + std::string im_text = im[IM_TEXT].asString(); + + //multilined text will be saved with prepended spaces + boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX); + ostr << im_text; } + } + +bool LLChatLogParser::parse(std::string& raw, LLSD& im) +{ + if (!raw.length()) return false; + + im = LLSD::emptyMap(); //matching a timestamp boost::match_results<std::string::const_iterator> matches; diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 8b1cc3484f..6958d56311 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -41,22 +41,49 @@ public: }; static std::string timestamp(bool withdate = false); static std::string makeLogFileName(std::string(filename)); - - // Log a single line item to the appropriate chat file - static void saveHistory(const std::string& filename, const LLChat& chat); - - // Prefer the above version - it saves more metadata about the item static void saveHistory(const std::string& filename, const std::string& from, const LLUUID& from_id, const std::string& line); + /** @deprecated @see loadAllHistory() */ + static void loadHistory(const std::string& filename, + void (*callback)(ELogLineType, const LLSD&, void*), + void* userdata); + static void loadAllHistory(const std::string& file_name, std::list<LLSD>& messages); private: static std::string cleanFileName(std::string filename); }; /** + * Formatter for the plain text chat log files + */ +class LLChatLogFormatter +{ +public: + LLChatLogFormatter(const LLSD& im) : mIM(im) {} + virtual ~LLChatLogFormatter() {}; + + friend std::ostream& operator<<(std::ostream& str, const LLChatLogFormatter& formatter) + { + formatter.format(formatter.mIM, str); + return str; + } + +protected: + + /** + * Format an instant message to a stream + * Timestamps and sender names are required + * New lines of multilined messages are prepended with a space + */ + void format(const LLSD& im, std::ostream& ostr) const; + + LLSD mIM; +}; + +/** * Parser for the plain text chat log files */ class LLChatLogParser @@ -74,7 +101,7 @@ public: * * @return false if failed to parse mandatory data - message text */ - static bool parse(const std::string& raw, LLSD& im); + static bool parse(std::string& raw, LLSD& im); protected: LLChatLogParser(); @@ -86,6 +113,5 @@ extern const std::string IM_TIME; //("time"); extern const std::string IM_TEXT; //("message"); extern const std::string IM_FROM; //("from"); extern const std::string IM_FROM_ID; //("from_id"); -extern const std::string IM_SOURCE_TYPE; //("source_type"); #endif diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index f16cc4cef4..180695e40b 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -46,6 +46,8 @@ #include "llchathistory.h" #include "llstylemap.h" +#include "llavatarnamecache.h" + #include "lldraghandle.h" #include "llbottomtray.h" @@ -179,7 +181,21 @@ void LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args) if (gSavedPerAccountSettings.getBOOL("LogNearbyChat")) { - LLLogChat::saveHistory("chat", chat); + std::string from_name = chat.mFromName; + + if (chat.mSourceType == CHAT_SOURCE_AGENT) + { + // if the chat is coming from an agent, log the complete name + LLAvatarName av_name; + LLAvatarNameCache::get(chat.mFromID, &av_name); + + if (!av_name.mIsDisplayNameDefault) + { + from_name = av_name.getCompleteName(); + } + } + + LLLogChat::saveHistory("chat", from_name, chat.mFromID, chat.mText); } } @@ -248,11 +264,23 @@ void LLNearbyChat::processChatHistoryStyleUpdate(const LLSD& newvalue) nearby_chat->updateChatHistoryStyle(); } -bool isTwoWordsName(const std::string& name) +bool isWordsName(const std::string& name) { - //checking for a single space - S32 pos = name.find(' ', 0); - return std::string::npos != pos && name.rfind(' ', name.length()) == pos && 0 != pos && name.length()-1 != pos; + // checking to see if it's display name plus username in parentheses + S32 open_paren = name.find(" (", 0); + S32 close_paren = name.find(')', 0); + + if (open_paren != std::string::npos && + close_paren == name.length()-1) + { + return true; + } + else + { + //checking for a single space + S32 pos = name.find(' ', 0); + return std::string::npos != pos && name.rfind(' ', name.length()) == pos && 0 != pos && name.length()-1 != pos; + } } void LLNearbyChat::loadHistory() @@ -275,9 +303,10 @@ void LLNearbyChat::loadHistory() from_id = msg[IM_FROM_ID].asUUID(); } else - { - gCacheName->getUUID(from, from_id); - } + { + std::string legacy_name = gCacheName->buildLegacyName(from); + gCacheName->getUUID(legacy_name, from_id); + } LLChat chat; chat.mFromName = from; @@ -286,18 +315,15 @@ void LLNearbyChat::loadHistory() chat.mTimeStr = msg[IM_TIME].asString(); chat.mChatStyle = CHAT_STYLE_HISTORY; - if (msg.has(IM_SOURCE_TYPE)) - { - S32 source_type = msg[IM_SOURCE_TYPE].asInteger(); - chat.mSourceType = (EChatSourceType)source_type; - } - else if (from_id.isNull() && SYSTEM_FROM == from) + chat.mSourceType = CHAT_SOURCE_AGENT; + if (from_id.isNull() && SYSTEM_FROM == from) { chat.mSourceType = CHAT_SOURCE_SYSTEM; + } else if (from_id.isNull()) { - chat.mSourceType = isTwoWordsName(from) ? CHAT_SOURCE_UNKNOWN : CHAT_SOURCE_OBJECT; + chat.mSourceType = isWordsName(from) ? CHAT_SOURCE_UNKNOWN : CHAT_SOURCE_OBJECT; } addMessage(chat, true, do_not_log); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 35f898bfa6..0d1d96eae6 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -49,6 +49,7 @@ #include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llfocusmgr.h" +#include "llviewercontrol.h" #include "roles_constants.h" @@ -742,10 +743,12 @@ LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab() mHasMatch(FALSE), mNumOwnerAdditions(0) { + mUdpateSessionID = LLUUID::null; } LLPanelGroupMembersSubTab::~LLPanelGroupMembersSubTab() { + gSavedSettings.setString("GroupMembersSortOrder", mMembersList->getSortColumnName()); } BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) @@ -772,6 +775,17 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) // Show the member's profile on double click. mMembersList->setDoubleClickCallback(onMemberDoubleClick, this); mMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR); + + LLSD row; + row["columns"][0]["column"] = "name"; + row["columns"][1]["column"] = "donated"; + row["columns"][2]["column"] = "online"; + mMembersList->addElement(row); + std::string order_by = gSavedSettings.getString("GroupMembersSortOrder"); + if(!order_by.empty()) + { + mMembersList->sortByColumn(order_by, TRUE); + } LLButton* button = parent->getChild<LLButton>("member_invite", recurse); if ( button ) @@ -1529,6 +1543,10 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc) mMemberProgress = gdatap->mMembers.begin(); mPendingMemberUpdate = TRUE; mHasMatch = FALSE; + // Generate unique ID for current updateMembers()- see onNameCache for details. + // Using unique UUID is perhaps an overkill but this way we are perfectly safe + // from coincidences. + mUdpateSessionID.generate(); } else { @@ -1556,6 +1574,59 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc) } } +void LLPanelGroupMembersSubTab::addMemberToList(LLUUID id, LLGroupMemberData* data) +{ + LLUIString donated = getString("donation_area"); + donated.setArg("[AREA]", llformat("%d", data->getContribution())); + + LLSD row; + row["id"] = id; + + row["columns"][0]["column"] = "name"; + // value is filled in by name list control + + row["columns"][1]["column"] = "donated"; + row["columns"][1]["value"] = donated.getString(); + + row["columns"][2]["column"] = "online"; + row["columns"][2]["value"] = data->getOnlineStatus(); + row["columns"][2]["font"] = "SANSSERIF_SMALL"; + + mMembersList->addElement(row); + + mHasMatch = TRUE; +} + +void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, const LLUUID& id) +{ + // Update ID is used to determine whether member whose id is passed + // into onNameCache() was passed after current or previous user-initiated update. + // This is needed to avoid probable duplication of members in list after changing filter + // or adding of members of another group if gets for their names were called on + // previous update. If this id is from get() called from older update, + // we do nothing. + if (mUdpateSessionID != update_id) return; + + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if (!gdatap) + { + llwarns << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << llendl; + return; + } + + std::string fullname; + gCacheName->getFullName(id, fullname); + if (matchesSearchFilter(fullname)) + { + addMemberToList(id, gdatap->mMembers[id]); + if(!mMembersList->getEnabled()) + { + mMembersList->setEnabled(TRUE); + } + } + +} + void LLPanelGroupMembersSubTab::updateMembers() { mPendingMemberUpdate = FALSE; @@ -1580,12 +1651,13 @@ void LLPanelGroupMembersSubTab::updateMembers() //cleanup list only for first iretation if(mMemberProgress == gdatap->mMembers.begin()) + { mMembersList->deleteAllItems(); + } LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end(); - LLUIString donated = getString("donation_area"); - + S32 i = 0; for( ; mMemberProgress != end && i<UPDATE_MEMBERS_PER_FRAME; ++mMemberProgress, ++i) @@ -1593,38 +1665,19 @@ void LLPanelGroupMembersSubTab::updateMembers() if (!mMemberProgress->second) continue; // Do filtering on name if it is already in the cache. - bool add_member = true; - std::string fullname; if (gCacheName->getFullName(mMemberProgress->first, fullname)) { - if ( !matchesSearchFilter(fullname) ) + if (matchesSearchFilter(fullname)) { - add_member = false; + addMemberToList(mMemberProgress->first, mMemberProgress->second); } } - - if (add_member) + else { - donated.setArg("[AREA]", llformat("%d", mMemberProgress->second->getContribution())); - - LLSD row; - row["id"] = (*mMemberProgress).first; - - row["columns"][0]["column"] = "name"; - // value is filled in by name list control - - row["columns"][1]["column"] = "donated"; - row["columns"][1]["value"] = donated.getString(); - - row["columns"][2]["column"] = "online"; - row["columns"][2]["value"] = mMemberProgress->second->getOnlineStatus(); - row["columns"][2]["font"] = "SANSSERIF_SMALL"; - - LLScrollListItem* member = mMembersList->addElement(row); - - LLUUID id = member->getUUID(); - mHasMatch = TRUE; + // If name is not cached, onNameCache() should be called when it is cached and add this member to list. + gCacheName->get(mMemberProgress->first, FALSE, boost::bind(&LLPanelGroupMembersSubTab::onNameCache, + this, mUdpateSessionID, _1)); } } diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 6a773f1ebb..270259c16f 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -187,6 +187,9 @@ public: virtual void setGroupID(const LLUUID& id); + void addMemberToList(LLUUID id, LLGroupMemberData* data); + void onNameCache(const LLUUID& update_id, const LLUUID& id); + protected: typedef std::map<LLUUID, LLRoleMemberChangeType> role_change_data_map_t; typedef std::map<LLUUID, role_change_data_map_t*> member_role_changes_map_t; @@ -207,6 +210,9 @@ protected: BOOL mPendingMemberUpdate; BOOL mHasMatch; + // This id is generated after each user initiated member list update(opening Roles or changing filter) + LLUUID mUdpateSessionID; + member_role_changes_map_t mMemberRoleChangeData; U32 mNumOwnerAdditions; diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 5638374178..63076364bc 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -404,6 +404,7 @@ LLPanelOutfitEdit::LLPanelOutfitEdit() mAddWearablesPanel(NULL), mFolderViewFilterCmbBox(NULL), mListViewFilterCmbBox(NULL), + mWearableListManager(NULL), mPlusBtn(NULL), mWearablesGearMenuBtn(NULL), mGearMenuBtn(NULL) @@ -431,6 +432,7 @@ LLPanelOutfitEdit::LLPanelOutfitEdit() LLPanelOutfitEdit::~LLPanelOutfitEdit() { + delete mWearableListManager; delete mSavedFolderState; delete mCOFDragAndDropObserver; diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index 9f4119e73b..afd933c7fa 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -774,7 +774,7 @@ <string name="xml_file"> XML Fil </string> - <string name="dot_raw_file"> + <string name="raw_file"> RAW Fil </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index ae2991df45..afcb68f537 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -798,7 +798,7 @@ <string name="xml_file"> XML-Datei </string> - <string name="dot_raw_file"> + <string name="raw_file"> RAW-Datei </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index f22dcbfc8a..43af1fb958 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -339,7 +339,7 @@ <string name="avi_movie_file">AVI Movie File</string> <string name="xaf_animation_file">XAF Anim File</string> <string name="xml_file">XML File</string> - <string name="dot_raw_file">RAW File</string> + <string name="raw_file">RAW File</string> <string name="compressed_image_files">Compressed Images</string> <string name="load_files">Load Files</string> <string name="choose_the_directory">Choose Directory</string> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index ac12b700ee..5fa3d54de2 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -777,7 +777,7 @@ <string name="xml_file"> Archivo XML </string> - <string name="dot_raw_file"> + <string name="raw_file"> Archivo RAW </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index a7a766f6a6..af70048106 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -798,7 +798,7 @@ <string name="xml_file"> Fichier XML </string> - <string name="dot_raw_file"> + <string name="raw_file"> Fichier RAW </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 4fc0d19199..9dbfc2b79c 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -783,7 +783,7 @@ <string name="xml_file"> File XML </string> - <string name="dot_raw_file"> + <string name="raw_file"> File RAW </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index 072ae6c630..92bbedaee5 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -798,7 +798,7 @@ <string name="xml_file"> XML ファイル </string> - <string name="dot_raw_file"> + <string name="raw_file"> RAW ファイル </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/nl/strings.xml b/indra/newview/skins/default/xui/nl/strings.xml index 1ee26c3f24..844945913f 100644 --- a/indra/newview/skins/default/xui/nl/strings.xml +++ b/indra/newview/skins/default/xui/nl/strings.xml @@ -665,7 +665,7 @@ <string name="xml_file"> XML bestand </string> - <string name="dot_raw_file"> + <string name="raw_file"> RAW bestand </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index c9fe22f3c8..e355bdbb96 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -774,7 +774,7 @@ <string name="xml_file"> Plik XML </string> - <string name="dot_raw_file"> + <string name="raw_file"> Plik RAW </string> <string name="compressed_image_files"> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 2247b0a76b..800ad479fc 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -777,7 +777,7 @@ <string name="xml_file"> Arquivo XML </string> - <string name="dot_raw_file"> + <string name="raw_file"> Arquivo RAW </string> <string name="compressed_image_files"> |