diff options
218 files changed, 7025 insertions, 2746 deletions
diff --git a/etc/message.xml b/etc/message.xml index c17ae3656d..ebbb4e57a9 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -370,6 +370,14 @@  				</map>  				<!-- Server to client --> +				<key>DisplayNameUpdate</key> +				<map> +					<key>flavor</key> +					<string>llsd</string> +					<key>trusted-sender</key> +					<boolean>true</boolean> +				</map> +                  				<key>ParcelVoiceInfo</key>  				<map>  					<key>flavor</key> @@ -426,6 +434,14 @@            <boolean>true</boolean>          </map> +        <key>SetDisplayNameReply</key> +        <map> +          <key>flavor</key> +          <string>llsd</string> +          <key>trusted-sender</key> +          <boolean>true</boolean> +        </map> +          <key>DirLandReply</key>          <map>            <key>flavor</key> diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 2a036df06e..77740fb8bf 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -33,6 +33,7 @@ set(llcommon_SOURCE_FILES      llapp.cpp      llapr.cpp      llassettype.cpp +    llavatarname.cpp      llbase32.cpp      llbase64.cpp      llcommon.cpp @@ -115,6 +116,7 @@ set(llcommon_HEADER_FILES      llallocator.h      llallocator_heap_profile.h      llagentconstants.h +    llavatarname.h      llapp.h      llapr.h      llassettype.h diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp new file mode 100644 index 0000000000..14dc41591b --- /dev/null +++ b/indra/llcommon/llavatarname.cpp @@ -0,0 +1,119 @@ +/**  + * @file llavatarname.cpp + * @brief Represents name-related data for an avatar, such as the + * username/SLID ("bobsmith123" or "james.linden") and the display + * name ("James Cook") + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, 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 "llavatarname.h" + +#include "lldate.h" +#include "llsd.h" + +// Store these in pre-built std::strings to avoid memory allocations in +// LLSD map lookups +static const std::string USERNAME("username"); +static const std::string DISPLAY_NAME("display_name"); +static const std::string LEGACY_FIRST_NAME("legacy_first_name"); +static const std::string LEGACY_LAST_NAME("legacy_last_name"); +static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default"); +static const std::string DISPLAY_NAME_EXPIRES("display_name_expires"); +static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update"); + +LLAvatarName::LLAvatarName() +:	mUsername(), +	mDisplayName(), +	mLegacyFirstName(), +	mLegacyLastName(), +	mIsDisplayNameDefault(false), +	mIsDummy(false), +	mExpires(F64_MAX), +	mNextUpdate(0.0) +{ } + +bool LLAvatarName::operator<(const LLAvatarName& rhs) const +{ +	if (mUsername == rhs.mUsername) +		return mDisplayName < rhs.mDisplayName; +	else +		return mUsername < rhs.mUsername; +} + +LLSD LLAvatarName::asLLSD() const +{ +	LLSD sd; +	sd[USERNAME] = mUsername; +	sd[DISPLAY_NAME] = mDisplayName; +	sd[LEGACY_FIRST_NAME] = mLegacyFirstName; +	sd[LEGACY_LAST_NAME] = mLegacyLastName; +	sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault; +	sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires); +	sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate); +	return sd; +} + +void LLAvatarName::fromLLSD(const LLSD& sd) +{ +	mUsername = sd[USERNAME].asString(); +	mDisplayName = sd[DISPLAY_NAME].asString(); +	mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString(); +	mLegacyLastName = sd[LEGACY_LAST_NAME].asString(); +	mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean(); +	LLDate expires = sd[DISPLAY_NAME_EXPIRES]; +	mExpires = expires.secondsSinceEpoch(); +	LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE]; +	mNextUpdate = next_update.secondsSinceEpoch(); +} + +std::string LLAvatarName::getCompleteName() const +{ +	std::string name; +	if (!mUsername.empty()) +	{ +		name = mDisplayName + " (" + mUsername + ")"; +	} +	else +	{ +		// ...display names are off, legacy name is in mDisplayName +		name = mDisplayName; +	} +	return name; +} + +std::string LLAvatarName::getLegacyName() const +{ +	std::string name; +	name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() ); +	name = mLegacyFirstName; +	name += " "; +	name += mLegacyLastName; +	return name; +} diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h new file mode 100644 index 0000000000..650a09a125 --- /dev/null +++ b/indra/llcommon/llavatarname.h @@ -0,0 +1,101 @@ +/**  + * @file llavatarname.h + * @brief Represents name-related data for an avatar, such as the + * username/SLID ("bobsmith123" or "james.linden") and the display + * name ("James Cook") + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, 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 LLAVATARNAME_H +#define LLAVATARNAME_H + +#include <string> + +class LLSD; + +class LL_COMMON_API LLAvatarName +{ +public: +	LLAvatarName(); +	 +	bool operator<(const LLAvatarName& rhs) const; + +	LLSD asLLSD() const; + +	void fromLLSD(const LLSD& sd); + +	// For normal names, returns "James Linden (james.linden)" +	// When display names are disabled returns just "James Linden" +	std::string getCompleteName() const; + +	// Returns "James Linden" or "bobsmith123 Resident" for backwards +	// compatibility with systems like voice and muting +	// *TODO: Eliminate this in favor of username only +	std::string getLegacyName() const; + +	// "bobsmith123" or "james.linden", US-ASCII only +	std::string mUsername; + +	// "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode +	// Contains data whether or not user has explicitly set +	// a display name; may duplicate their username. +	std::string mDisplayName; + +	// For "James Linden", "James" +	// For "bobsmith123", "bobsmith123" +	// Used to communicate with legacy systems like voice and muting which +	// rely on old-style names. +	// *TODO: Eliminate this in favor of username only +	std::string mLegacyFirstName; + +	// For "James Linden", "Linden" +	// For "bobsmith123", "Resident" +	// see above for rationale +	std::string mLegacyLastName; + +	// If true, both display name and SLID were generated from +	// a legacy first and last name, like "James Linden (james.linden)" +	bool mIsDisplayNameDefault; + +	// Under error conditions, we may insert "dummy" records with +	// names like "???" into caches as placeholders.  These can be +	// shown in UI, but are not serialized. +	bool mIsDummy; + +	// Names can change, so need to keep track of when name was +	// last checked. +	// Unix time-from-epoch seconds for efficiency +	F64 mExpires; +	 +	// You can only change your name every N hours, so record +	// when the next update is allowed +	// Unix time-from-epoch seconds +	F64 mNextUpdate; +}; + +#endif diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h index 63cce24005..2cc6e5c9bc 100644 --- a/indra/llcommon/llchat.h +++ b/indra/llcommon/llchat.h @@ -34,7 +34,6 @@  #ifndef LL_LLCHAT_H  #define LL_LLCHAT_H -#include "llstring.h"  #include "lluuid.h"  #include "v3math.h" @@ -77,7 +76,7 @@ typedef enum e_chat_style  class LLChat  {  public: -	LLChat(const std::string& text = LLStringUtil::null) +	LLChat(const std::string& text = std::string())  	:	mText(text),  		mFromName(),  		mFromID(), diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 2693c0e22b..2d391839ef 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -737,14 +737,17 @@ void LLStringOps::setupDatetimeInfo (bool daylight)  	nowT = time (NULL); -	tmpT = localtime (&nowT); -	localT = mktime (tmpT); -  	tmpT = gmtime (&nowT);  	gmtT = mktime (tmpT); +	tmpT = localtime (&nowT); +	localT = mktime (tmpT); +	  	sLocalTimeOffset = (long) (gmtT - localT); - +	if (tmpT->tm_isdst) +	{ +		sLocalTimeOffset -= 60 * 60;	// 1 hour +	}  	sPacificDaylightTime = daylight;  	sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60; diff --git a/indra/llinventory/lltransactionflags.cpp b/indra/llinventory/lltransactionflags.cpp index e0f87aa7db..79f8589bb1 100644 --- a/indra/llinventory/lltransactionflags.cpp +++ b/indra/llinventory/lltransactionflags.cpp @@ -114,6 +114,9 @@ std::string build_transfer_message_to_source(  	std::ostringstream ostr;  	if(dest_id.isNull())  	{ +		// *NOTE: Do not change these strings!  The viewer matches +		// them in llviewermessage.cpp to perform localization. +		// If you need to make changes, add a new, localizable message. JC  		ostr << "You paid L$" << amount;  		switch(transaction_type)  		{ @@ -160,6 +163,9 @@ std::string build_transfer_message_to_destination(  		return description;  	}  	std::ostringstream ostr; +	// *NOTE: Do not change these strings!  The viewer matches +	// them in llviewermessage.cpp to perform localization. +	// If you need to make changes, add a new, localizable message. JC  	ostr << source_name << " paid you L$" << amount;  	append_reason(ostr, transaction_type, description);  	ostr << "."; diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 1f8ee26716..1cad0f6d22 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -25,6 +25,7 @@ set(llmessage_SOURCE_FILES      llares.cpp      llareslistener.cpp      llassetstorage.cpp +    llavatarnamecache.cpp      llblowfishcipher.cpp      llbuffer.cpp      llbufferstream.cpp @@ -110,6 +111,7 @@ set(llmessage_HEADER_FILES      llares.h      llareslistener.h      llassetstorage.h +    llavatarnamecache.h      llblowfishcipher.h      llbuffer.h      llbufferstream.h @@ -248,6 +250,7 @@ if (LL_TESTS)      "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py"      ) +  LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}") diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp new file mode 100644 index 0000000000..912f34fcae --- /dev/null +++ b/indra/llmessage/llavatarnamecache.cpp @@ -0,0 +1,795 @@ +/**  + * @file llavatarnamecache.cpp + * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names + * ("James Cook") from avatar UUIDs. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, 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 "llavatarnamecache.h" + +#include "llcachename.h"		// we wrap this system +#include "llframetimer.h" +#include "llhttpclient.h" +#include "llsd.h" +#include "llsdserialize.h" + +#include <boost/tokenizer.hpp> + +#include <map> +#include <set> + +namespace LLAvatarNameCache +{ +	// Manual override for display names - can disable even if the region +	// supports it. +	bool sUseDisplayNames = true; + +	// Cache starts in a paused state until we can determine if the +	// current region supports display names. +	bool sRunning = false; +	 +	// Base lookup URL for name service. +	// On simulator, loaded from indra.xml +	// On viewer, usually a simulator capability (at People API team's request) +	// Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/" +	std::string sNameLookupURL; + +	// accumulated agent IDs for next query against service +	typedef std::set<LLUUID> ask_queue_t; +	ask_queue_t sAskQueue; + +	// agent IDs that have been requested, but with no reply +	// maps agent ID to frame time request was made +	typedef std::map<LLUUID, F64> pending_queue_t; +	pending_queue_t sPendingQueue; + +	// Callbacks to fire when we received a name. +	// May have multiple callbacks for a single ID, which are +	// represented as multiple slots bound to the signal. +	// Avoid copying signals via pointers. +	typedef std::map<LLUUID, callback_signal_t*> signal_map_t; +	signal_map_t sSignalMap; + +	// names we know about +	typedef std::map<LLUUID, LLAvatarName> cache_t; +	cache_t sCache; + +	// Send bulk lookup requests a few times a second at most +	// only need per-frame timing resolution +	LLFrameTimer sRequestTimer; + +	// Periodically clean out expired entries from the cache +	LLFrameTimer sEraseExpiredTimer; + +	//----------------------------------------------------------------------- +	// Internal methods +	//----------------------------------------------------------------------- + +	// Handle name response off network. +	// Optionally skip adding to cache, used when this is a fallback to the +	// legacy name system. +	void processName(const LLUUID& agent_id, +					 const LLAvatarName& av_name, +					 bool add_to_cache); + +	void requestNamesViaCapability(); + +	// Legacy name system callback +	void legacyNameCallback(const LLUUID& agent_id, +		const std::string& full_name, +		bool is_group); + +	void requestNamesViaLegacy(); + +	// Fill in an LLAvatarName with the legacy name data +	void buildLegacyName(const std::string& full_name, +						 LLAvatarName* av_name); + +	// Do a single callback to a given slot +	void fireSignal(const LLUUID& agent_id, +					const callback_slot_t& slot, +					const LLAvatarName& av_name); +	 +	// Is a request in-flight over the network? +	bool isRequestPending(const LLUUID& agent_id); + +	// Erase expired names from cache +	void eraseExpired(); + +	bool expirationFromCacheControl(LLSD headers, F64 *expires); +} + +/* Sample response: +<?xml version="1.0"?> +<llsd> +  <map> +    <key>agents</key> +    <array> +      <map> +        <key>display_name_next_update</key> +        <date>2010-04-16T21:34:02+00:00Z</date> +        <key>display_name_expires</key> +        <date>2010-04-16T21:32:26.142178+00:00Z</date> +        <key>display_name</key> +        <string>MickBot390 LLQABot</string> +        <key>sl_id</key> +        <string>mickbot390.llqabot</string> +        <key>id</key> +        <string>0012809d-7d2d-4c24-9609-af1230a37715</string> +        <key>is_display_name_default</key> +        <boolean>false</boolean> +      </map> +      <map> +        <key>display_name_next_update</key> +        <date>2010-04-16T21:34:02+00:00Z</date> +        <key>display_name_expires</key> +        <date>2010-04-16T21:32:26.142178+00:00Z</date> +        <key>display_name</key> +        <string>Bjork Gudmundsdottir</string> +        <key>sl_id</key> +        <string>sardonyx.linden</string> +        <key>id</key> +        <string>3941037e-78ab-45f0-b421-bd6e77c1804d</string> +        <key>is_display_name_default</key> +        <boolean>true</boolean> +      </map> +    </array> +  </map> +</llsd> +*/ + +class LLAvatarNameResponder : public LLHTTPClient::Responder +{ +private: +	// need to store agent ids that are part of this request in case of +	// an error, so we can flag them as unavailable +	std::vector<LLUUID> mAgentIDs; + +	// Need the headers to look up Expires: and Retry-After: +	LLSD mHeaders; +	 +public: +	LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids) +	:	mAgentIDs(agent_ids), +		mHeaders() +	{ } +	 +	/*virtual*/ void completedHeader(U32 status, const std::string& reason,  +		const LLSD& headers) +	{ +		mHeaders = headers; +	} + +	/*virtual*/ void result(const LLSD& content) +	{ +		// Pull expiration out of headers if available +		F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders); + +		LLSD agents = content["agents"]; +		LLSD::array_const_iterator it = agents.beginArray(); +		for ( ; it != agents.endArray(); ++it) +		{ +			const LLSD& row = *it; +			LLUUID agent_id = row["id"].asUUID(); + +			LLAvatarName av_name; +			av_name.fromLLSD(row); + +			// Use expiration time from header +			av_name.mExpires = expires; + +			// Some avatars don't have explicit display names set +			if (av_name.mDisplayName.empty()) +			{ +				av_name.mDisplayName = av_name.mUsername; +			} + +			// cache it and fire signals +			LLAvatarNameCache::processName(agent_id, av_name, true); +		} + +		// Same logic as error response case +		LLSD unresolved_agents = content["bad_ids"]; +		if (unresolved_agents.size() > 0) +		{ +			const std::string DUMMY_NAME("\?\?\?"); +			LLAvatarName av_name; +			av_name.mUsername = DUMMY_NAME; +			av_name.mDisplayName = DUMMY_NAME; +			av_name.mIsDisplayNameDefault = false; +			av_name.mIsDummy = true; +			av_name.mExpires = expires; + +			it = unresolved_agents.beginArray(); +			for ( ; it != unresolved_agents.endArray(); ++it) +			{ +				const LLUUID& agent_id = *it; +				// cache it and fire signals +				LLAvatarNameCache::processName(agent_id, av_name, true); +			} +		} +	} + +	/*virtual*/ void error(U32 status, const std::string& reason) +	{ +		// We're going to construct a dummy record and cache it for a while, +		// either briefly for a 503 Service Unavailable, or longer for other +		// errors. +		F64 retry_timestamp = errorRetryTimestamp(status); + +		// *NOTE: "??" starts trigraphs in C/C++, escape the question marks. +		const std::string DUMMY_NAME("\?\?\?"); +		LLAvatarName av_name; +		av_name.mUsername = DUMMY_NAME; +		av_name.mDisplayName = DUMMY_NAME; +		av_name.mIsDisplayNameDefault = false; +		av_name.mIsDummy = true; +		av_name.mExpires = retry_timestamp; + +		// Add dummy records for all agent IDs in this request +		std::vector<LLUUID>::const_iterator it = mAgentIDs.begin(); +		for ( ; it != mAgentIDs.end(); ++it) +		{ +			const LLUUID& agent_id = *it; +			// cache it and fire signals +			LLAvatarNameCache::processName(agent_id, av_name, true); +		} +	} + +	// Return time to retry a request that generated an error, based on +	// error type and headers.  Return value is seconds-since-epoch. +	F64 errorRetryTimestamp(S32 status) +	{ +		F64 now = LLFrameTimer::getTotalSeconds(); + +		// Retry-After takes priority +		LLSD retry_after = mHeaders["retry-after"]; +		if (retry_after.isDefined()) +		{ +			// We only support the delta-seconds type +			S32 delta_seconds = retry_after.asInteger(); +			if (delta_seconds > 0) +			{ +				// ...valid delta-seconds +				return now + F64(delta_seconds); +			} +		} + +		// If no Retry-After, look for Cache-Control max-age +		F64 expires = 0.0; +		if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires)) +		{ +			return expires; +		} + +		// No information in header, make a guess +		if (status == 503) +		{ +			// ...service unavailable, retry soon +			const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min +			return now + SERVICE_UNAVAILABLE_DELAY; +		} +		else +		{ +			// ...other unexpected error +			const F64 DEFAULT_DELAY = 3600.0; // 1 hour +			return now + DEFAULT_DELAY; +		} +	} +}; + +void LLAvatarNameCache::processName(const LLUUID& agent_id, +									const LLAvatarName& av_name, +									bool add_to_cache) +{ +	if (add_to_cache) +	{ +		sCache[agent_id] = av_name; +	} + +	sPendingQueue.erase(agent_id); + +	// signal everyone waiting on this name +	signal_map_t::iterator sig_it =	sSignalMap.find(agent_id); +	if (sig_it != sSignalMap.end()) +	{ +		callback_signal_t* signal = sig_it->second; +		(*signal)(agent_id, av_name); + +		sSignalMap.erase(agent_id); + +		delete signal; +		signal = NULL; +	} +} + +void LLAvatarNameCache::requestNamesViaCapability() +{ +	F64 now = LLFrameTimer::getTotalSeconds(); + +	// URL format is like: +	// http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0 +	// +	// Apache can handle URLs of 4096 chars, but let's be conservative +	const U32 NAME_URL_MAX = 4096; +	const U32 NAME_URL_SEND_THRESHOLD = 3000; +	std::string url; +	url.reserve(NAME_URL_MAX); + +	std::vector<LLUUID> agent_ids; +	agent_ids.reserve(128); +	 +	ask_queue_t::const_iterator it = sAskQueue.begin(); +	for ( ; it != sAskQueue.end(); ++it) +	{ +		const LLUUID& agent_id = *it; + +		if (url.empty()) +		{ +			// ...starting new request +			url += sNameLookupURL; +			url += "?ids="; +		} +		else +		{ +			// ...continuing existing request +			url += "&ids="; +		} +		url += agent_id.asString(); +		agent_ids.push_back(agent_id); + +		// mark request as pending +		sPendingQueue[agent_id] = now; + +		if (url.size() > NAME_URL_SEND_THRESHOLD) +		{ +			//llinfos << "requestNames " << url << llendl; +			LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); +			url.clear(); +			agent_ids.clear(); +		} +	} + +	if (!url.empty()) +	{ +		//llinfos << "requestNames " << url << llendl; +		LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); +		url.clear(); +		agent_ids.clear(); +	} + +	// We've moved all asks to the pending request queue +	sAskQueue.clear(); +} + +void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, +										   const std::string& full_name, +										   bool is_group) +{ +	// Construct a dummy record for this name.  By convention, SLID is blank +	// Never expires, but not written to disk, so lasts until end of session. +	LLAvatarName av_name; +	buildLegacyName(full_name, &av_name); + +	// Don't add to cache, the data already exists in the legacy name system +	// cache and we don't want or need duplicate storage, because keeping the +	// two copies in sync is complex. +	processName(agent_id, av_name, false); +} + +void LLAvatarNameCache::requestNamesViaLegacy() +{ +	F64 now = LLFrameTimer::getTotalSeconds(); +	std::string full_name; +	ask_queue_t::const_iterator it = sAskQueue.begin(); +	for (; it != sAskQueue.end(); ++it) +	{ +		const LLUUID& agent_id = *it; + +		// Mark as pending first, just in case the callback is immediately +		// invoked below.  This should never happen in practice. +		sPendingQueue[agent_id] = now; + +		gCacheName->get(agent_id, false,  // legacy compatibility +			boost::bind(&LLAvatarNameCache::legacyNameCallback, +				_1, _2, _3)); +	} + +	// We've either answered immediately or moved all asks to the +	// pending queue +	sAskQueue.clear(); +} + +void LLAvatarNameCache::initClass(bool running) +{ +	sRunning = running; +} + +void LLAvatarNameCache::cleanupClass() +{ +} + +void LLAvatarNameCache::importFile(std::istream& istr) +{ +	LLSD data; +	S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr); +	if (parse_count < 1) return; + +	// by convention LLSD storage is a map +	// we only store one entry in the map +	LLSD agents = data["agents"]; + +	LLUUID agent_id; +	LLAvatarName av_name; +	LLSD::map_const_iterator it = agents.beginMap(); +	for ( ; it != agents.endMap(); ++it) +	{ +		agent_id.set(it->first); +		av_name.fromLLSD( it->second ); +		sCache[agent_id] = av_name; +	} +	// entries may have expired since we last ran the viewer, just +	// clean them out now +	eraseExpired(); +	llinfos << "loaded " << sCache.size() << llendl; +} + +void LLAvatarNameCache::exportFile(std::ostream& ostr) +{ +	LLSD agents; +	cache_t::const_iterator it = sCache.begin(); +	for ( ; it != sCache.end(); ++it) +	{ +		const LLUUID& agent_id = it->first; +		const LLAvatarName& av_name = it->second; +		if (!av_name.mIsDummy) +		{ +			// key must be a string +			agents[agent_id.asString()] = av_name.asLLSD(); +		} +	} +	LLSD data; +	data["agents"] = agents; +	LLSDSerialize::toPrettyXML(data, ostr); +} + +void LLAvatarNameCache::setNameLookupURL(const std::string& name_lookup_url) +{ +	sNameLookupURL = name_lookup_url; +} + +bool LLAvatarNameCache::hasNameLookupURL() +{ +	return !sNameLookupURL.empty(); +} + +void LLAvatarNameCache::idle() +{ +	// By convention, start running at first idle() call +	sRunning = true; + +	// *TODO: Possibly re-enabled this based on People API load measurements +	// 100 ms is the threshold for "user speed" operations, so we can +	// stall for about that long to batch up requests. +	//const F32 SECS_BETWEEN_REQUESTS = 0.1f; +	//if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS)) +	//{ +	//	return; +	//} + +	// Must be large relative to above +	const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds +	if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) +	{ +		eraseExpired(); +	} + +	if (sAskQueue.empty()) +	{ +		return; +	} + +	if (useDisplayNames()) +	{ +		requestNamesViaCapability(); +	} +	else +	{ +		// ...fall back to legacy name cache system +		requestNamesViaLegacy(); +	} +} + +bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id) +{ +	const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; +	F64 now = LLFrameTimer::getTotalSeconds(); +	F64 expire_time = now - PENDING_TIMEOUT_SECS; + +	pending_queue_t::const_iterator it = sPendingQueue.find(agent_id); +	if (it != sPendingQueue.end()) +	{ +		bool request_expired = (it->second < expire_time); +		return !request_expired; +	} +	return false; +} + +void LLAvatarNameCache::eraseExpired() +{ +	F64 now = LLFrameTimer::getTotalSeconds(); +	cache_t::iterator it = sCache.begin(); +	while (it != sCache.end()) +	{ +		cache_t::iterator cur = it; +		++it; +		const LLAvatarName& av_name = cur->second; +		if (av_name.mExpires < now) +		{ +			sCache.erase(cur); +		} +	} +} + +void LLAvatarNameCache::buildLegacyName(const std::string& full_name, +										LLAvatarName* av_name) +{ +	llassert(av_name); +	av_name->mUsername = ""; +	av_name->mDisplayName = full_name; +	av_name->mIsDisplayNameDefault = true; +	av_name->mIsDummy = true; +	av_name->mExpires = F64_MAX; +} + +bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) +{ +	if (sRunning) +	{ +		// ...only do immediate lookups when cache is running +		if (useDisplayNames()) +		{ +			// ...use display names cache +			std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id); +			if (it != sCache.end()) +			{ +				*av_name = it->second; +				return true; +			} +		} +		else +		{ +			// ...use legacy names cache +			std::string full_name; +			if (gCacheName->getFullName(agent_id, full_name)) +			{ +				buildLegacyName(full_name, av_name); +				return true; +			} +		} +	} + +	if (!isRequestPending(agent_id)) +	{ +		sAskQueue.insert(agent_id); +	} + +	return false; +} + +void LLAvatarNameCache::fireSignal(const LLUUID& agent_id, +								   const callback_slot_t& slot, +								   const LLAvatarName& av_name) +{ +	callback_signal_t signal; +	signal.connect(slot); +	signal(agent_id, av_name); +} + +void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) +{ +	if (sRunning) +	{ +		// ...only do immediate lookups when cache is running +		if (useDisplayNames()) +		{ +			// ...use new cache +			std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id); +			if (it != sCache.end()) +			{ +				// ...name already exists in cache, fire callback now +				fireSignal(agent_id, slot, it->second); +				return; +			} +		} +		else +		{ +			// ...use old name system +			std::string full_name; +			if (gCacheName->getFullName(agent_id, full_name)) +			{ +				LLAvatarName av_name; +				buildLegacyName(full_name, &av_name); +				fireSignal(agent_id, slot, av_name); +				return; +			} +		} +	} + +	// schedule a request +	if (!isRequestPending(agent_id)) +	{ +		sAskQueue.insert(agent_id); +	} + +	// always store additional callback, even if request is pending +	signal_map_t::iterator sig_it = sSignalMap.find(agent_id); +	if (sig_it == sSignalMap.end()) +	{ +		// ...new callback for this id +		callback_signal_t* signal = new callback_signal_t(); +		signal->connect(slot); +		sSignalMap[agent_id] = signal; +	} +	else +	{ +		// ...existing callback, bind additional slot +		callback_signal_t* signal = sig_it->second; +		signal->connect(slot); +	} +} + + +void LLAvatarNameCache::setUseDisplayNames(bool use) +{ +	if (use != sUseDisplayNames) +	{ +		sUseDisplayNames = use; +		// flush our cache +		sCache.clear(); +	} +} + +bool LLAvatarNameCache::useDisplayNames() +{ +	// Must be both manually set on and able to look up names. +	return sUseDisplayNames && !sNameLookupURL.empty(); +} + +void LLAvatarNameCache::erase(const LLUUID& agent_id) +{ +	sCache.erase(agent_id); +} + +void LLAvatarNameCache::fetch(const LLUUID& agent_id) +{ +	// re-request, even if request is already pending +	sAskQueue.insert(agent_id); +} + +void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name) +{ +	// *TODO: update timestamp if zero? +	sCache[agent_id] = av_name; +} + +F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) +{ +	F64 expires = 0.0; +	if (expirationFromCacheControl(headers, &expires)) +	{ +		return expires; +	} +	else +	{ +		// With no expiration info, default to a day +		const F64 DEFAULT_EXPIRES = 24.0 * 60.0 * 60.0; +		F64 now = LLFrameTimer::getTotalSeconds(); +		return now + DEFAULT_EXPIRES; +	} +} + +bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) +{ +	// Allow the header to override the default +	LLSD cache_control_header = headers["cache-control"]; +	if (cache_control_header.isDefined()) +	{ +		S32 max_age = 0; +		std::string cache_control = cache_control_header.asString(); +		if (max_age_from_cache_control(cache_control, &max_age)) +		{ +			F64 now = LLFrameTimer::getTotalSeconds(); +			*expires = now + (F64)max_age; +			return true; +		} +	} +	return false; +} + +static const std::string MAX_AGE("max-age"); +static const boost::char_separator<char> EQUALS_SEPARATOR("="); +static const boost::char_separator<char> COMMA_SEPARATOR(","); + +bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age) +{ +	// Split the string on "," to get a list of directives +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	tokenizer directives(cache_control, COMMA_SEPARATOR); + +	tokenizer::iterator token_it = directives.begin(); +	for ( ; token_it != directives.end(); ++token_it) +	{ +		// Tokens may have leading or trailing whitespace +		std::string token = *token_it; +		LLStringUtil::trim(token); + +		if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) +		{ +			// ...this token starts with max-age, so let's chop it up by "=" +			tokenizer subtokens(token, EQUALS_SEPARATOR); +			tokenizer::iterator subtoken_it = subtokens.begin(); + +			// Must have a token +			if (subtoken_it == subtokens.end()) return false; +			std::string subtoken = *subtoken_it; + +			// Must exactly equal "max-age" +			LLStringUtil::trim(subtoken); +			if (subtoken != MAX_AGE) return false; + +			// Must have another token +			++subtoken_it; +			if (subtoken_it == subtokens.end()) return false; +			subtoken = *subtoken_it; + +			// Must be a valid integer +			// *NOTE: atoi() returns 0 for invalid values, so we have to +			// check the string first. +			// *TODO: Do servers ever send "0000" for zero?  We don't handle it +			LLStringUtil::trim(subtoken); +			if (subtoken == "0") +			{ +				*max_age = 0; +				return true; +			} +			S32 val = atoi( subtoken.c_str() ); +			if (val > 0 && val < S32_MAX) +			{ +				*max_age = val; +				return true; +			} +			return false; +		} +	} +	return false; +} + + diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h new file mode 100644 index 0000000000..0a8b987b05 --- /dev/null +++ b/indra/llmessage/llavatarnamecache.h @@ -0,0 +1,103 @@ +/**  + * @file llavatarnamecache.h + * @brief Provides lookup of avatar SLIDs ("bobsmith123") and display names + * ("James Cook") from avatar UUIDs. + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, 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 LLAVATARNAMECACHE_H +#define LLAVATARNAMECACHE_H + +#include "llavatarname.h"	// for convenience + +#include <boost/signals2.hpp> + +class LLSD; +class LLUUID; + +namespace LLAvatarNameCache +{ +	// Until the cache is set running, immediate lookups will fail and +	// async lookups will be queued.  This allows us to block requests +	// until we know if the first region supports display names. +	void initClass(bool running); +	void cleanupClass(); + +	void importFile(std::istream& istr); +	void exportFile(std::ostream& ostr); + +	// On the viewer, usually a simulator capabilitity +	// If empty, name cache will fall back to using legacy name +	// lookup system +	void setNameLookupURL(const std::string& name_lookup_url); + +	// Do we have a valid lookup URL, hence are we trying to use the +	// new display name lookup system? +	bool hasNameLookupURL(); +	 +	// Periodically makes a batch request for display names not already in +	// cache.  Call once per frame. +	void idle(); + +	// If name is in cache, returns true and fills in provided LLAvatarName +	// otherwise returns false +	bool get(const LLUUID& agent_id, LLAvatarName *av_name); + +	// Callback types for get() below +	typedef boost::signals2::signal< +		void (const LLUUID& agent_id, const LLAvatarName& av_name)> +			callback_signal_t; +	typedef callback_signal_t::slot_type callback_slot_t; + +	// Fetches name information and calls callback. +	// If name information is in cache, callback will be called immediately. +	void get(const LLUUID& agent_id, callback_slot_t slot); + +	// Allow display names to be explicitly disabled for testing. +	void setUseDisplayNames(bool use); +	bool useDisplayNames(); + +	void erase(const LLUUID& agent_id); + +	// Force a re-fetch of the most recent data, but keep the current +	// data in cache +	void fetch(const LLUUID& agent_id); + +	void insert(const LLUUID& agent_id, const LLAvatarName& av_name); + +	// Compute name expiration time from HTTP Cache-Control header, +	// or return default value, in seconds from epoch. +	F64 nameExpirationFromHeaders(LLSD headers); +} + +// Parse a cache-control header to get the max-age delta-seconds. +// Returns true if header has max-age param and it parses correctly. +// Exported here to ease unit testing. +bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age); + +#endif diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 9871c922f1..ef60fd5c4e 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -75,6 +75,8 @@ public:  public:  	bool mIsGroup;  	U32 mCreateTime;	// unix time_t +	// IDEVO TODO collapse names to one field, which will eliminate +	// many string compares on "Resident"  	std::string mFirstName;  	std::string mLastName;  	std::string mGroupName; @@ -220,7 +222,9 @@ public:  	Impl(LLMessageSystem* msg);  	~Impl(); -	 + +	BOOL getName(const LLUUID& id, std::string& first, std::string& last); +  	boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);  	void addPending(const LLUUID& id, const LLHost& host); @@ -306,89 +310,10 @@ boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback&  	return impl.mSignal.connect(callback);  } -void LLCacheName::importFile(LLFILE* fp) -{ -	S32 count = 0; - -	const S32 BUFFER_SIZE = 1024; -	char buffer[BUFFER_SIZE];	/*Flawfinder: ignore*/ - -	// *NOTE: These buffer sizes are hardcoded into sscanf() below -	char id_string[MAX_STRING]; /*Flawfinder: ignore*/ -	char firstname[MAX_STRING]; /*Flawfinder: ignore*/ -	char lastname[MAX_STRING]; /*Flawfinder: ignore*/ -	U32 create_time; - -	// This is OK if the first line is actually a name.  We just don't load it. -	char* valid = fgets(buffer, BUFFER_SIZE, fp); -	if (!valid) return; - -	// *NOTE: This buffer size is hardcoded into sscanf() below -	char version_string[BUFFER_SIZE]; /*Flawfinder: ignore*/ -	S32 version = 0; -	S32 match = sscanf(	/* Flawfinder: ignore */ -		buffer, -		"%1023s %d", -		version_string, &version); -	if (   match != 2 -		|| strcmp(version_string, "version") -		|| version != CN_FILE_VERSION) -	{ -		llwarns << "Ignoring old cache name file format" << llendl; -		return; -	} - -	// We'll expire entries more than a week old -	U32 now = (U32)time(NULL); -	const U32 SECS_PER_DAY = 60 * 60 * 24; -	U32 delete_before_time = now - (7 * SECS_PER_DAY); - -	while(!feof(fp)) -	{ -		valid = fgets(buffer, BUFFER_SIZE, fp); -		if (!valid) break; - -		match = sscanf(	/* Flawfinder: ignore */ -			buffer, -			"%254s %u %254s %254s", -			id_string,  -			&create_time, -			firstname,  -			lastname); -		if (4 != match) continue; - -		LLUUID id(id_string); -		if (id.isNull()) continue; - -		// undo trivial XOR -		S32 i; -		for (i = 0; i < UUID_BYTES; i++) -		{ -			id.mData[i] ^= 0x33; -		} - -		// Don't load entries that are more than a week old -		if (create_time < delete_before_time) continue; - -		LLCacheNameEntry* entry = new LLCacheNameEntry(); -		entry->mIsGroup = false; -		entry->mCreateTime = create_time; -		entry->mFirstName = firstname; -		entry->mLastName = lastname; -		impl.mCache[id] = entry; -		std::string fullname = entry->mFirstName + " " + entry->mLastName; -		impl.mReverseCache[fullname] = id; -		 -		count++; -	} - -	llinfos << "LLCacheName loaded " << count << " names" << llendl; -} -  bool LLCacheName::importFile(std::istream& istr)  {  	LLSD data; -	if(LLSDSerialize::fromXML(data, istr) < 1) +	if(LLSDSerialize::fromXMLDocument(data, istr) < 1)  		return false;  	// We'll expire entries more than a week old @@ -414,7 +339,7 @@ bool LLCacheName::importFile(std::istream& istr)  		entry->mFirstName = agent[FIRST].asString();  		entry->mLastName = agent[LAST].asString();  		impl.mCache[id] = entry; -		std::string fullname = entry->mFirstName + " " + entry->mLastName; +		std::string fullname = buildFullName(entry->mFirstName, entry->mLastName);  		impl.mReverseCache[fullname] = id;  		++count; @@ -463,6 +388,7 @@ void LLCacheName::exportFile(std::ostream& ostr)  		// store it  		LLUUID id = iter->first;  		std::string id_str = id.asString(); +		// IDEVO TODO: Should we store SLIDs with last name "Resident" or not?  		if(!entry->mFirstName.empty() && !entry->mLastName.empty())  		{  			data[AGENTS][id_str][FIRST] = entry->mFirstName; @@ -480,7 +406,7 @@ void LLCacheName::exportFile(std::ostream& ostr)  } -BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last) +BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last)  {  	if(id.isNull())  	{ @@ -489,7 +415,7 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las  		return TRUE;  	} -	LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); +	LLCacheNameEntry* entry = get_ptr_in_map(mCache, id );  	if (entry)  	{  		first = entry->mFirstName; @@ -500,16 +426,17 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las  	{  		first = sCacheName["waiting"];  		last.clear(); -		if (!impl.isRequestPending(id)) +		if (!isRequestPending(id))  		{ -			impl.mAskNameQueue.insert(id); +			mAskNameQueue.insert(id);  		}	  		return FALSE;  	}  } +  // static -void LLCacheName::LocalizeCacheName(std::string key, std::string value) +void LLCacheName::localizeCacheName(std::string key, std::string value)  {  	if (key!="" && value!= "" )  		sCacheName[key]=value; @@ -520,11 +447,13 @@ void LLCacheName::LocalizeCacheName(std::string key, std::string value)  BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname)  {  	std::string first_name, last_name; -	BOOL res = getName(id, first_name, last_name); -	fullname = first_name + " " + last_name; +	BOOL res = impl.getName(id, first_name, last_name); +	fullname = buildFullName(first_name, last_name);  	return res;  } + +  BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)  {  	if(id.isNull()) @@ -561,13 +490,13 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)  BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id)  { -	std::string fullname = first + " " + last; -	return getUUID(fullname, id); +	std::string full_name = buildFullName(first, last); +	return getUUID(full_name, id);  } -BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id) +BOOL LLCacheName::getUUID(const std::string& full_name, LLUUID& id)  { -	ReverseCache::iterator iter = impl.mReverseCache.find(fullname); +	ReverseCache::iterator iter = impl.mReverseCache.find(full_name);  	if (iter != impl.mReverseCache.end())  	{  		id = iter->second; @@ -579,6 +508,55 @@ BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)  	}  } +//static +std::string LLCacheName::buildFullName(const std::string& first, const std::string& last) +{ +	std::string fullname = first; +	if (!last.empty() +		&& last != "Resident") +	{ +		fullname += ' '; +		fullname += last; +	} +	return fullname; +} + +//static +std::string LLCacheName::cleanFullName(const std::string& full_name) +{ +	return full_name.substr(0, full_name.find(" Resident")); +} + +//static  +std::string LLCacheName::buildUsername(const std::string& full_name) +{ +	// rare, but handle hard-coded error names returned from server +	if (full_name == "(\?\?\?) (\?\?\?)") +	{ +		return "(\?\?\?)"; +	} +	 +	std::string::size_type index = full_name.find(' '); + +	if (index != std::string::npos) +	{ +		std::string username; +		username = full_name.substr(0, index); +		std::string lastname = full_name.substr(index+1); + +		if (lastname != "Resident") +		{ +			username = username + "." + lastname; +		} +		 +		LLStringUtil::toLower(username); +		return username; +	} + +	// if the input wasn't a correctly formatted legacy name just return it unchanged +	return full_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 @@ -586,7 +564,7 @@ BOOL LLCacheName::getUUID(const std::string& fullname, LLUUID& id)  //  we call it immediately. -Steve  // NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the  //  potential need for any parsing should any code need to handle first and last name independently. -boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback) +boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)  {  	boost::signals2::connection res; @@ -594,7 +572,7 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co  	{  		LLCacheNameSignal signal;  		signal.connect(callback); -		signal(id, sCacheName["nobody"], "", is_group); +		signal(id, sCacheName["nobody"], is_group);  		return res;  	} @@ -606,11 +584,13 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co  		// id found in map therefore we can call the callback immediately.  		if (entry->mIsGroup)  		{ -			signal(id, entry->mGroupName, "", entry->mIsGroup); +			signal(id, entry->mGroupName, entry->mIsGroup);  		}  		else  		{ -			signal(id, entry->mFirstName, entry->mLastName, entry->mIsGroup); +			std::string fullname = +				buildFullName(entry->mFirstName, entry->mLastName); +			signal(id, fullname, entry->mIsGroup);  		}  	}  	else @@ -632,9 +612,15 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, co  	return res;  } -boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data) +boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id, +												  const LLCacheNameCallback& callback) +{ +	return get(group_id, true, callback); +} + +boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data)  { -	return get(id, is_group, boost::bind(callback, _1, _2, _3, _4, user_data)); +	return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data));  }  void LLCacheName::processPending() @@ -706,7 +692,7 @@ void LLCacheName::dump()  		{  			llinfos  				<< iter->first << " = " -				<< entry->mFirstName << " " << entry->mLastName +				<< buildFullName(entry->mFirstName, entry->mLastName)  				<< " @ " << entry->mCreateTime  				<< llendl;  		} @@ -725,12 +711,24 @@ void LLCacheName::dumpStats()  			<< llendl;  } +void LLCacheName::clear() +{ +	for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer()); +	impl.mCache.clear(); +} +  //static   std::string LLCacheName::getDefaultName()  {  	return sCacheName["waiting"];  } +//static  +std::string LLCacheName::getDefaultLastName() +{ +	return "Resident"; +} +  void LLCacheName::Impl::processPendingAsks()  {  	LLMemType mt_ppa(LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS); @@ -752,11 +750,13 @@ void LLCacheName::Impl::processPendingReplies()  		if (!entry->mIsGroup)  		{ -			(reply->mSignal)(reply->mID, entry->mFirstName, entry->mLastName, FALSE); +			std::string fullname = +				LLCacheName::buildFullName(entry->mFirstName, entry->mLastName); +			(reply->mSignal)(reply->mID, fullname, false);  		}  		else  		{ -			(reply->mSignal)(reply->mID, entry->mGroupName, "", TRUE); +			(reply->mSignal)(reply->mID, entry->mGroupName, true);  		}  	} @@ -927,13 +927,27 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)  		if (!isGroup)  		{ -			mSignal(id, entry->mFirstName, entry->mLastName, FALSE); -			std::string fullname = entry->mFirstName + " " + entry->mLastName; -			mReverseCache[fullname] = id; +			// NOTE: Very occasionally the server sends down a full name +			// in the first name field with an empty last name, for example, +			// first = "Ladanie1 Resident", last = "". +			// I cannot reproduce this, nor can I find a bug in the server code. +			// Ensure "Resident" does not appear via cleanFullName, because +			// buildFullName only checks last name. JC +			std::string full_name; +			if (entry->mLastName.empty()) +			{ +				full_name = cleanFullName(entry->mFirstName); +			} +			else +			{ +				full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName); +			} +			mSignal(id, full_name, false); +			mReverseCache[full_name] = id;  		}  		else  		{ -			mSignal(id, entry->mGroupName, "", TRUE); +			mSignal(id, entry->mGroupName, true);  			mReverseCache[entry->mGroupName] = id;  		}  	} @@ -962,4 +976,3 @@ void LLCacheName::Impl::handleUUIDGroupNameReply(LLMessageSystem* msg, void** us  {  	((LLCacheName::Impl*)userData)->processUUIDReply(msg, true);  } - diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index 111cc8b650..697bb27556 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -42,13 +42,12 @@ class LLUUID;  typedef boost::signals2::signal<void (const LLUUID& id, -                                      const std::string& first_name, -                                      const std::string& last_name, -                                      BOOL is_group)> LLCacheNameSignal; +                                      const std::string& name, +                                      bool is_group)> LLCacheNameSignal;  typedef LLCacheNameSignal::slot_type LLCacheNameCallback;  // Old callback with user data for compatability -typedef void (*old_callback_t)(const LLUUID&, const std::string&, const std::string&, BOOL, void*); +typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);  // Here's the theory:  // If you request a name that isn't in the cache, it returns "waiting" @@ -71,24 +70,31 @@ public:  	boost::signals2::connection addObserver(const LLCacheNameCallback& callback); -	// janky old format. Remove after a while. Phoenix. 2008-01-30 -	void importFile(LLFILE* fp); -  	// storing cache on disk; for viewer, in name.cache  	bool importFile(std::istream& istr);  	void exportFile(std::ostream& ostr); -	// If available, copies the first and last name into the strings provided. -	// first must be at least DB_FIRST_NAME_BUF_SIZE characters. -	// last must be at least DB_LAST_NAME_BUF_SIZE characters. +	// If available, copies name ("bobsmith123" or "James Linden") into string  	// If not available, copies the string "waiting".  	// Returns TRUE iff available. -	BOOL getName(const LLUUID& id, std::string& first, std::string& last); -	BOOL getFullName(const LLUUID& id, std::string& fullname); -	 +	BOOL getFullName(const LLUUID& id, std::string& full_name); +  	// Reverse lookup of UUID from name  	BOOL getUUID(const std::string& first, const std::string& last, LLUUID& id);  	BOOL getUUID(const std::string& fullname, LLUUID& id); + +	// IDEVO Temporary code +	// Clean up new-style "bobsmith123 Resident" names to "bobsmith123" for display +	static std::string buildFullName(const std::string& first, const std::string& last); + +	// Clean up legacy "bobsmith123 Resident" to "bobsmith123" +	// If name does not contain "Resident" returns it unchanged. +	static std::string cleanFullName(const std::string& full_name); +	 +	// Converts a standard legacy name to a username +	// "bobsmith123 Resident" -> "bobsmith" +	// "Random Linden" -> "random.linden" +	static std::string buildUsername(const std::string& name);  	// If available, this method copies the group name into the string  	// provided. The caller must allocate at least @@ -100,10 +106,15 @@ public:  	// If the data is currently available, may call the callback immediatly  	// otherwise, will request the data, and will call the callback when  	// available.  There is no garuntee the callback will ever be called. -	boost::signals2::connection get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback); -	 +	boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback); + +	// Convenience method for looking up a group name, so you can +	// tell the difference between avatar lookup and group lookup +	// in global searches +	boost::signals2::connection getGroup(const LLUUID& group_id, const LLCacheNameCallback& callback); +  	// LEGACY -	boost::signals2::connection get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data); +	boost::signals2::connection get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data);  	// This method needs to be called from time to time to send out  	// requests.  	void processPending(); @@ -114,9 +125,15 @@ public:  	// Debugging  	void dump();		// Dumps the contents of the cache  	void dumpStats();	// Dumps the sizes of the cache and associated queues. +	void clear();		// Deletes all entries from the cache  	static std::string getDefaultName(); -	static void LocalizeCacheName(std::string key, std::string value); + +	// Returns "Resident", the default last name for SLID-based accounts +	// that have no last name. +	static std::string getDefaultLastName(); + +	static void localizeCacheName(std::string key, std::string value);  	static std::map<std::string, std::string> sCacheName;  private: diff --git a/indra/llmessage/mean_collision_data.h b/indra/llmessage/mean_collision_data.h index 03b96f9f90..a6c635e81e 100644 --- a/indra/llmessage/mean_collision_data.h +++ b/indra/llmessage/mean_collision_data.h @@ -61,7 +61,7 @@ public:  	LLMeanCollisionData(LLMeanCollisionData *mcd)  		: mVictim(mcd->mVictim), mPerp(mcd->mPerp), mTime(mcd->mTime), mType(mcd->mType), mMag(mcd->mMag), -		  mFirstName(mcd->mFirstName), mLastName(mcd->mLastName) +		  mFullName(mcd->mFullName)  	{  	}		 @@ -95,8 +95,7 @@ public:  	time_t mTime;  	EMeanCollisionType mType;  	F32	   mMag; -	std::string mFirstName; -	std::string mLastName; +	std::string mFullName;  }; diff --git a/indra/llmessage/tests/llavatarnamecache_test.cpp b/indra/llmessage/tests/llavatarnamecache_test.cpp new file mode 100644 index 0000000000..eeadb703d1 --- /dev/null +++ b/indra/llmessage/tests/llavatarnamecache_test.cpp @@ -0,0 +1,109 @@ +/** + * @file llhost_test.cpp + * @author Adroit + * @date 2007-02 + * @brief llhost test cases. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + *  + * Copyright (c) 2007-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +  +#include "linden_common.h" + +#include "../llavatarnamecache.h" + +#include "../test/lltut.h" + +namespace tut +{ +	struct avatarnamecache_data +	{ +	}; +	typedef test_group<avatarnamecache_data> avatarnamecache_test; +	typedef avatarnamecache_test::object avatarnamecache_object; +	tut::avatarnamecache_test avatarnamecache_testcase("llavatarnamecache"); + +	template<> template<> +	void avatarnamecache_object::test<1>() +	{ +		bool valid = false; +		S32 max_age = 0; + +		valid = max_age_from_cache_control("max-age=3600", &max_age); +		ensure("typical input valid", valid); +		ensure_equals("typical input parsed", max_age, 3600); + +		valid = max_age_from_cache_control( +			" max-age=600 , no-cache,private=\"stuff\" ", &max_age); +		ensure("complex input valid", valid); +		ensure_equals("complex input parsed", max_age, 600); + +		valid = max_age_from_cache_control( +			"no-cache, max-age = 123 ", &max_age); +		ensure("complex input 2 valid", valid); +		ensure_equals("complex input 2 parsed", max_age, 123); +	} + +	template<> template<> +	void avatarnamecache_object::test<2>() +	{ +		bool valid = false; +		S32 max_age = -1; + +		valid = max_age_from_cache_control("", &max_age); +		ensure("empty input returns invalid", !valid); +		ensure_equals("empty input doesn't change val", max_age, -1); + +		valid = max_age_from_cache_control("no-cache", &max_age); +		ensure("no max-age field returns invalid", !valid); + +		valid = max_age_from_cache_control("max", &max_age); +		ensure("just 'max' returns invalid", !valid); + +		valid = max_age_from_cache_control("max-age", &max_age); +		ensure("partial max-age is invalid", !valid); + +		valid = max_age_from_cache_control("max-age=", &max_age); +		ensure("longer partial max-age is invalid", !valid); + +		valid = max_age_from_cache_control("max-age=FOO", &max_age); +		ensure("invalid integer max-age is invalid", !valid); + +		valid = max_age_from_cache_control("max-age 234", &max_age); +		ensure("space separated max-age is invalid", !valid); + +		valid = max_age_from_cache_control("max-age=0", &max_age); +		ensure("zero max-age is valid", valid); + +		// *TODO: Handle "0000" as zero +		//valid = max_age_from_cache_control("max-age=0000", &max_age); +		//ensure("multi-zero max-age is valid", valid); + +		valid = max_age_from_cache_control("max-age=-123", &max_age); +		ensure("less than zero max-age is invalid", !valid); +	} +} diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index cc107c972d..f49069f065 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -58,8 +58,6 @@  #include "lltooltip.h"  // Globals -S32 LLCOMBOBOX_HEIGHT = 0; -S32 LLCOMBOBOX_WIDTH = 0;  S32 MAX_COMBO_WIDTH = 500;  static LLDefaultChildRegistry::Register<LLComboBox> register_combo_box("combo_box"); @@ -711,10 +709,10 @@ void LLComboBox::onItemSelected(const LLSD& data)  		setLabel(getSelectedItemLabel());  		if (mAllowTextEntry) -		{ -			gFocusMgr.setKeyboardFocus(mTextEntry); -			mTextEntry->selectAll(); -		} +	{ +		gFocusMgr.setKeyboardFocus(mTextEntry); +		mTextEntry->selectAll(); +	}  	}  	// hiding the list reasserts the old value stored in the text editor/dropdown button  	hideList(); diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index f0bd432f3a..7f93cd1477 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -49,9 +49,6 @@  class LLFontGL;  class LLViewBorder; -extern S32 LLCOMBOBOX_HEIGHT; -extern S32 LLCOMBOBOX_WIDTH; -  class LLComboBox  :	public LLUICtrl, public LLCtrlListInterface  { @@ -230,8 +227,8 @@ private:  	commit_callback_t	mPrearrangeCallback;  	commit_callback_t	mTextEntryCallback;  	commit_callback_t	mSelectionCallback; -        boost::signals2::connection mTopLostSignalConnection; -    S32					mLastSelectedIndex; +	boost::signals2::connection mTopLostSignalConnection; +	S32                 mLastSelectedIndex;  };  // A combo box with icons for the list of items. diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 7fa3c2cf65..421ddd98cc 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -34,7 +34,9 @@  #include "llnotifications.h" +#include "llavatarnamecache.h"  #include "llinstantmessage.h" +#include "llcachename.h"  #include "llxmlnode.h"  #include "lluictrl.h"  #include "lluictrlfactory.h" @@ -1487,17 +1489,50 @@ std::ostream& operator<<(std::ostream& s, const LLNotification& notification)  	return s;  } -void LLPostponedNotification::onCachedNameReceived(const LLUUID& id, const std::string& first, -		const std::string& last, bool is_group) +//static +void LLPostponedNotification::lookupName(LLPostponedNotification* thiz, +										 const LLUUID& id, +										 bool is_group) +{ +	if (is_group) +	{ +		gCacheName->getGroup(id, +			boost::bind(&LLPostponedNotification::onGroupNameCache, +				thiz, _1, _2, _3)); +	} +	else +	{ +		LLAvatarNameCache::get(id, +			boost::bind(&LLPostponedNotification::onAvatarNameCache, +				thiz, _1, _2)); +	} +} + +void LLPostponedNotification::onGroupNameCache(const LLUUID& id, +											   const std::string& full_name, +											   bool is_group) +{ +	finalizeName(full_name); +} + +void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id, +												const LLAvatarName& av_name)  { -	mName = first + " " + last; +	std::string name = av_name.getCompleteName(); -	LLStringUtil::trim(mName); -	if (mName.empty()) +	// from PE merge - we should figure out if this is the right thing to do +	if (name.empty())  	{ -		llwarns << "Empty name received for Id: " << id << llendl; -		mName = SYSTEM_FROM; +		llwarns << "Empty name received for Id: " << agent_id << llendl; +		name = SYSTEM_FROM;  	} +	 +	finalizeName(name); +} + +void LLPostponedNotification::finalizeName(const std::string& name) +{ +	mName = name;  	modifyNotificationParams();  	LLNotifications::instance().add(mParams);  	cleanup(); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 1cdd744a68..9ff309351c 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -104,8 +104,8 @@  #include "llinitparam.h"  #include "llnotificationslistener.h"  #include "llnotificationptr.h" -#include "llcachename.h" +class LLAvatarName;  typedef enum e_notification_priority  { @@ -1000,17 +1000,20 @@ public:  	{  		// upcast T to the base type to restrict T derivation from LLPostponedNotification  		LLPostponedNotification* thiz = new T(); -  		thiz->mParams = params; -		gCacheName->get(id, is_group, boost::bind( -				&LLPostponedNotification::onCachedNameReceived, thiz, _1, _2, -				_3, _4)); +		// Avoid header file dependency on llcachename.h +		lookupName(thiz, id, is_group);  	}  private: -	void onCachedNameReceived(const LLUUID& id, const std::string& first, -			const std::string& last, bool is_group); +	static void lookupName(LLPostponedNotification* thiz, const LLUUID& id, bool is_group); +	// only used for groups +	void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group); +	// only used for avatars +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); +	// used for both group and avatar names +	void finalizeName(const std::string& name);  	void cleanup()  	{ diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp index b8f93b6a0e..5965ca6fb5 100644 --- a/indra/llui/llstyle.cpp +++ b/indra/llui/llstyle.cpp @@ -44,7 +44,8 @@ LLStyle::Params::Params()  	color("color", LLColor4::black),  	font("font", LLFontGL::getFontMonospace()),  	image("image"), -	link_href("href") +	link_href("href"), +	is_link("is_link")  {} @@ -57,6 +58,7 @@ LLStyle::LLStyle(const LLStyle::Params& p)  	mReadOnlyColor(p.readonly_color()),  	mFont(p.font()),  	mLink(p.link_href), +	mIsLink(p.is_link.isProvided() ? p.is_link : !p.link_href().empty()),  	mDropShadow(p.drop_shadow),  	mImagep(p.image())  {} @@ -79,7 +81,7 @@ void LLStyle::setLinkHREF(const std::string& href)  BOOL LLStyle::isLink() const  { -	return mLink.size(); +	return mIsLink;  }  BOOL LLStyle::isVisible() const diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h index 2067e8e8be..0ca1f2027e 100644 --- a/indra/llui/llstyle.h +++ b/indra/llui/llstyle.h @@ -51,6 +51,7 @@ public:  		Optional<const LLFontGL*>		font;  		Optional<LLUIImage*>			image;  		Optional<std::string>			link_href; +		Optional<bool>					is_link;  		Params();  	};  	LLStyle(const Params& p = Params()); @@ -113,6 +114,7 @@ private:  	std::string	mFontName;  	const LLFontGL*   mFont;		// cached for performance  	std::string	mLink; +	bool		mIsLink;  	LLUIImagePtr mImagep;  }; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index d3b2a368a5..f8e97f2b39 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -976,9 +976,9 @@ void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)  	if (width != getRect().getWidth() || height != getRect().getHeight())  	{  		bool scrolled_to_bottom = mScroller ? mScroller->isAtBottom() : false; - +		  		LLUICtrl::reshape( width, height, called_from_parent ); - +	  		if (mScroller && scrolled_to_bottom && mTrackEnd)  		{  			// keep bottom of text buffer visible @@ -987,7 +987,7 @@ void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)  			// not be scrolled to the bottom, since the scroll index  			// specified the _top_ of the visible document region  			mScroller->goToBottom(); -		} +		}		  		// do this first after reshape, because other things depend on  		// up-to-date mVisibleTextRect @@ -1298,28 +1298,28 @@ void LLTextBase::reflow()  		}  	} -	// apply scroll constraints after reflowing text -	if (!hasMouseCapture() && mScroller) -	{ -		if (scrolled_to_bottom && mTrackEnd) +		// apply scroll constraints after reflowing text +		if (!hasMouseCapture() && mScroller)  		{ -			// keep bottom of text buffer visible -			endOfDoc(); -		} -		else if (hasSelection() && follow_selection) -		{ -			// keep cursor in same vertical position on screen when selecting text -			LLRect new_cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); +			if (scrolled_to_bottom && mTrackEnd) +			{ +				// keep bottom of text buffer visible +				endOfDoc(); +			} +			else if (hasSelection() && follow_selection) +			{ +				// keep cursor in same vertical position on screen when selecting text +				LLRect new_cursor_rect_doc = getDocRectFromDocIndex(mCursorPos);  			LLRect old_cursor_rect = cursor_rect;  			old_cursor_rect.mTop = mVisibleTextRect.mTop - cursor_rect.mTop;  			old_cursor_rect.mBottom = mVisibleTextRect.mTop - cursor_rect.mBottom; -			mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect); -		} -		else -		{ -			// keep first line of text visible -			LLRect new_first_char_rect = getDocRectFromDocIndex(mScrollIndex); +				mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect); +			} +			else +			{ +				// keep first line of text visible +				LLRect new_first_char_rect = getDocRectFromDocIndex(mScrollIndex);  			// pass in desired rect in the coordinate frame of the document viewport  			LLRect old_first_char_rect = first_char_rect; @@ -1327,12 +1327,12 @@ void LLTextBase::reflow()  			old_first_char_rect.mBottom = mVisibleTextRect.mTop - first_char_rect.mBottom;  			mScroller->scrollToShowRect(new_first_char_rect, old_first_char_rect); +			}  		} -	} -	// reset desired x cursor position -	updateCursorXPos(); -} +		// reset desired x cursor position +		updateCursorXPos(); +	}  LLRect LLTextBase::getTextBoundingRect()  { @@ -1603,6 +1603,20 @@ std::string LLTextBase::getText() const  	return getViewModel()->getValue().asString();  } +// IDEVO - icons can be UI image names or UUID sent from +// server with avatar display name +static LLUIImagePtr image_from_icon_name(const std::string& icon_name) +{ +	if (LLUUID::validate(icon_name)) +	{ +		return LLUI::getUIImageByID( LLUUID(icon_name) ); +	} +	else +	{ +		return LLUI::getUIImage(icon_name); +	} +} +  void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)  {  	LLStyle::Params style_params(input_params); @@ -1615,7 +1629,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  		LLUrlMatch match;  		std::string text = new_text;  		while ( LLUrlRegistry::instance().findUrl(text, match, -		        boost::bind(&LLTextBase::replaceUrlLabel, this, _1, _2)) ) +		        boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) )  		{  			LLTextUtil::processUrlMatch(&match,this); @@ -1623,11 +1637,8 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  			start = match.getStart();  			end = match.getEnd()+1; -			LLStyle::Params link_params = style_params; -			link_params.color = match.getColor(); -			link_params.readonly_color =  match.getColor(); -			link_params.font.style("UNDERLINE"); -			link_params.link_href = match.getUrl(); +			LLStyle::Params link_params(style_params); +			link_params.overwriteFrom(match.getStyle());  			// output the text before the Url  			if (start > 0) @@ -1644,26 +1655,21 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  				std::string subtext=text.substr(0,start);  				appendAndHighlightText(subtext, part, style_params);   			} -			// output the styled Url (unless we've been asked to suppress hyperlinking) -			if (match.isLinkDisabled()) + +			// output the styled Url +			appendAndHighlightTextImpl(match.getLabel(), part, link_params); +			 +			// set the tooltip for the Url label +			if (! match.getTooltip().empty())  			{ -				appendAndHighlightText(match.getLabel(), part, style_params); +				segment_set_t::iterator it = getSegIterContaining(getLength()-1); +				if (it != mSegments.end()) +					{ +						LLTextSegmentPtr segment = *it; +						segment->setToolTip(match.getTooltip()); +					}  			} -			else -			{ -				appendAndHighlightText(match.getLabel(), part, link_params); -				// 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()); -						} -				} -			}  			// move on to the rest of the text after the Url  			if (end < (S32)text.length())   			{ @@ -1761,7 +1767,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig  			highlight_params.color = lcolor;  			LLWString wide_text; -			wide_text = utf8str_to_wstring(pieces[i]["text"].asString()); +				wide_text = utf8str_to_wstring(pieces[i]["text"].asString());  			S32 cur_length = getLength();  			LLStyleConstSP sp(new LLStyle(highlight_params)); @@ -1774,7 +1780,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig  	else  	{  		LLWString wide_text; -		wide_text = utf8str_to_wstring(new_text); +			wide_text = utf8str_to_wstring(new_text);  		segment_vec_t segments;  		S32 segment_start = old_length; @@ -1828,8 +1834,9 @@ void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlig  } -void LLTextBase::replaceUrlLabel(const std::string &url, -								   const std::string &label) +void LLTextBase::replaceUrl(const std::string &url, +							const std::string &label, +							const std::string &icon)  {  	// get the full (wide) text for the editor so we can change it  	LLWString text = getWText(); @@ -1850,7 +1857,7 @@ void LLTextBase::replaceUrlLabel(const std::string &url,  		seg->setEnd(seg_start + seg_length);  		// if we find a link with our Url, then replace the label -		if (style->isLink() && style->getLinkHREF() == url) +		if (style->getLinkHREF() == url)  		{  			S32 start = seg->getStart();  			S32 end = seg->getEnd(); @@ -1859,6 +1866,21 @@ void LLTextBase::replaceUrlLabel(const std::string &url,  			modified = true;  		} +		// Icon might be updated when more avatar or group info +		// becomes available +		if (style->isImage() && style->getLinkHREF() == url) +		{ +			LLUIImagePtr image = image_from_icon_name( icon ); +			if (image) +			{ +				LLStyle::Params icon_params; +				icon_params.image = image; +				LLStyleConstSP new_style(new LLStyle(icon_params)); +				seg->setStyle(new_style); +				modified = true; +			} +		} +  		// work out the character offset for the next segment  		seg_start = seg->getEnd();  	} @@ -1956,8 +1978,8 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round,  		else if (hit_past_end_of_line && segmentp->getEnd() > line_iter->mDocIndexEnd - 1)	  		{  			// segment wraps to next line, so just set doc pos to the end of the line - 			// segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd) - 			pos = llmin(getLength(), line_iter->mDocIndexEnd); +			// segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd) +			pos = llmin(getLength(), line_iter->mDocIndexEnd);  			break;  		}  		start_x += text_width; @@ -2613,8 +2635,8 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt  		height = mFontHeight;  		const LLWString &text = mEditor.getWText();  		// if last character is a newline, then return true, forcing line break -		width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); -	} +			width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars); +		}  	return false;  } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 4b0eeeb7d6..63451a2ae0 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -481,7 +481,11 @@ protected:  	// misc  	void							updateRects();  	void							needsScroll() { mScrollNeeded = TRUE; } -	void							replaceUrlLabel(const std::string &url, const std::string &label); + +	struct URLLabelCallback; +	// Replace a URL with a new icon and label, for example, when +	// avatar names are looked up. +	void replaceUrl(const std::string &url, const std::string &label, const std::string& icon);  	void							appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params = LLStyle::Params());  	void							appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e075699a6e..c408f8d8b5 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -37,18 +37,19 @@  #include "llurlmatch.h"  #include "llurlregistry.h" +#include "llavatarnamecache.h"  #include "llcachename.h"  #include "lltrans.h"  #include "lluicolortable.h"  #define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" +// Utility functions +std::string localize_slapp_label(const std::string& url, const std::string& full_name); -LLUrlEntryBase::LLUrlEntryBase() : -	mColor(LLUIColorTable::instance().getColor("HTMLLinkColor")), -	mDisabledLink(false) -{ -} + +LLUrlEntryBase::LLUrlEntryBase() +{}  LLUrlEntryBase::~LLUrlEntryBase()  { @@ -59,6 +60,22 @@ std::string LLUrlEntryBase::getUrl(const std::string &string) const  	return escapeUrl(string);  } +//virtual +std::string LLUrlEntryBase::getIcon(const std::string &url) +{ +	return mIcon; +} + +LLStyle::Params LLUrlEntryBase::getStyle() const +{ +	LLStyle::Params style_params; +	style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); +	style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); +	style_params.font.style = "UNDERLINE"; +	return style_params; +} + +  std::string LLUrlEntryBase::getIDStringFromUrl(const std::string &url) const  {  	// return the id from a SLURL in the format /app/{cmd}/{id}/about @@ -136,16 +153,20 @@ void LLUrlEntryBase::addObserver(const std::string &id,  		mObservers.insert(std::pair<std::string, LLUrlEntryObserver>(id, observer));  	}  } -  -void LLUrlEntryBase::callObservers(const std::string &id, const std::string &label) + +// *NOTE: See also LLUrlEntryAgent::callObservers() +void LLUrlEntryBase::callObservers(const std::string &id, +								   const std::string &label, +								   const std::string &icon)  {  	// notify all callbacks waiting on the given uuid -	std::multimap<std::string, LLUrlEntryObserver>::iterator it; -	for (it = mObservers.find(id); it != mObservers.end();) +	typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it; +	std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id); +	for (observer_it it = matching_range.first; it != matching_range.second;)  	{  		// call the callback - give it the new label  		LLUrlEntryObserver &observer = it->second; -		(*observer.signal)(it->second.url, label); +		(*observer.signal)(it->second.url, label, icon);  		// then remove the signal - we only need to call it once  		delete observer.signal;  		mObservers.erase(it++); @@ -314,16 +335,35 @@ LLUrlEntryAgent::LLUrlEntryAgent()  							boost::regex::perl|boost::regex::icase);  	mMenuName = "menu_url_agent.xml";  	mIcon = "Generic_Person"; -	mColor = LLUIColorTable::instance().getColor("AgentLinkColor");  } -void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id, -										  const std::string& first, -										  const std::string& last, -										  BOOL is_group) +// virtual +void LLUrlEntryAgent::callObservers(const std::string &id, +								    const std::string &label, +								    const std::string &icon)  { +	// notify all callbacks waiting on the given uuid +	typedef std::multimap<std::string, LLUrlEntryObserver>::iterator observer_it; +	std::pair<observer_it, observer_it> matching_range = mObservers.equal_range(id); +	for (observer_it it = matching_range.first; it != matching_range.second;) +	{ +		// call the callback - give it the new label +		LLUrlEntryObserver &observer = it->second; +		std::string final_label = localize_slapp_label(observer.url, label); +		(*observer.signal)(observer.url, final_label, icon); +		// then remove the signal - we only need to call it once +		delete observer.signal; +		mObservers.erase(it++); +	} +} + +void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id, +										const LLAvatarName& av_name) +{ +	std::string label = av_name.getCompleteName(); +  	// received the agent name from the server - tell our observers -	callObservers(id.asString(), first + " " + last); +	callObservers(id.asString(), label, mIcon);  }  LLUUID	LLUrlEntryAgent::getID(const std::string &string) const @@ -336,6 +376,10 @@ std::string LLUrlEntryAgent::getTooltip(const std::string &string) const  	// return a tooltip corresponding to the URL type instead of the generic one  	std::string url = getUrl(string); +	if (LLStringUtil::endsWith(url, "/inspect")) +	{ +		return LLTrans::getString("TooltipAgentInspect"); +	}  	if (LLStringUtil::endsWith(url, "/mute"))  	{  		return LLTrans::getString("TooltipAgentMute"); @@ -379,50 +423,182 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa  	}  	LLUUID agent_id(agent_id_string); -	std::string full_name;  	if (agent_id.isNull())  	{  		return LLTrans::getString("AvatarNameNobody");  	} -	else if (gCacheName->getFullName(agent_id, full_name)) -	{ -		// customize label string based on agent SLapp suffix -		if (LLStringUtil::endsWith(url, "/mute")) -		{ -			return LLTrans::getString("SLappAgentMute") + " " + full_name; -		} -		if (LLStringUtil::endsWith(url, "/unmute")) -		{ -			return LLTrans::getString("SLappAgentUnmute") + " " + full_name; -		} -		if (LLStringUtil::endsWith(url, "/im")) -		{ -			return LLTrans::getString("SLappAgentIM") + " " + full_name; -		} -		if (LLStringUtil::endsWith(url, "/pay")) -		{ -			return LLTrans::getString("SLappAgentPay") + " " + full_name; -		} -		if (LLStringUtil::endsWith(url, "/offerteleport")) -		{ -			return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name; -		} -		if (LLStringUtil::endsWith(url, "/requestfriend")) -		{ -			return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name; -		} -		return full_name; + +	LLAvatarName av_name; +	if (LLAvatarNameCache::get(agent_id, &av_name)) +	{ +		std::string label = av_name.getCompleteName(); + +		// handle suffixes like /mute or /offerteleport +		label = localize_slapp_label(url, label); +		return label;  	}  	else  	{ -		gCacheName->get(agent_id, FALSE, -			boost::bind(&LLUrlEntryAgent::onAgentNameReceived, -				this, _1, _2, _3, _4)); +		LLAvatarNameCache::get(agent_id, +			boost::bind(&LLUrlEntryAgent::onAvatarNameCache, +				this, _1, _2));  		addObserver(agent_id_string, url, cb);  		return LLTrans::getString("LoadingData");  	}  } +LLStyle::Params LLUrlEntryAgent::getStyle() const +{ +	LLStyle::Params style_params = LLUrlEntryBase::getStyle(); +	style_params.color = LLUIColorTable::instance().getColor("AgentLinkColor"); +	style_params.readonly_color = LLUIColorTable::instance().getColor("AgentLinkColor"); +	return style_params; +} + +std::string localize_slapp_label(const std::string& url, const std::string& full_name) +{ +	// customize label string based on agent SLapp suffix +	if (LLStringUtil::endsWith(url, "/mute")) +	{ +		return LLTrans::getString("SLappAgentMute") + " " + full_name; +	} +	if (LLStringUtil::endsWith(url, "/unmute")) +	{ +		return LLTrans::getString("SLappAgentUnmute") + " " + full_name; +	} +	if (LLStringUtil::endsWith(url, "/im")) +	{ +		return LLTrans::getString("SLappAgentIM") + " " + full_name; +	} +	if (LLStringUtil::endsWith(url, "/pay")) +	{ +		return LLTrans::getString("SLappAgentPay") + " " + full_name; +	} +	if (LLStringUtil::endsWith(url, "/offerteleport")) +	{ +		return LLTrans::getString("SLappAgentOfferTeleport") + " " + full_name; +	} +	if (LLStringUtil::endsWith(url, "/requestfriend")) +	{ +		return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name; +	} +	return full_name; +} + + +std::string LLUrlEntryAgent::getIcon(const std::string &url) +{ +	// *NOTE: Could look up a badge here by calling getIDStringFromUrl() +	// and looking up the badge for the agent. +	return mIcon; +} + +// +// LLUrlEntryAgentName describes a Second Life agent name Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) +// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) +// +LLUrlEntryAgentName::LLUrlEntryAgentName() +{} + +void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id, +										const LLAvatarName& av_name) +{ +	std::string label = getName(av_name); +	// received the agent name from the server - tell our observers +	callObservers(id.asString(), label, mIcon); +} + +std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ +	if (!gCacheName) +	{ +		// probably at the login screen, use short string for layout +		return LLTrans::getString("LoadingData"); +	} + +	std::string agent_id_string = getIDStringFromUrl(url); +	if (agent_id_string.empty()) +	{ +		// something went wrong, just give raw url +		return unescapeUrl(url); +	} + +	LLUUID agent_id(agent_id_string); +	if (agent_id.isNull()) +	{ +		return LLTrans::getString("AvatarNameNobody"); +	} + +	LLAvatarName av_name; +	if (LLAvatarNameCache::get(agent_id, &av_name)) +	{ +		return getName(av_name); +	} +	else +	{ +		LLAvatarNameCache::get(agent_id, +			boost::bind(&LLUrlEntryAgentCompleteName::onAvatarNameCache, +				this, _1, _2)); +		addObserver(agent_id_string, url, cb); +		return LLTrans::getString("LoadingData"); +	} +} + +LLStyle::Params LLUrlEntryAgentName::getStyle() const +{ +	// don't override default colors +	return LLStyle::Params().is_link(false); +} + +// +// LLUrlEntryAgentCompleteName describes a Second Life agent complete name Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename +// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename +// +LLUrlEntryAgentCompleteName::LLUrlEntryAgentCompleteName() +{ +	mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/completename", +							boost::regex::perl|boost::regex::icase); +} + +std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name) +{ +	return avatar_name.getCompleteName(); +} + +// +// LLUrlEntryAgentDisplayName describes a Second Life agent display name Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname +// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname +// +LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName() +{ +	mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/displayname", +							boost::regex::perl|boost::regex::icase); +} + +std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name) +{ +	return avatar_name.mDisplayName; +} + +// +// LLUrlEntryAgentUserName describes a Second Life agent user name Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username +// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username +// +LLUrlEntryAgentUserName::LLUrlEntryAgentUserName() +{ +	mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/username", +							boost::regex::perl|boost::regex::icase); +} + +std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name) +{ +	return avatar_name.mUsername.empty() ? avatar_name.getLegacyName() : avatar_name.mUsername; +} +  //  // LLUrlEntryGroup Describes a Second Life group Url, e.g.,  // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about @@ -436,18 +612,16 @@ LLUrlEntryGroup::LLUrlEntryGroup()  	mMenuName = "menu_url_group.xml";  	mIcon = "Generic_Group";  	mTooltip = LLTrans::getString("TooltipGroupUrl"); -	mColor = LLUIColorTable::instance().getColor("GroupLinkColor");  }  void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id, -										  const std::string& first, -										  const std::string& last, -										  BOOL is_group) +										  const std::string& name, +										  bool is_group)  {  	// received the group name from the server - tell our observers -	callObservers(id.asString(), first); +	callObservers(id.asString(), name, mIcon);  }  LLUUID	LLUrlEntryGroup::getID(const std::string &string) const @@ -483,14 +657,23 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa  	}  	else  	{ -		gCacheName->get(group_id, TRUE, +		gCacheName->getGroup(group_id,  			boost::bind(&LLUrlEntryGroup::onGroupNameReceived, -				this, _1, _2, _3, _4)); +				this, _1, _2, _3));  		addObserver(group_id_string, url, cb);  		return LLTrans::getString("LoadingData");  	}  } +LLStyle::Params LLUrlEntryGroup::getStyle() const +{ +	LLStyle::Params style_params = LLUrlEntryBase::getStyle(); +	style_params.color = LLUIColorTable::instance().getColor("GroupLinkColor"); +	style_params.readonly_color = LLUIColorTable::instance().getColor("GroupLinkColor"); +	return style_params; +} + +  //  // LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,  // secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select @@ -778,7 +961,6 @@ LLUrlEntryNoLink::LLUrlEntryNoLink()  {  	mPattern = boost::regex("<nolink>[^<]*</nolink>",  							boost::regex::perl|boost::regex::icase); -	mDisabledLink = true;  }  std::string LLUrlEntryNoLink::getUrl(const std::string &url) const @@ -792,6 +974,12 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC  	return getUrl(url);  } +LLStyle::Params LLUrlEntryNoLink::getStyle() const  +{  +	return LLStyle::Params();  +} + +  //  // LLUrlEntryIcon describes an icon with <icon>...</icon> tags  // @@ -799,7 +987,6 @@ LLUrlEntryIcon::LLUrlEntryIcon()  {  	mPattern = boost::regex("<icon\\s*>\\s*([^<]*)?\\s*</icon\\s*>",  							boost::regex::perl|boost::regex::icase); -	mDisabledLink = true;  }  std::string LLUrlEntryIcon::getUrl(const std::string &url) const diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 7d718b67a9..f60ef0d968 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -36,13 +36,17 @@  #include "lluuid.h"  #include "lluicolor.h" +#include "llstyle.h"  #include <boost/signals2.hpp>  #include <boost/regex.hpp>  #include <string>  #include <map> +class LLAvatarName; +  typedef boost::signals2::signal<void (const std::string& url, -									  const std::string& label)> LLUrlLabelSignal; +									  const std::string& label, +									  const std::string& icon)> LLUrlLabelSignal;  typedef LLUrlLabelSignal::slot_type LLUrlLabelCallback;  /// @@ -77,10 +81,10 @@ public:  	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 -	virtual std::string getIcon(const std::string &url) { return mIcon; } +	virtual std::string getIcon(const std::string &url); -	/// Return the color to render the displayed text -	LLUIColor getColor() const { return mColor; } +	/// Return the style to render the displayed text +	virtual LLStyle::Params getStyle() const;  	/// Given a matched Url, return a tooltip string for the hyperlink  	virtual std::string getTooltip(const std::string &string) const { return mTooltip; } @@ -91,9 +95,6 @@ public:  	/// Return the name of a SL location described by this Url, if any  	virtual std::string getLocation(const std::string &url) const { return ""; } -	/// is this a match for a URL that should not be hyperlinked? -	bool isLinkDisabled() const { return mDisabledLink; } -  	virtual LLUUID	getID(const std::string &string) const { return LLUUID::null; }  protected: @@ -103,7 +104,7 @@ protected:  	std::string getLabelFromWikiLink(const std::string &url) const;  	std::string getUrlFromWikiLink(const std::string &string) const;  	void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb);  -	void callObservers(const std::string &id, const std::string &label); +	virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon);  	typedef struct {  		std::string url; @@ -114,9 +115,7 @@ protected:  	std::string                                    	mIcon;  	std::string                                    	mMenuName;  	std::string                                    	mTooltip; -	LLUIColor										mColor;  	std::multimap<std::string, LLUrlEntryObserver>	mObservers; -	bool                                            mDisabledLink;  };  /// @@ -165,17 +164,77 @@ public:  ///  /// 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); +	/*virtual*/ std::string getIcon(const std::string &url);  	/*virtual*/ std::string getTooltip(const std::string &string) const; +	/*virtual*/ LLStyle::Params getStyle() const;  	/*virtual*/ LLUUID	getID(const std::string &string) const; +protected: +	/*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon); +private: +	void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); +}; + +/// +/// LLUrlEntryAgentName Describes a Second Life agent name Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) +/// that displays various forms of user name +/// This is a base class for the various implementations of name display +class LLUrlEntryAgentName : public LLUrlEntryBase +{ +public: +	LLUrlEntryAgentName(); +	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +	/*virtual*/ LLStyle::Params getStyle() const; +protected: +	// override this to pull out relevant name fields +	virtual std::string getName(const LLAvatarName& avatar_name) = 0; +private: +	void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); +}; + + +/// +/// LLUrlEntryAgentCompleteName Describes a Second Life agent name Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename +/// that displays the full display name + user name for an avatar +/// such as "James Linden (james.linden)" +class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName +{ +public: +	LLUrlEntryAgentCompleteName(); +private: +	/*virtual*/ std::string getName(const LLAvatarName& avatar_name); +}; + +/// +/// LLUrlEntryAgentDisplayName Describes a Second Life agent display name Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname +/// that displays the just the display name for an avatar +/// such as "James Linden" +class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName +{ +public: +	LLUrlEntryAgentDisplayName(); +private: +	/*virtual*/ std::string getName(const LLAvatarName& avatar_name); +}; + +/// +/// LLUrlEntryAgentUserName Describes a Second Life agent username Url, e.g., +/// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username +/// that displays the just the display name for an avatar +/// such as "james.linden" +class LLUrlEntryAgentUserName : public LLUrlEntryAgentName +{ +public: +	LLUrlEntryAgentUserName();  private: -	void onAgentNameReceived(const LLUUID& id, const std::string& first, -							 const std::string& last, BOOL is_group); +	/*virtual*/ std::string getName(const LLAvatarName& avatar_name);  };  /// @@ -187,10 +246,10 @@ class LLUrlEntryGroup : public LLUrlEntryBase  public:  	LLUrlEntryGroup();  	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +	/*virtual*/ LLStyle::Params getStyle() const;  	/*virtual*/ LLUUID	getID(const std::string &string) const;  private: -	void onGroupNameReceived(const LLUUID& id, const std::string& first, -							 const std::string& last, BOOL is_group); +	void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group);  };  /// @@ -298,6 +357,7 @@ public:  	LLUrlEntryNoLink();  	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);  	/*virtual*/ std::string getUrl(const std::string &string) const; +	/*virtual*/ LLStyle::Params getStyle() const;  };  /// diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp index 7c96665ce4..55ef07da36 100644 --- a/indra/llui/llurlmatch.cpp +++ b/indra/llui/llurlmatch.cpp @@ -42,16 +42,15 @@ LLUrlMatch::LLUrlMatch() :  	mTooltip(""),  	mIcon(""),  	mMenuName(""), -	mLocation(""), -	mDisabledLink(false) +	mLocation("")  {  }  void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,  						   const std::string &label, const std::string &tooltip, -						   const std::string &icon, const LLUIColor& color, +						   const std::string &icon, const LLStyle::Params& style,  						   const std::string &menu, const std::string &location, -						   bool disabled_link, const LLUUID& id) +						   const LLUUID& id)  {  	mStart = start;  	mEnd = end; @@ -59,9 +58,9 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,  	mLabel = label;  	mTooltip = tooltip;  	mIcon = icon; -	mColor = color; +	mStyle = style; +	mStyle.link_href = url;  	mMenuName = menu;  	mLocation = location; -	mDisabledLink = disabled_link;  	mID = id;  } diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h index 78dd2c528f..1ffac6ea0f 100644 --- a/indra/llui/llurlmatch.h +++ b/indra/llui/llurlmatch.h @@ -34,11 +34,11 @@  #ifndef LL_LLURLMATCH_H  #define LL_LLURLMATCH_H -#include "linden_common.h" +//#include "linden_common.h"  #include <string>  #include <vector> -#include "lluicolor.h" +#include "llstyle.h"  ///  /// LLUrlMatch describes a single Url that was matched within a string by  @@ -75,7 +75,7 @@ public:  	std::string getIcon() const { return mIcon; }  	/// Return the color to render the displayed text -	LLUIColor getColor() const { return mColor; } +	LLStyle::Params getStyle() const { return mStyle; }  	/// Return the name of a XUI file containing the context menu items  	std::string getMenuName() const { return mMenuName; } @@ -83,18 +83,13 @@ public:  	/// return the SL location that this Url describes, or "" if none.  	std::string getLocation() const { return mLocation; } -	/// is this a match for a URL that should not be hyperlinked? -	bool isLinkDisabled() const { return mDisabledLink; } -  	/// 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 LLUIColor& color, const std::string &menu,  -				   const std::string &location, bool disabled_link -				   , const LLUUID& id ); - -	const LLUUID& getID() const { return mID;} +				   const LLStyle::Params& style, const std::string &menu,  +				   const std::string &location, const LLUUID& id); +	const LLUUID& getID() const { return mID; }  private:  	U32         mStart;  	U32         mEnd; @@ -104,10 +99,8 @@ private:  	std::string mIcon;  	std::string mMenuName;  	std::string mLocation; -  	LLUUID		mID; -	LLUIColor	mColor; -	bool        mDisabledLink; +	LLStyle::Params mStyle;  };  #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 1f86f72faa..5de249d994 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -37,18 +37,25 @@  #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) +void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, const std::string& icon)  {  }  LLUrlRegistry::LLUrlRegistry()  { +	mUrlEntry.reserve(20); +  	// Urls are matched in the order that they were registered  	registerUrl(new LLUrlEntryNoLink());  	registerUrl(new LLUrlEntryIcon());  	registerUrl(new LLUrlEntrySLURL());  	registerUrl(new LLUrlEntryHTTP());  	registerUrl(new LLUrlEntryHTTPLabel()); +	registerUrl(new LLUrlEntryAgentCompleteName()); +	registerUrl(new LLUrlEntryAgentDisplayName()); +	registerUrl(new LLUrlEntryAgentUserName()); +	// LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since  +	// LLUrlEntryAgent is a less specific (catchall for agent urls)  	registerUrl(new LLUrlEntryAgent());  	registerUrl(new LLUrlEntryGroup());  	registerUrl(new LLUrlEntryParcel()); @@ -77,10 +84,13 @@ LLUrlRegistry::~LLUrlRegistry()  	}  } -void LLUrlRegistry::registerUrl(LLUrlEntryBase *url) +void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front)  {  	if (url)  	{ +		if (force_front)  // IDEVO +			mUrlEntry.insert(mUrlEntry.begin(), url); +		else  		mUrlEntry.push_back(url);  	}  } @@ -180,10 +190,9 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL  						match_entry->getLabel(url, cb),  						match_entry->getTooltip(url),  						match_entry->getIcon(url), -						match_entry->getColor(), +						match_entry->getStyle(),  						match_entry->getMenuName(),  						match_entry->getLocation(url), -						match_entry->isLinkDisabled(),  						match_entry->getID(url));  		return true;  	} @@ -215,10 +224,9 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr  						match.getLabel(),  						match.getTooltip(),  						match.getIcon(), -						match.getColor(), +						match.getStyle(),  						match.getMenuName(),  						match.getLocation(), -						match.isLinkDisabled(),  						match.getID());  		return true;  	} diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index 399ee0a988..dffbd9d4bf 100644 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -43,7 +43,9 @@  #include <vector>  /// This default callback for findUrl() simply ignores any label updates -void LLUrlRegistryNullCallback(const std::string &url, const std::string &label); +void LLUrlRegistryNullCallback(const std::string &url, +							   const std::string &label, +							   const std::string &icon);  ///  /// LLUrlRegistry is a singleton that contains a set of Url types that @@ -70,7 +72,9 @@ public:  	~LLUrlRegistry();  	/// add a new Url handler to the registry (will be freed on destruction) -	void registerUrl(LLUrlEntryBase *url); +	/// optionally force it to the front of the list, making it take +	/// priority over other regular expression matches for URLs +	void registerUrl(LLUrlEntryBase *url, bool force_front = false);  	/// 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 diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index 26d1f2e067..bc0f5dc9c2 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -22,11 +22,28 @@  #include "llstring.h"  #include "llfile.h" +#include "llavatarnamecache.h"  #include "llcachename.h"  #include "lluuid.h"  #include <string> +// Stub for LLAvatarNameCache +bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) +{ +	return false; +} + +void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) +{ +	return; +} + +bool LLAvatarNameCache::useDisplayNames() +{ +	return false; +} +  //  // Stub implementation for LLCacheName  // @@ -42,7 +59,12 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)  	return TRUE;  } -boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback) +boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback) +{ +	return boost::signals2::connection(); +} + +boost::signals2::connection LLCacheName::getGroup(const LLUUID& id, const LLCacheNameCallback& callback)  {  	return boost::signals2::connection();  } @@ -62,3 +84,106 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::  {  	return std::string();  } + +// +// Stub implementation for LLStyle::Params::Params +// + +LLStyle::Params::Params() +{ +} + +// +// Stub implementations for various LLInitParam classes +// + +namespace LLInitParam +{ +	BaseBlock::BaseBlock() {} +	BaseBlock::~BaseBlock() {} +	Param::Param(BaseBlock* enclosing_block) +	:	mIsProvided(false) +	{ +		const U8* my_addr = reinterpret_cast<const U8*>(this); +		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); +		mEnclosingBlockOffset = (U16)(my_addr - block_addr); +	} +	void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) {} + +	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name){} +	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} +	 +	void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) +	{ +		mBlockDescriptor = &descriptor; +		descriptor.mCurrentBlockPtr = this; +	} +	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack){ return true; } +	bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const { return true; } +	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const { return true; } +	bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } +	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } + +	TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count) +	:	super_t(descriptor, name, value, func, min_count, max_count) +	{} + +	void TypedParam<LLUIColor>::setValueFromBlock() const +	{} +	 +	void TypedParam<LLUIColor>::setBlockFromValue() +	{} + +	void TypeValues<LLUIColor>::declareValues() +	{} + +	bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) +	{ +		return false; +	} + +	TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count) +	:	super_t(descriptor, _name, value, func, min_count, max_count) +	{} + +	void TypedParam<const LLFontGL*>::setValueFromBlock() const +	{} +	 +	void TypedParam<const LLFontGL*>::setBlockFromValue() +	{} + +	void TypeValues<LLFontGL::HAlign>::declareValues() +	{} + +	void TypeValues<LLFontGL::VAlign>::declareValues() +	{} + +	void TypeValues<LLFontGL::ShadowType>::declareValues() +	{} + +	void TypedParam<LLUIImage*>::setValueFromBlock() const +	{} +	 +	void TypedParam<LLUIImage*>::setBlockFromValue() +	{} + +	 +	bool ParamCompare<LLUIImage*, false>::equals( +		LLUIImage* const &a, +		LLUIImage* const &b) +	{ +		return false; +	} + +	bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) +	{ +		return false; +	} + +} + +//static +LLFontGL* LLFontGL::getFontDefault() +{ +	return NULL;  +} diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 4463b6cc6f..009d82ed99 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -25,6 +25,7 @@  #include "llurlentry_stub.cpp"  #include "lltut.h"  #include "../lluicolortable.h" +#include "../lluiimage.h"  #include <boost/regex.hpp> @@ -35,6 +36,26 @@ LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& defa  LLUIColor::LLUIColor() : mColorPtr(NULL) {} +LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) +{ +} + +LLUIImage::~LLUIImage() +{ +} + +//virtual +S32 LLUIImage::getWidth() const +{ +	return 0; +} + +//virtual +S32 LLUIImage::getHeight() const +{ +	return 0; +} +  namespace tut  {  	struct LLUrlEntryData diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp index 06b850d233..93fd11d999 100644 --- a/indra/llui/tests/llurlmatch_test.cpp +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -20,14 +20,136 @@   * $/LicenseInfo$   */ +#include "linden_common.h" +  #include "../llurlmatch.h" +#include "../lluiimage.h"  #include "lltut.h" -// link seam +// link seams +  LLUIColor::LLUIColor()  	: mColorPtr(NULL)  {} +LLStyle::Params::Params() +{ +} + +LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) +{ +} + +LLUIImage::~LLUIImage() +{ +} + +//virtual +S32 LLUIImage::getWidth() const +{ +	return 0; +} + +//virtual +S32 LLUIImage::getHeight() const +{ +	return 0; +} + +namespace LLInitParam +{ +	BaseBlock::BaseBlock() {} +	BaseBlock::~BaseBlock() {} + +	void BaseBlock::setLastChangedParam(const Param& last_param, bool user_provided) {} + +	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptor& in_param, const char* char_name){} +	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} +	 +	void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) +	{ +		mBlockDescriptor = &descriptor; +		descriptor.mCurrentBlockPtr = this; +	} + +	Param::Param(BaseBlock* enclosing_block) +	:	mIsProvided(false) +	{ +		const U8* my_addr = reinterpret_cast<const U8*>(this); +		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); +		mEnclosingBlockOffset = (U16)(my_addr - block_addr); +	} + +	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack){ return true; } +	bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t name_stack, const LLInitParam::BaseBlock* diff_block) const { return true; } +	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack) const { return true; } +	bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } +	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } + +	TypedParam<LLUIColor >::TypedParam(BlockDescriptor& descriptor, const char* name, const LLUIColor& value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count) +	:	super_t(descriptor, name, value, func, min_count, max_count) +	{} + +	void TypedParam<LLUIColor>::setValueFromBlock() const +	{} +	 +	void TypedParam<LLUIColor>::setBlockFromValue() +	{} + +	void TypeValues<LLUIColor>::declareValues() +	{} + +	bool ParamCompare<const LLFontGL*, false>::equals(const LLFontGL* a, const LLFontGL* b) +	{ +		return false; +	} + +	TypedParam<const LLFontGL*>::TypedParam(BlockDescriptor& descriptor, const char* _name, const LLFontGL*const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count) +	:	super_t(descriptor, _name, value, func, min_count, max_count) +	{} + +	void TypedParam<const LLFontGL*>::setValueFromBlock() const +	{} +	 +	void TypedParam<const LLFontGL*>::setBlockFromValue() +	{} + +	void TypeValues<LLFontGL::HAlign>::declareValues() +	{} + +	void TypeValues<LLFontGL::VAlign>::declareValues() +	{} + +	void TypeValues<LLFontGL::ShadowType>::declareValues() +	{} + +	void TypedParam<LLUIImage*>::setValueFromBlock() const +	{} +	 +	void TypedParam<LLUIImage*>::setBlockFromValue() +	{} +	 +	bool ParamCompare<LLUIImage*, false>::equals( +		LLUIImage* const &a, +		LLUIImage* const &b) +	{ +		return false; +	} + +	bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) +	{ +		return false; +	} + +} + +//static +LLFontGL* LLFontGL::getFontDefault() +{ +	return NULL;  +} + +  namespace tut  {  	struct LLUrlMatchData @@ -54,7 +176,7 @@ namespace tut  		LLUrlMatch match;  		ensure("empty()", match.empty()); -		match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure("! empty()", ! match.empty());  	} @@ -67,7 +189,7 @@ namespace tut  		LLUrlMatch match;  		ensure_equals("getStart() == 0", match.getStart(), 0); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getStart() == 10", match.getStart(), 10);  	} @@ -80,7 +202,7 @@ namespace tut  		LLUrlMatch match;  		ensure_equals("getEnd() == 0", match.getEnd(), 0); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getEnd() == 20", match.getEnd(), 20);  	} @@ -93,10 +215,10 @@ namespace tut  		LLUrlMatch match;  		ensure_equals("getUrl() == ''", match.getUrl(), ""); -		match.setValues(10, 20, "http://slurl.com/", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "http://slurl.com/", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/"); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getUrl() == '' (2)", match.getUrl(), "");  	} @@ -109,10 +231,10 @@ namespace tut  		LLUrlMatch match;  		ensure_equals("getLabel() == ''", match.getLabel(), ""); -		match.setValues(10, 20, "", "Label", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "Label", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label"); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getLabel() == '' (2)", match.getLabel(), "");  	} @@ -125,10 +247,10 @@ namespace tut  		LLUrlMatch match;  		ensure_equals("getTooltip() == ''", match.getTooltip(), ""); -		match.setValues(10, 20, "", "", "Info", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "Info", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info"); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getTooltip() == '' (2)", match.getTooltip(), "");  	} @@ -141,10 +263,10 @@ namespace tut  		LLUrlMatch match;  		ensure_equals("getIcon() == ''", match.getIcon(), ""); -		match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon"); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure_equals("getIcon() == '' (2)", match.getIcon(), "");  	} @@ -157,10 +279,10 @@ namespace tut  		LLUrlMatch match;  		ensure("getMenuName() empty", match.getMenuName().empty()); -		match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "", LLUUID::null);  		ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml"); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure("getMenuName() empty (2)", match.getMenuName().empty());  	} @@ -173,10 +295,10 @@ namespace tut  		LLUrlMatch match;  		ensure("getLocation() empty", match.getLocation().empty()); -		match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "Paris", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "Icon", LLStyle::Params(), "xui_file.xml", "Paris", LLUUID::null);  		ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris"); -		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "", false,LLUUID::null); +		match.setValues(10, 20, "", "", "", "", LLStyle::Params(), "", "", LLUUID::null);  		ensure("getLocation() empty (2)", match.getLocation().empty());  	}  } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 65502209f7..b75bff507e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -240,6 +240,7 @@ set(viewer_SOURCE_FILES      llhudeffecttrail.cpp      llhudicon.cpp      llhudmanager.cpp +    llhudnametag.cpp      llhudobject.cpp      llhudrender.cpp      llhudtext.cpp @@ -479,6 +480,7 @@ set(viewer_SOURCE_FILES      llviewercontrol.cpp      llviewercontrollistener.cpp      llviewerdisplay.cpp +    llviewerdisplayname.cpp      llviewerfloaterreg.cpp      llviewerfoldertype.cpp      llviewergenericmessage.cpp @@ -766,6 +768,7 @@ set(viewer_HEADER_FILES      llhudeffecttrail.h      llhudicon.h      llhudmanager.h +    llhudnametag.h      llhudobject.h      llhudrender.h      llhudtext.h @@ -1005,6 +1008,7 @@ set(viewer_HEADER_FILES      llviewercontrol.h      llviewercontrollistener.h      llviewerdisplay.h +    llviewerdisplayname.h      llviewerfloaterreg.h      llviewerfoldertype.h      llviewergenericmessage.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 810b2d9a1d..4fa183ceac 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7822,7 +7822,7 @@        <key>Value</key>        <integer>0</integer>      </map> -    <key>RenderShowGroupTitleAll</key> +    <key>NameTagShowGroupTitles</key>      <map>        <key>Comment</key>        <string>Show group titles in name labels</string> @@ -7831,7 +7831,40 @@        <key>Type</key>        <string>Boolean</string>        <key>Value</key> +      <integer>0</integer> +    </map> +    <key>NameTagShowDisplayNames</key> +    <map> +      <key>Comment</key> +      <string>Show display names in name labels</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>NameTagShowFriends</key> +    <map> +      <key>Comment</key> +      <string>Highlight the name tags of your friends</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>NameTagShowUsernames</key> +    <map> +      <key>Comment</key> +      <string>Show usernames in avatar name tags</string> +      <key>Persist</key>        <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer>      </map>      <key>RenderInitError</key>      <map> @@ -10858,6 +10891,17 @@        <key>Value</key>        <integer>0</integer>      </map> +  <key>UseDisplayNames</key> +  <map> +    <key>Comment</key> +    <string>Use new, changeable, unicode names</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>1</integer> +  </map>      <key>UseEnergy</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 15d9f36b74..b5f9810e24 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -46,29 +46,6 @@  #include "llslurl.h"  //static -void LLAgentUI::buildName(std::string& name) -{ -	name.clear(); -	if (isAgentAvatarValid()) -	{ -		LLNameValue *first_nv = gAgentAvatarp->getNVPair("FirstName"); -		LLNameValue *last_nv = gAgentAvatarp->getNVPair("LastName"); -		if (first_nv && last_nv) -		{ -			name = first_nv->printData() + " " + last_nv->printData(); -		} -		else -		{ -			llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl; -		} -	} -	else -	{ -		name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName"); -	} -} - -//static  void LLAgentUI::buildFullname(std::string& name)  {  	if (isAgentAvatarValid()) diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h index 577b752fbe..2c3c65fb8a 100644 --- a/indra/newview/llagentui.h +++ b/indra/newview/llagentui.h @@ -47,7 +47,6 @@ public:  		LOCATION_FORMAT_FULL,			// Parcel, Region (x, y, z) - Maturity  	}; -	static void buildName(std::string& name);  	static void buildFullname(std::string &name);  	static void buildSLURL(LLSLURL& slurl, const bool escaped = true); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 58b651ec39..7d55162a05 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -90,6 +90,7 @@  #include "llsecondlifeurls.h"  // Linden library includes +#include "llavatarnamecache.h"  #include "llimagej2c.h"  #include "llmemory.h"  #include "llprimitive.h" @@ -162,7 +163,6 @@  // Included so that constants/settings might be initialized  // in save_settings_to_globals()  #include "llbutton.h" -#include "llcombobox.h"  #include "llstatusbar.h"  #include "llsurface.h"  #include "llvosky.h" @@ -438,9 +438,6 @@ static void settings_to_globals()  	MENU_BAR_HEIGHT		= gSavedSettings.getS32("MenuBarHeight");  	MENU_BAR_WIDTH		= gSavedSettings.getS32("MenuBarWidth"); -	LLCOMBOBOX_HEIGHT	= BTN_HEIGHT - 2; -	LLCOMBOBOX_WIDTH	= 128; -  	LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));  	LLImageGL::sGlobalUseAnisotropic	= gSavedSettings.getBOOL("RenderAnisotropic"); @@ -1357,8 +1354,7 @@ bool LLAppViewer::cleanup()  	LLPolyMesh::freeAllMeshes(); -	delete gCacheName; -	gCacheName = NULL; +	LLStartUp::cleanupNameCache();  	// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. @@ -3424,6 +3420,15 @@ void LLAppViewer::saveFinalSnapshot()  void LLAppViewer::loadNameCache()  { +	// display names cache +	std::string filename = +		gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); +	llifstream name_cache_stream(filename); +	if(name_cache_stream.is_open()) +	{ +		LLAvatarNameCache::importFile(name_cache_stream); +	} +  	if (!gCacheName) return;  	std::string name_cache; @@ -3433,19 +3438,19 @@ void LLAppViewer::loadNameCache()  	{  		if(gCacheName->importFile(cache_file)) return;  	} +} -	// Try to load from the legacy format. This should go away after a -	// while. Phoenix 2008-01-30 -	LLFILE* name_cache_fp = LLFile::fopen(name_cache, "r");		// Flawfinder: ignore -	if (name_cache_fp) +void LLAppViewer::saveNameCache()  	{ -		gCacheName->importFile(name_cache_fp); -		fclose(name_cache_fp); -	} +	// display names cache +	std::string filename = +		gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); +	llofstream name_cache_stream(filename); +	if(name_cache_stream.is_open()) +	{ +		LLAvatarNameCache::exportFile(name_cache_stream);  } -void LLAppViewer::saveNameCache() -{  	if (!gCacheName) return;  	std::string name_cache; @@ -3641,6 +3646,7 @@ void LLAppViewer::idle()  	    // NOTE: Starting at this point, we may still have pointers to "dead" objects  	    // floating throughout the various object lists.  	    // +		idleNameCache();  		idleNetwork(); @@ -3978,6 +3984,60 @@ void LLAppViewer::sendLogoutRequest()  	}  } +void LLAppViewer::idleNameCache() +{ +	// Neither old nor new name cache can function before agent has a region +	LLViewerRegion* region = gAgent.getRegion(); +	if (!region) return; + +	// deal with any queued name requests and replies. +	gCacheName->processPending(); + +	// Can't run the new cache until we have the list of capabilities +	// for the agent region, and can therefore decide whether to use +	// display names or fall back to the old name system. +	if (!region->capabilitiesReceived()) return; + +	// Agent may have moved to a different region, so need to update cap URL +	// for name lookups.  Can't do this in the cap grant code, as caps are +	// granted to neighbor regions before the main agent gets there.  Can't +	// do it in the move-into-region code because cap not guaranteed to be +	// granted yet, for example on teleport. +	bool had_capability = LLAvatarNameCache::hasNameLookupURL(); +	std::string name_lookup_url; +	name_lookup_url.reserve(128); // avoid a memory allocation below +	name_lookup_url = region->getCapability("GetDisplayNames"); +	bool have_capability = !name_lookup_url.empty(); +	if (have_capability) +	{ +		// we have support for display names, use it +	    U32 url_size = name_lookup_url.size(); +	    // capabilities require URLs with slashes before query params: +	    // https://<host>:<port>/cap/<uuid>/?ids=<blah> +	    // but the caps are granted like: +	    // https://<host>:<port>/cap/<uuid> +	    if (url_size > 0 && name_lookup_url[url_size-1] != '/') +	    { +		    name_lookup_url += '/'; +	    } +		LLAvatarNameCache::setNameLookupURL(name_lookup_url); +	} +	else +	{ +		// Display names not available on this region +		LLAvatarNameCache::setNameLookupURL( std::string() ); +	} + +	// Error recovery - did we change state? +	if (had_capability != have_capability) +	{ +		// name tags are persistant on screen, so make sure they refresh +		LLVOAvatar::invalidateNameTags(); +	} + +	LLAvatarNameCache::idle(); +} +  //  // Handle messages, and all message related stuff  // @@ -4003,8 +4063,6 @@ void LLAppViewer::idleNetwork()  	{  		LLFastTimer t(FTM_IDLE_NETWORK); // decode -		// deal with any queued name requests and replies. -		gCacheName->processPending();  		LLTimer check_message_timer;  		//  Read all available packets from network   		const S64 frame_count = gFrameCount;  // U32->S64 diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 0b862a92a1..cac580e896 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -209,6 +209,8 @@ private:      void idle();       void idleShutdown(); +	// update avatar SLID and display name caches +	void idleNameCache();      void idleNetwork();      void sendLogoutRequest(); diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 1e59e5b805..2a1f239065 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -37,11 +37,11 @@  #include "boost/lambda/lambda.hpp"	// for lambda::constant +#include "llavatarnamecache.h"	// IDEVO  #include "llsd.h"  #include "lldarray.h"  #include "llnotifications.h"  #include "llnotificationsutil.h" -  #include "roles_constants.h"    // for GP_MEMBER_INVITE  #include "llagent.h" @@ -70,6 +70,7 @@  #include "llimfloater.h"  #include "lltrans.h"  #include "llcallingcard.h" +#include "llslurl.h"			// IDEVO  // static  void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name) @@ -81,26 +82,22 @@ void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::strin  	}  	LLSD args; -	args["NAME"] = name; +	args["NAME"] = LLSLURL("agent", id, "completename").getSLURLString();  	LLSD payload;  	payload["id"] = id;  	payload["name"] = name; -    // Look for server versions like: Second Life Server 1.24.4.95600 -	if (gLastVersionChannel.find(" 1.24.") != std::string::npos) -	{ -		// Old and busted server version, doesn't support friend -		// requests with messages. -    	LLNotificationsUtil::add("AddFriend", args, payload, &callbackAddFriend); -	} -	else -	{ +          	LLNotificationsUtil::add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage); -	}  	// add friend to recent people list  	LLRecentPeople::instance().add(id);  } +void on_avatar_name_friendship(const LLUUID& id, const LLAvatarName av_name) +{ +	LLAvatarActions::requestFriendshipDialog(id, av_name.getCompleteName()); +} +  // static  void LLAvatarActions::requestFriendshipDialog(const LLUUID& id)  { @@ -109,9 +106,7 @@ void LLAvatarActions::requestFriendshipDialog(const LLUUID& id)  		return;  	} -	std::string full_name; -	gCacheName->getFullName(id, full_name); -	requestFriendshipDialog(id, full_name); +	LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_friendship, _1, _2));  }  // static @@ -136,11 +131,10 @@ void LLAvatarActions::removeFriendsDialog(const uuid_vec_t& ids)  	if(ids.size() == 1)  	{  		LLUUID agent_id = ids[0]; -		std::string first, last; -		if(gCacheName->getName(agent_id, first, last)) +		LLAvatarName av_name; +		if(LLAvatarNameCache::get(agent_id, &av_name))  		{ -			args["FIRST_NAME"] = first; -			args["LAST_NAME"] = last;	 +			args["NAME"] = av_name.mDisplayName;  		}  		msgType = "RemoveFromFriends"; @@ -168,14 +162,6 @@ void LLAvatarActions::offerTeleport(const LLUUID& invitee)  	if (invitee.isNull())  		return; -	//waiting until Name Cache gets updated with corresponding avatar name -	std::string just_to_request_name; -	if (!gCacheName->getFullName(invitee, just_to_request_name)) -	{ -		gCacheName->get(invitee, FALSE, boost::bind((void (*)(const LLUUID&)) &LLAvatarActions::offerTeleport, invitee)); -		return; -	} -  	LLDynamicArray<LLUUID> ids;  	ids.push_back(invitee);  	offerTeleport(ids); @@ -190,20 +176,11 @@ void LLAvatarActions::offerTeleport(const uuid_vec_t& ids)  	handle_lure(ids);  } -// static -void LLAvatarActions::startIM(const LLUUID& id) +static void on_avatar_name_cache_start_im(const LLUUID& agent_id, +										  const LLAvatarName& av_name)  { -	if (id.isNull()) -		return; - -	std::string name; -	if (!gCacheName->getFullName(id, name)) -	{ -		gCacheName->get(id, FALSE, boost::bind(&LLAvatarActions::startIM, id)); -		return; -	} - -	LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, id); +	std::string name = av_name.getCompleteName(); +	LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, agent_id);  	if (session_id != LLUUID::null)  	{  		LLIMFloater::show(session_id); @@ -212,6 +189,16 @@ void LLAvatarActions::startIM(const LLUUID& id)  }  // static +void LLAvatarActions::startIM(const LLUUID& id) +{ +	if (id.isNull()) +		return; + +	LLAvatarNameCache::get(id, +		boost::bind(&on_avatar_name_cache_start_im, _1, _2)); +} + +// static  void LLAvatarActions::endIM(const LLUUID& id)  {  	if (id.isNull()) @@ -224,6 +211,18 @@ void LLAvatarActions::endIM(const LLUUID& id)  	}  } +static void on_avatar_name_cache_start_call(const LLUUID& agent_id, +											const LLAvatarName& av_name) +{ +	std::string name = av_name.getCompleteName(); +	LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, agent_id, true); +	if (session_id != LLUUID::null) +	{ +		gIMMgr->startCall(session_id); +	} +	make_ui_sound("UISndStartIM"); +} +  // static  void LLAvatarActions::startCall(const LLUUID& id)  { @@ -231,15 +230,8 @@ void LLAvatarActions::startCall(const LLUUID& id)  	{  		return;  	} - -	std::string name; -	gCacheName->getFullName(id, name); -	LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, id, true); -	if (session_id != LLUUID::null) -	{ -		gIMMgr->startCall(session_id); -	} -	make_ui_sound("UISndStartIM"); +	LLAvatarNameCache::get(id, +		boost::bind(&on_avatar_name_cache_start_call, _1, _2));  }  // static @@ -335,14 +327,14 @@ void LLAvatarActions::showProfile(const LLUUID& id)  // static  void LLAvatarActions::showOnMap(const LLUUID& id)  { -	std::string name; -	if (!gCacheName->getFullName(id, name)) +	LLAvatarName av_name; +	if (!LLAvatarNameCache::get(id, &av_name))  	{ -		gCacheName->get(id, FALSE, boost::bind(&LLAvatarActions::showOnMap, id)); +		LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::showOnMap, id));  		return;  	} -	gFloaterWorldMap->trackAvatar(id, name); +	gFloaterWorldMap->trackAvatar(id, av_name.mDisplayName);  	LLFloaterReg::showInstance("world_map");  } @@ -492,14 +484,15 @@ namespace action_give_inventory  		return acceptable;  	} -	static void build_residents_string(const std::vector<std::string>& avatar_names, std::string& residents_string) +	static void build_residents_string(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)  	{  		llassert(avatar_names.size() > 0);  		const std::string& separator = LLTrans::getString("words_separator"); -		for (std::vector<std::string>::const_iterator it = avatar_names.begin(); ; ) +		for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )  		{ -			residents_string.append(*it); +			LLAvatarName av_name = *it; +			residents_string.append(av_name.mDisplayName);  			if	(++it == avatar_names.end())  			{  				break; @@ -536,7 +529,7 @@ namespace action_give_inventory  	struct LLShareInfo : public LLSingleton<LLShareInfo>  	{ -		std::vector<std::string> mAvatarNames; +		std::vector<LLAvatarName> mAvatarNames;  		uuid_vec_t mAvatarUuids;  	}; @@ -601,7 +594,7 @@ namespace action_give_inventory  				}  				else  				{ -					LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id); +				LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id);  					shared = true;  				}  			} @@ -633,11 +626,10 @@ namespace action_give_inventory  	 * @param avatar_names - avatar names request to be sent.  	 * @param avatar_uuids - avatar names request to be sent.  	 */ -	static void give_inventory(const std::vector<std::string>& avatar_names, const uuid_vec_t& avatar_uuids) +	static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names)  	{  		llassert(avatar_names.size() == avatar_uuids.size()); -  		LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE);  		if (!active_panel)  		{ @@ -683,7 +675,7 @@ void LLAvatarActions::toggleBlock(const LLUUID& id)  {  	std::string name; -	gCacheName->getFullName(id, name); +	gCacheName->getFullName(id, name); // needed for mute  	LLMute mute(id, name, LLMute::AGENT);  	if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName)) @@ -855,23 +847,6 @@ bool LLAvatarActions::handleUnfreeze(const LLSD& notification, const LLSD& respo  	}  	return false;  } -// static -bool LLAvatarActions::callbackAddFriend(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if (option == 0) -	{ -		// Servers older than 1.25 require the text of the message to be the -		// calling card folder ID for the offering user. JC -		LLUUID calling_card_folder_id =  -			gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); -		std::string message = calling_card_folder_id.asString(); -		requestFriendship(notification["payload"]["id"].asUUID(),  -		    notification["payload"]["name"].asString(), -		    message); -	} -    return false; -}  // static  void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message) @@ -889,7 +864,6 @@ void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::stri  	LLSD payload;  	payload["from_id"] = target_id; -	payload["SESSION_NAME"] = target_name;  	payload["SUPPRESS_TOAST"] = true;  	LLNotificationsUtil::add("FriendshipOffered", args, payload);  } @@ -904,16 +878,16 @@ bool LLAvatarActions::isFriend(const LLUUID& id)  bool LLAvatarActions::isBlocked(const LLUUID& id)  {  	std::string name; -	gCacheName->getFullName(id, name); +	gCacheName->getFullName(id, name); // needed for mute  	return LLMuteList::getInstance()->isMuted(id, name);  }  // static  bool LLAvatarActions::canBlock(const LLUUID& id)  { -	std::string firstname, lastname; -	gCacheName->getName(id, firstname, lastname); -	bool is_linden = !LLStringUtil::compareStrings(lastname, "Linden"); +	std::string full_name; +	gCacheName->getFullName(id, full_name); // needed for mute +	bool is_linden = (full_name.find("Linden") != std::string::npos);  	bool is_self = id == gAgentID;  	return !is_self && !is_linden;  } diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index d106a83eea..2d69c01ffe 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -184,7 +184,6 @@ public:  private: -	static bool callbackAddFriend(const LLSD& notification, const LLSD& response);  	static bool callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response);  	static bool handleRemove(const LLSD& notification, const LLSD& response);  	static bool handlePay(const LLSD& notification, const LLSD& response, LLUUID avatar_id); diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index abb79b53a7..f4d5d45726 100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp @@ -34,17 +34,19 @@  #include "llavatariconctrl.h" +// viewer includes  #include "llagent.h"  #include "llavatarconstants.h"  #include "llcallingcard.h" // for LLAvatarTracker  #include "llavataractions.h"  #include "llmenugl.h"  #include "lluictrlfactory.h" - -#include "llcachename.h"  #include "llagentdata.h"  #include "llimfloater.h" +// library includes +#include "llavatarnamecache.h" +  #define MENU_ITEM_VIEW_PROFILE 0  #define MENU_ITEM_SEND_IM 1 @@ -233,6 +235,9 @@ void LLAvatarIconCtrl::setValue(const LLSD& value)  			// Check if cache already contains image_id for that avatar  			if (!updateFromCache())  			{ +				// *TODO: Consider getting avatar icon/badge directly from  +				// People API, rather than sending AvatarPropertyRequest +				// messages.  People API already hits the user table.  				LLIconCtrl::setValue(mDefaultIconName);  				app->addObserver(mAvatarId, this);  				app->sendAvatarPropertiesRequest(mAvatarId); @@ -244,10 +249,9 @@ void LLAvatarIconCtrl::setValue(const LLSD& value)  		LLIconCtrl::setValue(value);  	} -	if  (gCacheName) -	{ -		gCacheName->get(mAvatarId, FALSE, boost::bind(&LLAvatarIconCtrl::nameUpdatedCallback, this, _1, _2, _3, _4)); -	} +	LLAvatarNameCache::get(mAvatarId, +		boost::bind(&LLAvatarIconCtrl::onAvatarNameCache,  +			this, _1, _2));  }  bool LLAvatarIconCtrl::updateFromCache() @@ -290,24 +294,21 @@ void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type)  	}  } -void LLAvatarIconCtrl::nameUpdatedCallback( -	const LLUUID& id, -	const std::string& first, -	const std::string& last, -	BOOL is_group) +void LLAvatarIconCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)  { -	if (id == mAvatarId) +	if (agent_id == mAvatarId)  	{ -		mFirstName = first; -		mLastName = last; +		// Most avatar icon controls are next to a UI element that shows +		// a display name, so only show username. +		mFullName = av_name.mUsername;  		if (mDrawTooltip)  		{ -			setToolTip(mFirstName + " " + mLastName); +			setToolTip(mFullName);  		}  		else  		{ -			setToolTip(std::string("")); +			setToolTip(std::string());  		}  	}  } diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h index 38616b7852..5befc73d92 100644 --- a/indra/newview/llavatariconctrl.h +++ b/indra/newview/llavatariconctrl.h @@ -37,6 +37,8 @@  #include "llavatarpropertiesprocessor.h"  #include "llviewermenu.h" +class LLAvatarName; +  class LLAvatarIconIDCache: public LLSingleton<LLAvatarIconIDCache>  {  public: @@ -90,22 +92,16 @@ public:  	// LLAvatarPropertiesProcessor observer trigger  	virtual void processProperties(void* data, EAvatarProcessorType type); -	void nameUpdatedCallback( -		const LLUUID& id, -		const std::string& first, -		const std::string& last, -		BOOL is_group); +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);  	const LLUUID&		getAvatarId() const	{ return mAvatarId; } -	const std::string&	getFirstName() const { return mFirstName; } -	const std::string&	getLastName() const { return mLastName; } +	const std::string&	getFullName() const { return mFullName; }  	void setDrawTooltip(bool value) { mDrawTooltip = value;}  protected:  	LLUUID				mAvatarId; -	std::string			mFirstName; -	std::string			mLastName; +	std::string			mFullName;  	bool				mDrawTooltip;  	std::string			mDefaultIconName; diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 99156b9d9d..9d14804b33 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -44,6 +44,7 @@  // newview  #include "llagentdata.h" // for comparator  #include "llavatariconctrl.h" +#include "llavatarnamecache.h"  #include "llcallingcard.h" // for LLAvatarTracker  #include "llcachename.h"  #include "lllistcontextmenu.h" @@ -242,12 +243,15 @@ void LLAvatarList::refresh()  	// Handle added items.  	unsigned nadded = 0; +	const std::string waiting_str = LLTrans::getString("AvatarNameWaiting"); +  	for (uuid_vec_t::const_iterator it=added.begin(); it != added.end(); it++)  	{ -		std::string name;  		const LLUUID& buddy_id = *it; -		have_names &= (bool)gCacheName->getFullName(buddy_id, name); -		if (!have_filter || findInsensitive(name, mNameFilter)) +		LLAvatarName av_name; +		have_names &= LLAvatarNameCache::get(buddy_id, &av_name); + +		if (!have_filter || findInsensitive(av_name.mDisplayName, mNameFilter))  		{  			if (nadded >= ADD_LIMIT)  			{ @@ -256,7 +260,11 @@ void LLAvatarList::refresh()  			}  			else  			{ -				addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); +				// *NOTE: If you change the UI to show a different string, +				// be sure to change the filter code below. +				addNewItem(buddy_id,  +					       av_name.mDisplayName.empty() ? waiting_str : av_name.mDisplayName,  +						   LLAvatarTracker::instance().isBuddyOnline(buddy_id));  				modified = true;  				nadded++;  			} @@ -278,10 +286,10 @@ void LLAvatarList::refresh()  		for (std::vector<LLSD>::const_iterator it=cur_values.begin(); it != cur_values.end(); it++)  		{ -			std::string name;  			const LLUUID& buddy_id = it->asUUID(); -			have_names &= (bool)gCacheName->getFullName(buddy_id, name); -			if (!findInsensitive(name, mNameFilter)) +			LLAvatarName av_name; +			have_names &= LLAvatarNameCache::get(buddy_id, &av_name); +			if (!findInsensitive(av_name.mDisplayName, mNameFilter))  			{  				removeItemByUUID(buddy_id);  				modified = true; @@ -333,14 +341,14 @@ bool LLAvatarList::filterHasMatches()  	for (uuid_vec_t::const_iterator it=values.begin(); it != values.end(); it++)  	{ -		std::string name;  		const LLUUID& buddy_id = *it; -		BOOL have_name = gCacheName->getFullName(buddy_id, name); +		LLAvatarName av_name; +		bool have_name = LLAvatarNameCache::get(buddy_id, &av_name);  		// If name has not been loaded yet we consider it as a match.  		// When the name will be loaded the filter will be applied again(in refresh()). -		if (have_name && !findInsensitive(name, mNameFilter)) +		if (have_name && !findInsensitive(av_name.mDisplayName, mNameFilter))  		{  			continue;  		} @@ -374,7 +382,7 @@ S32 LLAvatarList::notifyParent(const LLSD& info)  void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos)  {  	LLAvatarListItem* item = new LLAvatarListItem(); -	item->setName(name); +	// This sets the name as a side effect  	item->setAvatarId(id, mSessionID, mIgnoreOnlineStatus);  	item->setOnline(mIgnoreOnlineStatus ? true : is_online);  	item->showLastInteractionTime(mShowLastInteractionTime); @@ -540,11 +548,13 @@ void LLAvalineListItem::setName(const std::string& name)  		std::string hidden_name = LLTrans::getString("AvalineCaller", args);  		LL_DEBUGS("Avaline") << "Avaline caller: " << uuid << ", name: " << hidden_name << LL_ENDL; -		LLAvatarListItem::setName(hidden_name); +		LLAvatarListItem::setAvatarName(hidden_name); +		LLAvatarListItem::setAvatarToolTip(hidden_name);  	}  	else  	{  		const std::string& formatted_phone = LLTextUtil::formatPhoneNumber(name); -		LLAvatarListItem::setName(formatted_phone); +		LLAvatarListItem::setAvatarName(formatted_phone); +		LLAvatarListItem::setAvatarToolTip(formatted_phone);  	}  } diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index fffc6e6e73..b9b85094fb 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -34,7 +34,6 @@  #define LL_LLAVATARLIST_H  #include "llflatlistview.h" -  #include "llavatarlistitem.h"  class LLTimer; diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index c74075d67f..079a7d3ed2 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -41,6 +41,7 @@  #include "lltextutil.h"  #include "llagent.h" +#include "llavatarnamecache.h"  #include "llavatariconctrl.h"  #include "lloutputmonitorctrl.h" @@ -167,11 +168,16 @@ void LLAvatarListItem::setOnline(bool online)  	setState(online ? IS_ONLINE : IS_OFFLINE);  } -void LLAvatarListItem::setName(const std::string& name) +void LLAvatarListItem::setAvatarName(const std::string& name)  {  	setNameInternal(name, mHighlihtSubstring);  } +void LLAvatarListItem::setAvatarToolTip(const std::string& tooltip) +{ +	mAvatarName->setToolTip(tooltip); +} +  void LLAvatarListItem::setHighlight(const std::string& highlight)  {  	setNameInternal(mAvatarName->getText(), mHighlihtSubstring = highlight); @@ -230,7 +236,8 @@ void LLAvatarListItem::setAvatarId(const LLUUID& id, const LLUUID& session_id, b  		mAvatarIcon->setValue(id);  		// Set avatar name. -		gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3)); +		LLAvatarNameCache::get(id, +			boost::bind(&LLAvatarListItem::onAvatarNameCache, this, _2));  	}  } @@ -323,23 +330,27 @@ const LLUUID& LLAvatarListItem::getAvatarId() const  	return mAvatarId;  } -const std::string LLAvatarListItem::getAvatarName() const +std::string LLAvatarListItem::getAvatarName() const  {  	return mAvatarName->getValue();  } +std::string LLAvatarListItem::getAvatarToolTip() const +{ +	return mAvatarName->getToolTip(); +} +  //== PRIVATE SECITON ==========================================================  void LLAvatarListItem::setNameInternal(const std::string& name, const std::string& highlight)  {  	LLTextUtil::textboxSetHighlightedVal(mAvatarName, mAvatarNameStyle, name, highlight); -	mAvatarName->setToolTip(name);  } -void LLAvatarListItem::onNameCache(const std::string& first_name, const std::string& last_name) +void LLAvatarListItem::onAvatarNameCache(const LLAvatarName& av_name)  { -	std::string name = first_name + " " + last_name; -	setName(name); +	setAvatarName(av_name.mDisplayName); +	setAvatarToolTip(av_name.mUsername);  	//requesting the list to resort  	notifyParent(LLSD().with("sort", LLSD())); diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index ba9c3574d5..78257ce9ba 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -42,6 +42,7 @@  #include "llcallingcard.h" // for LLFriendObserver  class LLAvatarIconCtrl; +class LLAvatarName;  class LLAvatarListItem : public LLPanel, public LLFriendObserver  { @@ -91,7 +92,8 @@ public:  	virtual void changed(U32 mask); // from LLFriendObserver  	void setOnline(bool online); -	void setName(const std::string& name); +	void setAvatarName(const std::string& name); +	void setAvatarToolTip(const std::string& tooltip);  	void setHighlight(const std::string& highlight);  	void setState(EItemState item_style);  	void setAvatarId(const LLUUID& id, const LLUUID& session_id, bool ignore_status_changes = false, bool is_resident = true); @@ -104,7 +106,8 @@ public:  	void setAvatarIconVisible(bool visible);  	const LLUUID& getAvatarId() const; -	const std::string getAvatarName() const; +	std::string getAvatarName() const; +	std::string getAvatarToolTip() const;  	void onInfoBtnClick();  	void onProfileBtnClick(); @@ -145,7 +148,7 @@ private:  	} EAvatarListItemChildIndex;  	void setNameInternal(const std::string& name, const std::string& highlight); -	void onNameCache(const std::string& first_name, const std::string& last_name); +	void onAvatarNameCache(const LLAvatarName& av_name);  	std::string formatSeconds(U32 secs); diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index b494470cbc..03ab8a9de1 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -33,13 +33,14 @@  #include "llviewerprecompiledheaders.h" +#include "llcallfloater.h" +  #include "llnotificationsutil.h"  #include "lltrans.h" -#include "llcallfloater.h" -  #include "llagent.h"  #include "llagentdata.h" // for gAgentID +#include "llavatarnamecache.h"  #include "llavatariconctrl.h"  #include "llavatarlist.h"  #include "llbottomtray.h" @@ -83,7 +84,8 @@ public:  	void setName(const std::string& name)  	{  		const std::string& formatted_phone = LLTextUtil::formatPhoneNumber(name); -		LLAvatarListItem::setName(formatted_phone); +		LLAvatarListItem::setAvatarName(formatted_phone); +		LLAvatarListItem::setAvatarToolTip(formatted_phone);  	}  	void setSpeakerId(const LLUUID& id) { mSpeakingIndicator->setSpeakerId(id); } @@ -374,9 +376,31 @@ void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)  	call_floater->connectToChannel(channel);  } +void LLCallFloater::onAvatarNameCache(const LLUUID& agent_id, +									  const LLAvatarName& av_name) +{ +	LLStringUtil::format_map_t args; +	args["[NAME]"] = av_name.getCompleteName(); +	std::string title = getString("title_peer_2_peer", args); +	setTitle(title); +} +  void LLCallFloater::updateTitle()  {  	LLVoiceChannel* voice_channel = LLVoiceChannel::getCurrentVoiceChannel(); +	if (mVoiceType == VC_PEER_TO_PEER) +	{ +		LLUUID session_id = voice_channel->getSessionID(); +		LLIMModel::LLIMSession* im_session = +			LLIMModel::getInstance()->findIMSession(session_id); +		if (im_session) +		{ +			LLAvatarNameCache::get(im_session->mOtherParticipantID, +				boost::bind(&LLCallFloater::onAvatarNameCache, +					this, _1, _2)); +			return; +		} +	}  	std::string title;  	switch (mVoiceType)  	{ @@ -421,9 +445,10 @@ void LLCallFloater::initAgentData()  	{  		mAgentPanel->childSetValue("user_icon", gAgentID); -		std::string name; -		gCacheName->getFullName(gAgentID, name); -		mAgentPanel->childSetValue("user_text", name); +		// Just use display name, because it's you +		LLAvatarName av_name; +		LLAvatarNameCache::get( gAgentID, &av_name ); +		mAgentPanel->childSetValue("user_text", av_name.mDisplayName);  		mSpeakingIndicator = mAgentPanel->getChild<LLOutputMonitorCtrl>("speaking_indicator");  		mSpeakingIndicator->setSpeakerId(gAgentID); @@ -444,7 +469,10 @@ void LLCallFloater::setModeratorMutedVoice(bool moderator_muted)  void LLCallFloater::updateAgentModeratorState()  {  	std::string name; -	gCacheName->getFullName(gAgentID, name); +	// Just use display name, because it's you +	LLAvatarName av_name; +	LLAvatarNameCache::get(gAgentID, &av_name); +	name = av_name.mDisplayName;  	if(gAgent.isInGroup(mSpeakerManager->getSessionID()))  	{ diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index e4341175e2..5eafede482 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -40,6 +40,7 @@  class LLAvatarList;  class LLAvatarListItem; +class LLAvatarName;  class LLNonAvatarCaller;  class LLOutputMonitorCtrl;  class LLParticipantList; @@ -122,6 +123,10 @@ private:  	 */  	void onAvatarListRefreshed(); +	/** +	 * Updates window title with an avatar name +	 */ +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);  	void updateTitle();  	void initAgentData(); diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 1a6c11fa73..1685562013 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -43,6 +43,7 @@  //#include <iterator>  #include "indra_constants.h" +#include "llavatarnamecache.h"  #include "llcachename.h"  #include "llstl.h"  #include "lltimer.h" @@ -50,6 +51,7 @@  #include "message.h"  #include "llagent.h" +#include "llavatarnamecache.h"  #include "llbutton.h"  #include "llinventoryobserver.h"  #include "llinventorymodel.h" @@ -96,8 +98,10 @@ const F32 OFFLINE_SECONDS = FIND_FREQUENCY + 8.0f;  // static  LLAvatarTracker LLAvatarTracker::sInstance; - - +static void on_avatar_name_cache_notify(const LLUUID& agent_id, +										const LLAvatarName& av_name, +										bool online, +										LLSD payload);  ///----------------------------------------------------------------------------  /// Class LLAvatarTracker @@ -250,7 +254,7 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)  	using namespace std;  	U32 new_buddy_count = 0; -	std::string first,last; +	std::string full_name;  	LLUUID agent_id;  	for(buddy_map_t::const_iterator itr = buds.begin(); itr != buds.end(); ++itr)  	{ @@ -260,7 +264,8 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)  		{  			++new_buddy_count;  			mBuddyInfo[agent_id] = (*itr).second; -			gCacheName->getName(agent_id, first, last); +			// IDEVO: is this necessary?  name is unused? +			gCacheName->getFullName(agent_id, full_name);  			addChangedMask(LLFriendObserver::ADD, agent_id);  			lldebugs << "Added buddy " << agent_id  					<< ", " << (mBuddyInfo[agent_id]->isOnline() ? "Online" : "Offline") @@ -633,12 +638,9 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg)  			{  				if((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^  new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS)  				{ -					std::string name;  					LLSD args; -					if(gCacheName->getFullName(agent_id, name)) -					{ -						args["NAME"] = name; -					} +					args["NAME"] = LLSLURL("agent", agent_id, "displayname").getSLURLString(); +					  					LLSD payload;  					payload["from_id"] = agent_id;  					if(LLRelationship::GRANT_MODIFY_OBJECTS & new_rights) @@ -680,8 +682,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)  		{  			tracking_id = mTrackingData->mAvatarID;  		} -		BOOL notify = FALSE; -		LLSD args;  		LLSD payload;  		for(S32 i = 0; i < count; ++i)  		{ @@ -691,17 +691,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)  			if(info)  			{  				setBuddyOnline(agent_id,online); -				if(chat_notify) -				{ -					std::string first, last; -					if(gCacheName->getName(agent_id, first, last)) -					{ -						notify = TRUE; -						args["FIRST"] = first; -						args["LAST"] = last; -					} - -				}  			}  			else  			{ @@ -717,29 +706,12 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)  			// *TODO: get actual inventory id  			gInventory.addChangedMask(LLInventoryObserver::CALLING_CARD, LLUUID::null);  		} -		if(notify) +		if(chat_notify)  		{ -			// Popup a notify box with online status of this agent -			LLNotificationPtr notification; - -			if (online) -			{ -				notification = -					LLNotificationsUtil::add("FriendOnline", -											 args, -											 payload.with("respond_on_mousedown", TRUE), -											 boost::bind(&LLAvatarActions::startIM, agent_id)); -			} -			else -			{ -				notification = -					LLNotificationsUtil::add("FriendOffline", args, payload); -			} - -			// If there's an open IM session with this agent, send a notification there too. -			LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id); -			std::string notify_msg = notification->getMessage(); -			LLIMModel::instance().proccessOnlineOfflineNotification(session_id, notify_msg); +			// Look up the name of this agent for the notification +			LLAvatarNameCache::get(agent_id, +				boost::bind(&on_avatar_name_cache_notify, +					_1, _2, online, payload));  		}  		mModifyMask |= LLFriendObserver::ONLINE; @@ -748,6 +720,37 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)  	}  } +static void on_avatar_name_cache_notify(const LLUUID& agent_id, +										const LLAvatarName& av_name, +										bool online, +										LLSD payload) +{ +	// Popup a notify box with online status of this agent +	// Use display name only because this user is your friend +	LLSD args; +	args["NAME"] = av_name.mDisplayName; + +	LLNotificationPtr notification; +	if (online) +	{ +		notification = +			LLNotificationsUtil::add("FriendOnline", +									 args, +									 payload.with("respond_on_mousedown", TRUE), +									 boost::bind(&LLAvatarActions::startIM, agent_id)); +	} +	else +	{ +		notification = +			LLNotificationsUtil::add("FriendOffline", args, payload); +	} + +	// If there's an open IM session with this agent, send a notification there too. +	LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id); +	std::string notify_msg = notification->getMessage(); +	LLIMModel::instance().proccessOnlineOfflineNotification(session_id, notify_msg); +} +  void LLAvatarTracker::formFriendship(const LLUUID& id)  {  	if(id.notNull()) @@ -868,10 +871,9 @@ bool LLCollectProxyBuddies::operator()(const LLUUID& buddy_id, LLRelationship* b  bool LLCollectMappableBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)  { -	gCacheName->getName(buddy_id, mFirst, mLast); -	std::ostringstream fullname; -	fullname << mFirst << " " << mLast; -	buddy_map_t::value_type value(fullname.str(), buddy_id); +	LLAvatarName av_name; +	LLAvatarNameCache::get( buddy_id, &av_name); +	buddy_map_t::value_type value(av_name.mDisplayName, buddy_id);  	if(buddy->isOnline() && buddy->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION))  	{  		mMappable.insert(value); @@ -881,10 +883,8 @@ bool LLCollectMappableBuddies::operator()(const LLUUID& buddy_id, LLRelationship  bool LLCollectOnlineBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)  { -	gCacheName->getName(buddy_id, mFirst, mLast); -	std::ostringstream fullname; -	fullname << mFirst << " " << mLast; -	buddy_map_t::value_type value(fullname.str(), buddy_id); +	gCacheName->getFullName(buddy_id, mFullName); +	buddy_map_t::value_type value(mFullName, buddy_id);  	if(buddy->isOnline())  	{  		mOnline.insert(value); @@ -894,10 +894,10 @@ bool LLCollectOnlineBuddies::operator()(const LLUUID& buddy_id, LLRelationship*  bool LLCollectAllBuddies::operator()(const LLUUID& buddy_id, LLRelationship* buddy)  { -	gCacheName->getName(buddy_id, mFirst, mLast); -	std::ostringstream fullname; -	fullname << mFirst << " " << mLast; -	buddy_map_t::value_type value(fullname.str(), buddy_id); +	LLAvatarName av_name; +	LLAvatarNameCache::get(buddy_id, &av_name); +	mFullName = av_name.mDisplayName; +	buddy_map_t::value_type value(mFullName, buddy_id);  	if(buddy->isOnline())  	{  		mOnline.insert(value); @@ -908,5 +908,3 @@ bool LLCollectAllBuddies::operator()(const LLUUID& buddy_id, LLRelationship* bud  	}  	return true;  } - - diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h index 47b0dcb903..5bd1f05687 100644 --- a/indra/newview/llcallingcard.h +++ b/indra/newview/llcallingcard.h @@ -241,8 +241,7 @@ public:  	virtual bool operator()(const LLUUID& buddy_id, LLRelationship* buddy);  	typedef std::map<std::string, LLUUID, LLDictionaryLess> buddy_map_t;  	buddy_map_t mMappable; -	std::string mFirst; -	std::string mLast; +	std::string mFullName;  };  // collect dictionary sorted map of name -> agent_id for every online buddy @@ -254,8 +253,7 @@ public:  	virtual bool operator()(const LLUUID& buddy_id, LLRelationship* buddy);  	typedef std::map<std::string, LLUUID, LLDictionaryLess> buddy_map_t;  	buddy_map_t mOnline; -	std::string mFirst; -	std::string mLast; +	std::string mFullName;  };  // collect dictionary sorted map of name -> agent_id for every buddy, @@ -269,8 +267,7 @@ public:  	typedef std::map<std::string, LLUUID, LLDictionaryLess> buddy_map_t;  	buddy_map_t mOnline;  	buddy_map_t mOffline; -	std::string mFirst; -	std::string mLast; +	std::string mFullName;  };  #endif // LL_LLCALLINGCARD_H diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 7c33923f04..1c77567a80 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -32,10 +32,12 @@  #include "llviewerprecompiledheaders.h" +#include "llchathistory.h" + +#include "llavatarnamecache.h"  #include "llinstantmessage.h"  #include "llimview.h" -#include "llchathistory.h"  #include "llcommandhandler.h"  #include "llpanel.h"  #include "lluictrlfactory.h" @@ -104,6 +106,18 @@ LLObjectIMHandler gObjectIMHandler;  class LLChatHistoryHeader: public LLPanel  {  public: +	LLChatHistoryHeader() +	:	LLPanel(), +		mPopupMenuHandleAvatar(), +		mPopupMenuHandleObject(), +		mAvatarID(), +		mSourceType(CHAT_SOURCE_UNKNOWN), +		mFrom(), +		mSessionID(), +		mMinUserNameWidth(0), +		mUserNameFont(NULL) +	{} +  	static LLChatHistoryHeader* createInstance(const std::string& file_name)  	{  		LLChatHistoryHeader* pInstance = new LLChatHistoryHeader; @@ -246,7 +260,6 @@ public:  		mAvatarID = chat.mFromID;  		mSessionID = chat.mSessionID;  		mSourceType = chat.mSourceType; -		gCacheName->get(mAvatarID, FALSE, boost::bind(&LLChatHistoryHeader::nameUpdatedCallback, this, _1, _2, _3, _4));  		//*TODO overly defensive thing, source type should be maintained out there  		if((chat.mFromID.isNull() && chat.mFromName.empty()) || chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull()) @@ -254,22 +267,40 @@ public:  			mSourceType = CHAT_SOURCE_SYSTEM;  		} -		LLTextBox* userName = getChild<LLTextBox>("user_name"); +		mUserNameFont = style_params.font(); +		LLTextBox* user_name = getChild<LLTextBox>("user_name"); +		user_name->setReadOnlyColor(style_params.readonly_color()); +		user_name->setColor(style_params.color()); -		userName->setReadOnlyColor(style_params.readonly_color()); -		userName->setColor(style_params.color()); -		 -		userName->setValue(chat.mFromName); -		mFrom = chat.mFromName; -		if (chat.mFromName.empty() || CHAT_SOURCE_SYSTEM == mSourceType) +		if (chat.mFromName.empty() +			|| mSourceType == CHAT_SOURCE_SYSTEM +			|| mAvatarID.isNull())  		{  			mFrom = LLTrans::getString("SECOND_LIFE"); -			userName->setValue(mFrom); +			user_name->setValue(mFrom); +			updateMinUserNameWidth(); +		} +		else if (mSourceType == CHAT_SOURCE_AGENT +				 && chat.mChatStyle != CHAT_STYLE_HISTORY) +		{ +			// ...from a normal user, lookup the name and fill in later. +			// *NOTE: Do not do this for chat history logs, otherwise the viewer +			// will flood the People API with lookup requests on startup + +			// Start with blank so sample data from XUI XML doesn't +			// flash on the screen +			user_name->setValue( LLSD() ); +			LLAvatarNameCache::get(mAvatarID, +				boost::bind(&LLChatHistoryHeader::onAvatarNameCache, this, _1, _2)); +		} +		else { +			// ...from an object, just use name as given +			mFrom = chat.mFromName; +			user_name->setValue(mFrom); +			updateMinUserNameWidth();  		} -		mMinUserNameWidth = style_params.font()->getWidth(userName->getWText().c_str()) + PADDING; -  		setTimeField(chat);  		LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); @@ -323,12 +354,28 @@ public:  		LLPanel::draw();  	} -	void nameUpdatedCallback(const LLUUID& id,const std::string& first,const std::string& last,BOOL is_group) +	void updateMinUserNameWidth()  	{ -		if (id != mAvatarID) -			return; -		mFrom = first + " " + last; +		if (mUserNameFont) +		{ +			LLTextBox* user_name = getChild<LLTextBox>("user_name"); +			const LLWString& text = user_name->getWText(); +			mMinUserNameWidth = mUserNameFont->getWidth(text.c_str()) + PADDING; +		}  	} + +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +	{ +		mFrom = av_name.mDisplayName; + +		LLTextBox* user_name = getChild<LLTextBox>("user_name"); +		user_name->setValue( LLSD(av_name.mDisplayName ) ); +		user_name->setToolTip( av_name.mUsername ); +		setToolTip( av_name.mUsername ); +		// name might have changed, update width +		updateMinUserNameWidth(); +	} +  protected:  	static const S32 PADDING = 20; @@ -455,6 +502,7 @@ protected:  	LLUUID				mSessionID;  	S32					mMinUserNameWidth; +	const LLFontGL*		mUserNameFont;  };  LLUICtrl* LLChatHistoryHeader::sInfoCtrl = NULL; diff --git a/indra/newview/lldateutil.cpp b/indra/newview/lldateutil.cpp index 3e71ecdfba..ae955b6cad 100644 --- a/indra/newview/lldateutil.cpp +++ b/indra/newview/lldateutil.cpp @@ -172,3 +172,23 @@ std::string LLDateUtil::ageFromDate(const std::string& date_string)  {  	return ageFromDate(date_string, LLDate::now());  } + +//std::string LLDateUtil::ageFromDateISO(const std::string& date_string, +//									   const LLDate& now) +//{ +//	S32 born_month, born_day, born_year; +//	S32 matched = sscanf(date_string.c_str(), "%d-%d-%d", +//			&born_year, &born_month, &born_day); +//	if (matched != 3) return "???"; +//	date.fromYMDHMS(year, month, day); +//	F64 secs_since_epoch = date.secondsSinceEpoch(); +//	// Correct for the fact that specified date is in Pacific time, == UTC - 8 +//	secs_since_epoch += 8.0 * 60.0 * 60.0; +//	date.secondsSinceEpoch(secs_since_epoch); +//	return ageFromDate(born_year, born_month, born_day, now); +//} +// +//std::string LLDateUtil::ageFromDateISO(const std::string& date_string) +//{ +//	return ageFromDateISO(date_string, LLDate::now()); +//} diff --git a/indra/newview/lldateutil.h b/indra/newview/lldateutil.h index a0df21022e..8d41eea511 100644 --- a/indra/newview/lldateutil.h +++ b/indra/newview/lldateutil.h @@ -67,6 +67,14 @@ namespace LLDateUtil  	// Calls the above with LLDate::now()  	std::string ageFromDate(const std::string& date_string); + +	// As above, for YYYY-MM-DD dates +	//std::string ageFromDateISO(const std::string& date_string, const LLDate& now); + +	// Calls the above with LLDate::now() +	//std::string ageFromDateISO(const std::string& date_string); + +	//std::string ageFromDate(S32 born_year, S32 born_month, S32 born_day, const LLDate& now);  }  #endif diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 08972853c3..05ce8cbe57 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -53,6 +53,7 @@ class LLCamera;  class LLDrawPool;  class LLDrawable;  class LLFace; +class LLFacePool;  class LLSpatialGroup;  class LLSpatialBridge;  class LLSpatialPartition; diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 8f6816b845..7ed6539387 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -41,10 +41,14 @@  #include "llimview.h"			// for gIMMgr  #include "lltooldraganddrop.h"	// for LLToolDragAndDrop  #include "llviewercontrol.h" +#include "llviewerregion.h"		// getCapability()  #include "llworld.h"  // Linden libraries +#include "llavatarnamecache.h"	// IDEVO  #include "llbutton.h" +#include "llcachename.h" +#include "llhttpclient.h"		// IDEVO  #include "lllineeditor.h"  #include "llscrolllistctrl.h"  #include "llscrolllistitem.h" @@ -53,6 +57,11 @@  #include "lluictrlfactory.h"  #include "message.h" +//#include "llsdserialize.h" + +//put it back as a member once the legacy path is out? +static std::map<LLUUID, LLAvatarName> sAvatarNameMap; +  LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback,  												   BOOL allow_multiple,  												   BOOL closeOnSelect) @@ -159,7 +168,7 @@ void LLFloaterAvatarPicker::onBtnFind()  	find();  } -static void getSelectedAvatarData(const LLScrollListCtrl* from, std::vector<std::string>& avatar_names, uuid_vec_t& avatar_ids) +static void getSelectedAvatarData(const LLScrollListCtrl* from, uuid_vec_t& avatar_ids, std::vector<LLAvatarName>& avatar_names)  {  	std::vector<LLScrollListItem*> items = from->getAllSelected();  	for (std::vector<LLScrollListItem*>::iterator iter = items.begin(); iter != items.end(); ++iter) @@ -167,8 +176,21 @@ static void getSelectedAvatarData(const LLScrollListCtrl* from, std::vector<std:  		LLScrollListItem* item = *iter;  		if (item->getUUID().notNull())  		{ -			avatar_names.push_back(item->getColumn(0)->getValue().asString());  			avatar_ids.push_back(item->getUUID()); + +			std::map<LLUUID, LLAvatarName>::iterator iter = sAvatarNameMap.find(item->getUUID()); +			if (iter != sAvatarNameMap.end()) +			{ +				avatar_names.push_back(iter->second); +			} +			else +			{ +				// the only case where it isn't in the name map is friends +				// but it should be in the name cache +				LLAvatarName av_name; +				LLAvatarNameCache::get(item->getUUID(), &av_name); +				avatar_names.push_back(av_name); +			}  		}  	}  } @@ -204,10 +226,10 @@ void LLFloaterAvatarPicker::onBtnSelect()  		if(list)  		{ -			std::vector<std::string>	avatar_names;  			uuid_vec_t			avatar_ids; -			getSelectedAvatarData(list, avatar_names, avatar_ids); -			mSelectionCallback(avatar_names, avatar_ids); +			std::vector<LLAvatarName>	avatar_names; +			getSelectedAvatarData(list, avatar_ids, avatar_names); +			mSelectionCallback(avatar_ids, avatar_names);  		}  	}  	getChild<LLScrollListCtrl>("SearchResults")->deselectAllItems(TRUE); @@ -257,15 +279,22 @@ void LLFloaterAvatarPicker::populateNearMe()  		if(av == gAgent.getID()) continue;  		LLSD element;  		element["id"] = av; // value -		std::string fullname; -		if(!gCacheName->getFullName(av, fullname)) +		LLAvatarName av_name; + +		if (!LLAvatarNameCache::get(av, &av_name))  		{ +			element["columns"][0]["column"] = "name";  			element["columns"][0]["value"] = LLCacheName::getDefaultName();  			all_loaded = FALSE;  		}			  		else  		{ -			element["columns"][0]["value"] = fullname; +			element["columns"][0]["column"] = "name"; +			element["columns"][0]["value"] = av_name.mDisplayName; +			element["columns"][1]["column"] = "username"; +			element["columns"][1]["value"] = av_name.mUsername; + +			sAvatarNameMap[av] = av_name;  		}  		near_me_scroller->addElement(element);  		empty = FALSE; @@ -300,7 +329,6 @@ void LLFloaterAvatarPicker::populateFriend()  	LLAvatarTracker::instance().applyFunctor(collector);  	LLCollectAllBuddies::buddy_map_t::iterator it; -	  	for(it = collector.mOnline.begin(); it!=collector.mOnline.end(); it++)  	{  		friends_scroller->addStringUUIDItem(it->first, it->second); @@ -352,14 +380,69 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const  	return FALSE;  } +class LLAvatarPickerResponder : public LLHTTPClient::Responder +{ +public: +	LLUUID mQueryID; + +	LLAvatarPickerResponder(const LLUUID& id) : mQueryID(id) { } + +	/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) +	{ +		//std::ostringstream ss; +		//LLSDSerialize::toPrettyXML(content, ss); +		//llinfos << ss.str() << llendl; + +		if (isGoodStatus(status)) +		{ +			LLFloaterAvatarPicker* floater = +				LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker"); +			if (floater) +			{ +				floater->processResponse(mQueryID, content); +			} +		} +		else +		{ +			llinfos << "avatar picker failed " << status +				<< " reason " << reason << llendl; +		} +	} +}; +  void LLFloaterAvatarPicker::find()  { +	//clear our stored LLAvatarNames +	sAvatarNameMap.clear(); +  	std::string text = childGetValue("Edit").asString();  	mQueryID.generate(); -	LLMessageSystem* msg = gMessageSystem; +	std::string url; +	url.reserve(128); // avoid a memory allocation or two +	LLViewerRegion* region = gAgent.getRegion(); +	url = region->getCapability("AvatarPickerSearch"); +	// Prefer use of capabilities to search on both SLID and display name +	// but allow display name search to be manually turned off for test +	if (!url.empty() +		&& LLAvatarNameCache::useDisplayNames()) +	{ +		// capability urls don't end in '/', but we need one to parse +		// query parameters correctly +		if (url.size() > 0 && url[url.size()-1] != '/') +		{ +			url += "/"; +		} +		url += "?names="; +		url += LLURI::escape(text); +		llinfos << "avatar picker " << url << llendl; +		LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID)); +	} +	else +	{ +	LLMessageSystem* msg = gMessageSystem;  	msg->newMessage("AvatarPickerRequest");  	msg->nextBlock("AgentData");  	msg->addUUID("AgentID", gAgent.getID()); @@ -367,8 +450,8 @@ void LLFloaterAvatarPicker::find()  	msg->addUUID("QueryID", mQueryID);	// not used right now  	msg->nextBlock("Data");  	msg->addString("Name", text); -  	gAgent.sendReliableMessage(); +	}  	getChild<LLScrollListCtrl>("SearchResults")->deleteAllItems();  	getChild<LLScrollListCtrl>("SearchResults")->setCommentText(getString("searching")); @@ -509,12 +592,21 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void*  		}  		else  		{ -			avatar_name = first_name + " " + last_name; +			avatar_name = LLCacheName::buildFullName(first_name, last_name);  			search_results->setEnabled(TRUE);  			found_one = TRUE; + +			LLAvatarName av_name; +			av_name.mLegacyFirstName = first_name; +			av_name.mLegacyLastName = last_name; +			av_name.mDisplayName = avatar_name; +			const LLUUID& agent_id = avatar_id; +			sAvatarNameMap[agent_id] = av_name; +  		}  		LLSD element;  		element["id"] = avatar_id; // value +		element["columns"][0]["column"] = "name";  		element["columns"][0]["value"] = avatar_name;  		search_results->addElement(element);  	} @@ -528,10 +620,61 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void*  	}  } +void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD& content) +{ +	// Check for out-of-date query +	if (query_id != mQueryID) return; + +	LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>("SearchResults"); + +	LLSD agents = content["agents"]; +	if (agents.size() == 0) +	{ +		LLStringUtil::format_map_t map; +		map["[TEXT]"] = childGetText("Edit"); +		LLSD item; +		item["id"] = LLUUID::null; +		item["columns"][0]["column"] = "name"; +		item["columns"][0]["value"] = getString("not_found", map); +		search_results->addElement(item); +		search_results->setEnabled(FALSE); +		childDisable("ok_btn"); +		return; +	} + +	// clear "Searching" label on first results +	search_results->deleteAllItems(); + +	LLSD item; +	LLSD::array_const_iterator it = agents.beginArray(); +	for ( ; it != agents.endArray(); ++it) +	{ +		const LLSD& row = *it; +		item["id"] = row["id"]; +		LLSD& columns = item["columns"]; +		columns[0]["column"] = "name"; +		columns[0]["value"] = row["display_name"]; +		columns[1]["column"] = "username"; +		columns[1]["value"] = row["username"]; +		search_results->addElement(item); + +		// add the avatar name to our list +		LLAvatarName avatar_name; +		avatar_name.fromLLSD(row); +		sAvatarNameMap[row["id"].asUUID()] = avatar_name; +	} + +	childEnable("ok_btn"); +	search_results->setEnabled(true); +	search_results->selectFirstItem(); +	onList(); +	search_results->setFocus(TRUE); +} +  //static  void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data)  { -	childSetEnabled("Find", caller->getText().size() >= 3); +	childSetEnabled("Find", caller->getText().size() > 0);  }  // virtual @@ -589,8 +732,8 @@ bool LLFloaterAvatarPicker::isSelectBtnEnabled()  		if(list)  		{  			uuid_vec_t avatar_ids; -			std::vector<std::string> avatar_names; -			getSelectedAvatarData(list, avatar_names, avatar_ids); +			std::vector<LLAvatarName> avatar_names; +			getSelectedAvatarData(list, avatar_ids, avatar_names);  			return mOkButtonValidateSignal(avatar_ids);  		}  	} diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 0af72e85a0..2607500dd8 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -37,6 +37,7 @@  #include <vector> +class LLAvatarName;  class LLScrollListCtrl;  class LLFloaterAvatarPicker : public LLFloater @@ -46,7 +47,7 @@ public:  	typedef validate_signal_t::slot_type validate_callback_t;  	// The callback function will be called with an avatar name and UUID. -	typedef boost::function<void (const std::vector<std::string>&, const uuid_vec_t&)> select_callback_t; +	typedef boost::function<void (const uuid_vec_t&, const std::vector<LLAvatarName>&)> select_callback_t;  	// Call this to select an avatar.	  	static LLFloaterAvatarPicker* show(select_callback_t callback,   									   BOOL allow_multiple = FALSE, @@ -60,6 +61,7 @@ public:  	void setOkBtnEnableCb(validate_callback_t cb);  	static void processAvatarPickerReply(class LLMessageSystem* msg, void**); +	void processResponse(const LLUUID& query_id, const LLSD& content);  	BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,  						   BOOL drop, EDragAndDropType cargo_type, diff --git a/indra/newview/llfloateravatartextures.cpp b/indra/newview/llfloateravatartextures.cpp index 847462a6c3..f09071e92d 100644 --- a/indra/newview/llfloateravatartextures.cpp +++ b/indra/newview/llfloateravatartextures.cpp @@ -33,6 +33,9 @@  #include "llviewerprecompiledheaders.h"  #include "llfloateravatartextures.h" +// library headers +#include "llavatarnamecache.h" +  #include "llagent.h"  #include "llagentwearables.h"  #include "lltexturectrl.h" @@ -138,10 +141,10 @@ void LLFloaterAvatarTextures::refresh()  		LLVOAvatar *avatarp = find_avatar(mID);  		if (avatarp)  		{ -			std::string fullname; -			if (gCacheName->getFullName(avatarp->getID(), fullname)) +			LLAvatarName av_name; +			if (LLAvatarNameCache::get(avatarp->getID(), &av_name))  			{ -				setTitle(mTitle + ": " + fullname); +				setTitle(mTitle + ": " + av_name.getCompleteName());  			}  			for (U32 i=0; i < TEX_NUM_INDICES; i++)  			{ diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index e925796526..9ccae43a92 100644 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -89,7 +89,7 @@ void LLFloaterBump::onOpen(const LLSD& key)  void LLFloaterBump::add(LLScrollListCtrl* list, LLMeanCollisionData* mcd)  { -	if (mcd->mFirstName.empty() || list->getItemCount() >= 20) +	if (mcd->mFullName.empty() || list->getItemCount() >= 20)  	{  		return;  	} @@ -127,8 +127,7 @@ void LLFloaterBump::add(LLScrollListCtrl* list, LLMeanCollisionData* mcd)  	// All above action strings are in XML file  	LLUIString text = getString(action);  	text.setArg("[TIME]", timeStr); -	text.setArg("[FIRST]", mcd->mFirstName); -	text.setArg("[LAST]", mcd->mLastName); +	text.setArg("[NAME]", mcd->mFullName);  	LLSD row;  	row["id"] = mcd->mPerp; diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 9379b3f5a8..1e6b748bd7 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -186,9 +186,8 @@ public:  	void updateNames();  	// Name cache callback  	void updateGroupName(const LLUUID& id, -						 const std::string& first_name, -						 const std::string& last_name, -						 BOOL is_group); +						 const std::string& name, +						 bool is_group);  	void refreshUI(); @@ -825,28 +824,26 @@ void LLFloaterBuyLandUI::updateNames()  	}  	else if (parcelp->getIsGroupOwned())  	{ -		gCacheName->get(parcelp->getGroupID(), TRUE, +		gCacheName->getGroup(parcelp->getGroupID(),  			boost::bind(&LLFloaterBuyLandUI::updateGroupName, this, -				_1, _2, _3, _4)); +				_1, _2, _3));  	}  	else  	{ -		mParcelSellerName = -			LLSLURL("agent", parcelp->getOwnerID(), "inspect").getSLURLString(); +		mParcelSellerName = LLSLURL("agent", parcelp->getOwnerID(), "completename").getSLURLString();  	}  }  void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id, -						 const std::string& first_name, -						 const std::string& last_name, -						 BOOL is_group) +						 const std::string& name, +						 bool is_group)  {  	LLParcel* parcelp = mParcel->getParcel();  	if (parcelp  		&& parcelp->getGroupID() == id)  	{  		// request is current -		mParcelSellerName = first_name; +		mParcelSellerName = name;  	}  } diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index bd07cfdfbf..44f104d687 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -34,6 +34,7 @@  #include "llfloatergodtools.h" +#include "llavatarnamecache.h"  #include "llcoord.h"  #include "llfontgl.h"  #include "llframetimer.h" @@ -1151,11 +1152,11 @@ void LLPanelObjectTools::onClickSetBySelection(void* data)  	panelp->childSetValue("target_avatar_name", name);  } -void LLPanelObjectTools::callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLPanelObjectTools::callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)  {  	if (ids.empty() || names.empty()) return;  	mTargetAvatar = ids[0]; -	childSetValue("target_avatar_name", names[0]); +	childSetValue("target_avatar_name", names[0].getCompleteName());  	refresh();  } diff --git a/indra/newview/llfloatergodtools.h b/indra/newview/llfloatergodtools.h index aee9db78a3..438f1024ce 100644 --- a/indra/newview/llfloatergodtools.h +++ b/indra/newview/llfloatergodtools.h @@ -41,6 +41,7 @@  #include "llpanel.h"  #include <vector> +class LLAvatarName;  class LLButton;  class LLCheckBoxCtrl;  class LLComboBox; @@ -231,7 +232,7 @@ public:  	void onChangeAnything();  	void onApplyChanges();  	void onClickSet(); -	void callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids); +	void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);  	void onClickDeletePublicOwnedBy();  	void onClickDeleteAllScriptedOwnedBy();  	void onClickDeleteAllOwnedBy(); diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 13ca7638c5..f22ab70678 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -37,7 +37,7 @@  #include "llfloaterreg.h"  #include "llfloatertools.h"  #include "llavataractions.h" -#include "llcachename.h" +#include "llavatarnamecache.h"  #include "llscrolllistctrl.h"  #include "llscrolllistitem.h"  #include "llselectmgr.h" @@ -212,8 +212,12 @@ void LLFloaterInspect::refresh()  		substitution["datetime"] = (S32) timestamp;  		LLStringUtil::format (timeStr, substitution); -		gCacheName->getFullName(obj->mPermissions->getOwner(), owner_name); -		gCacheName->getFullName(obj->mPermissions->getCreator(), creator_name); +		LLAvatarName av_name; +		LLAvatarNameCache::get(obj->mPermissions->getOwner(), &av_name); +		owner_name = av_name.getCompleteName(); +		LLAvatarNameCache::get(obj->mPermissions->getCreator(), &av_name); +		creator_name = av_name.getCompleteName(); +		  		row["id"] = obj->getObject()->getID();  		row["columns"][0]["column"] = "object_name";  		row["columns"][0]["type"] = "text"; diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index f0ed659f5a..7971c9569b 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -37,7 +37,7 @@  #include "llfloaterland.h" -#include "llcachename.h" +#include "llavatarnamecache.h"  #include "llfocusmgr.h"  #include "llnotificationsutil.h"  #include "llparcel.h" @@ -1392,10 +1392,7 @@ bool LLPanelLandObjects::callbackReturnOwnerObjects(const LLSD& notification, co  			}  			else  			{ -				std::string first, last; -				gCacheName->getName(owner_id, first, last); -				args["FIRST"] = first; -				args["LAST"] = last; +				args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString();  				LLNotificationsUtil::add("OtherObjectsReturned", args);  			}  			send_return_objects_message(parcel->getLocalID(), RT_OWNER); @@ -1613,9 +1610,9 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo  		}  		// Placeholder for name. -		std::string name; -		gCacheName->getFullName(owner_id, name);		 -		item_params.columns.add().value(name).font(FONT).column("name"); +		LLAvatarName av_name; +		LLAvatarNameCache::get(owner_id, &av_name); +		item_params.columns.add().value(av_name.getCompleteName()).font(FONT).column("name");  		object_count_str = llformat("%d", object_count);  		item_params.columns.add().value(object_count_str).font(FONT).column("count"); @@ -1724,9 +1721,7 @@ void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata)  	}  	else  	{ -		std::string name; -		gCacheName->getFullName(owner_id, name); -		args["NAME"] = name; +		args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString();  		LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2));  	}  } @@ -1785,10 +1780,7 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata)  		}  		else  		{ -			std::string name; -			gCacheName->getFullName(owner_id, name); -			args["NAME"] = name; - +			args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString();  			LLNotificationsUtil::add("ReturnObjectsNotOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2));  		}  	} @@ -2779,12 +2771,12 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata)  void LLPanelLandAccess::onClickAddAccess()  { -	gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBAccess, this, _1,_2)) ); +	gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBAccess, this, _1)) );  } -void LLPanelLandAccess::callbackAvatarCBAccess(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLPanelLandAccess::callbackAvatarCBAccess(const uuid_vec_t& ids)  { -	if (!names.empty() && !ids.empty()) +	if (!ids.empty())  	{  		LLUUID id = ids[0];  		LLParcel* parcel = mParcel->getParcel(); @@ -2823,13 +2815,13 @@ void LLPanelLandAccess::onClickRemoveAccess(void* data)  // static  void LLPanelLandAccess::onClickAddBanned()  { -	gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned, this, _1,_2))); +	gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned, this, _1)));  }  // static -void LLPanelLandAccess::callbackAvatarCBBanned(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLPanelLandAccess::callbackAvatarCBBanned(const uuid_vec_t& ids)  { -	if (!names.empty() && !ids.empty()) +	if (!ids.empty())  	{  		LLUUID id = ids[0];  		LLParcel* parcel = mParcel->getParcel(); diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index 0a743e5215..e742d04aa0 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -379,8 +379,8 @@ public:  	void onClickAddAccess();  	void onClickAddBanned(); -	void callbackAvatarCBBanned(const std::vector<std::string>& names, const uuid_vec_t& ids); -	void callbackAvatarCBAccess(const std::vector<std::string>& names, const uuid_vec_t& ids); +	void callbackAvatarCBBanned(const uuid_vec_t& ids); +	void callbackAvatarCBAccess(const uuid_vec_t& ids);  protected:  	LLNameListCtrl*		mListAccess; diff --git a/indra/newview/llfloaterpay.cpp b/indra/newview/llfloaterpay.cpp index ba7526ccd5..dc424720a7 100644 --- a/indra/newview/llfloaterpay.cpp +++ b/indra/newview/llfloaterpay.cpp @@ -47,6 +47,7 @@  #include "lllineeditor.h"  #include "llmutelist.h"  #include "llfloaterreporter.h" +#include "llslurl.h"  #include "llviewerobject.h"  #include "llviewerobjectlist.h"  #include "llviewerregion.h" @@ -102,10 +103,6 @@ private:  	static void onGive(void* data);  	void give(S32 amount);  	static void processPayPriceReply(LLMessageSystem* msg, void **userdata); -	void onCacheOwnerName(const LLUUID& owner_id, -						  const std::string& firstname, -						  const std::string& lastname, -						  BOOL is_group);  	void finishPayUI(const LLUUID& target_id, BOOL is_group);  protected: @@ -430,33 +427,26 @@ void LLFloaterPay::payDirectly(money_callback callback,  void LLFloaterPay::finishPayUI(const LLUUID& target_id, BOOL is_group)  { -	gCacheName->get(target_id, is_group, boost::bind(&LLFloaterPay::onCacheOwnerName, this, _1, _2, _3, _4)); - -	// Make sure the amount field has focus - -	childSetFocus("amount", TRUE); -	 -	LLLineEditor* amount = getChild<LLLineEditor>("amount"); -	amount->selectAll(); -	mTargetIsGroup = is_group; -} - -void LLFloaterPay::onCacheOwnerName(const LLUUID& owner_id, -									const std::string& firstname, -									const std::string& lastname, -									BOOL is_group) -{ +	std::string slurl;  	if (is_group)  	{  		setTitle(getString("payee_group")); +		slurl = LLSLURL("group", target_id, "inspect").getSLURLString();  	}  	else  	{  		setTitle(getString("payee_resident")); +		slurl = LLSLURL("agent", target_id, "inspect").getSLURLString();  	} +	childSetText("payee_name", slurl); -	childSetTextArg("payee_name", "[FIRST]", firstname); -	childSetTextArg("payee_name", "[LAST]", lastname); +	// Make sure the amount field has focus + +	childSetFocus("amount", TRUE); +	 +	LLLineEditor* amount = getChild<LLLineEditor>("amount"); +	amount->selectAll(); +	mTargetIsGroup = is_group;  }  // static diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 3ce1b46a4c..69e81ce157 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -82,6 +82,7 @@  #include "llvosky.h"  // linden library includes +#include "llavatarnamecache.h"  #include "llerror.h"  #include "llfontgl.h"  #include "llrect.h" @@ -185,6 +186,8 @@ void LLVoiceSetKeyDialog::onCancel(void* user_data)  // if creating/destroying these is too slow, we'll need to create  // a static member and update all our static callbacks +void handleNameTagOptionChanged(const LLSD& newvalue);	 +void handleDisplayNamesOptionChanged(const LLSD& newvalue);	  bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response);  //bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater); @@ -220,6 +223,18 @@ bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response  	return false;  } +void handleNameTagOptionChanged(const LLSD& newvalue) +{ +	LLVOAvatar::invalidateNameTags(); +} + +void handleDisplayNamesOptionChanged(const LLSD& newvalue) +{ +	LLAvatarNameCache::setUseDisplayNames(newvalue.asBoolean()); +	LLVOAvatar::invalidateNameTags(); +} + +  /*bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater)  {  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -313,6 +328,10 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)  	mCommitCallbackRegistrar.add("Pref.BlockList",				boost::bind(&LLFloaterPreference::onClickBlockList, this));  	sSkin = gSavedSettings.getString("SkinCurrent"); +	 +	gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	 +	gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged,  _2));	 +	gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged,  _2));  }  BOOL LLFloaterPreference::postBuild() diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 8c219cb3fd..590e14a362 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -49,6 +49,7 @@  #include "llagent.h"  #include "llappviewer.h" +#include "llavatarname.h"  #include "llfloateravatarpicker.h"  #include "llbutton.h"   #include "llcheckboxctrl.h" @@ -606,13 +607,13 @@ void LLPanelRegionGeneralInfo::onClickKick()  	// this depends on the grandparent view being a floater  	// in order to set up floater dependency  	LLFloater* parent_floater = gFloaterView->getParentFloater(this); -	LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelRegionGeneralInfo::onKickCommit, this, _1,_2), FALSE, TRUE); +	LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelRegionGeneralInfo::onKickCommit, this, _1), FALSE, TRUE);  	parent_floater->addDependentFloater(child_floater);  } -void LLPanelRegionGeneralInfo::onKickCommit(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLPanelRegionGeneralInfo::onKickCommit(const uuid_vec_t& ids)  { -	if (names.empty() || ids.empty()) return; +	if (ids.empty()) return;  	if(ids[0].notNull())  	{  		strings_t strings; @@ -848,11 +849,11 @@ void LLPanelRegionDebugInfo::onClickChooseAvatar()  } -void LLPanelRegionDebugInfo::callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLPanelRegionDebugInfo::callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)  {  	if (ids.empty() || names.empty()) return;  	mTargetAvatar = ids[0]; -	childSetValue("target_avatar_name", LLSD(names[0])); +	childSetValue("target_avatar_name", names[0].getCompleteName());  	refreshFromRegion( gAgent.getRegion() );  } @@ -1527,24 +1528,17 @@ void LLPanelEstateInfo::onClickKickUser()  	// this depends on the grandparent view being a floater  	// in order to set up floater dependency  	LLFloater* parent_floater = gFloaterView->getParentFloater(this); -	LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::onKickUserCommit, this, _1, _2), FALSE, TRUE); +	LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::onKickUserCommit, this, _1), FALSE, TRUE);  	parent_floater->addDependentFloater(child_floater);  } -void LLPanelEstateInfo::onKickUserCommit(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLPanelEstateInfo::onKickUserCommit(const uuid_vec_t& ids)  { -	if (names.empty() || ids.empty()) return; +	if (ids.empty()) return; -	//check to make sure there is one valid user and id -	if( (ids[0].isNull()) || -		(names[0].length() == 0) ) -	{ -		return; -	} -  	//Bring up a confirmation dialog  	LLSD args; -	args["EVIL_USER"] = names[0]; +	args["EVIL_USER"] = LLSLURL("agent", ids[0], "completename").getSLURLString();  	LLSD payload;  	payload["agent_id"] = ids[0];  	LLNotificationsUtil::add("EstateKickUser", args, payload, boost::bind(&LLPanelEstateInfo::kickUserConfirm, this, _1, _2)); @@ -1710,12 +1704,12 @@ bool LLPanelEstateInfo::accessAddCore2(const LLSD& notification, const LLSD& res  	LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]);  	// avatar picker yes multi-select, yes close-on-select -	LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::accessAddCore3, _1, _2, (void*)change_info), TRUE, TRUE); +	LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::accessAddCore3, _1, (void*)change_info), TRUE, TRUE);  	return false;  }  // static -void LLPanelEstateInfo::accessAddCore3(const std::vector<std::string>& names, const uuid_vec_t& ids, void* data) +void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, void* data)  {  	LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data;  	if (!change_info) return; @@ -1971,8 +1965,15 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region)  	childSetEnabled("remove_allowed_avatar_btn",	god || owner || manager);  	childSetEnabled("add_allowed_group_btn",		god || owner || manager);  	childSetEnabled("remove_allowed_group_btn",		god || owner || manager); -	childSetEnabled("add_banned_avatar_btn",		god || owner || manager); -	childSetEnabled("remove_banned_avatar_btn",		god || owner || manager); + +	// Can't ban people from mainland, orientation islands, etc. because this +	// creates much network traffic and server load. +	// Disable their accounts in CSR tool instead. +	bool linden_estate = (getEstateID() <= ESTATE_LAST_LINDEN); +	bool enable_ban = (god || owner || manager) && !linden_estate; +	childSetEnabled("add_banned_avatar_btn",		enable_ban); +	childSetEnabled("remove_banned_avatar_btn",		enable_ban); +  	childSetEnabled("message_estate_btn",			god || owner || manager);  	childSetEnabled("kick_user_from_estate_btn",	god || owner || manager); diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 482ebb3303..13c2e46639 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -40,6 +40,7 @@  #include "llhost.h"  #include "llpanel.h" +class LLAvatarName;  class LLDispatcher;  class LLLineEditor;  class LLMessageSystem; @@ -168,7 +169,7 @@ public:  protected:  	virtual BOOL sendUpdate();  	void onClickKick(); -	void onKickCommit(const std::vector<std::string>& names, const uuid_vec_t& ids); +	void onKickCommit(const uuid_vec_t& ids);  	static void onClickKickAll(void* userdata);  	bool onKickAllCommit(const LLSD& notification, const LLSD& response);  	static void onClickMessage(void* userdata); @@ -193,7 +194,7 @@ protected:  	virtual BOOL sendUpdate();  	void onClickChooseAvatar(); -	void callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids); +	void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);  	static void onClickReturn(void *);  	bool callbackReturn(const LLSD& notification, const LLSD& response);  	static void onClickTopColliders(void*); @@ -284,7 +285,7 @@ public:  	// Core methods for all above add/remove button clicks  	static void accessAddCore(U32 operation_flag, const std::string& dialog_name);  	static bool accessAddCore2(const LLSD& notification, const LLSD& response); -	static void accessAddCore3(const std::vector<std::string>& names, const uuid_vec_t& ids, void* data); +	static void accessAddCore3(const uuid_vec_t& ids, void* data);  	static void accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name);  	static bool accessRemoveCore2(const LLSD& notification, const LLSD& response); @@ -296,7 +297,7 @@ public:  	// Send the actual EstateOwnerRequest "estateaccessdelta" message  	static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id); -	void onKickUserCommit(const std::vector<std::string>& names, const uuid_vec_t& ids); +	void onKickUserCommit(const uuid_vec_t& ids);  	static void onClickMessageEstate(void* data);  	bool onMessageCommit(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index f7c8855bf6..195b3e22d9 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -39,6 +39,8 @@  // linden library includes  #include "llassetstorage.h" +#include "llavatarnamecache.h" +#include "llcachename.h"  #include "llfontgl.h"  #include "llimagej2c.h"  #include "llinventory.h" @@ -182,9 +184,8 @@ BOOL LLFloaterReporter::postBuild()  	childSetAction("cancel_btn", onClickCancel, this);  	// grab the user's name -	std::string fullname; -	LLAgentUI::buildFullname(fullname); -	childSetText("reporter_field", fullname); +	std::string reporter = LLSLURL("agent", gAgent.getID(), "inspect").getSLURLString(); +	childSetText("reporter_field", reporter);  	center(); @@ -267,22 +268,7 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)  			if (objectp->isAvatar())  			{ -				// we have the information we need -				std::string object_owner; - -				LLNameValue* firstname = objectp->getNVPair("FirstName"); -				LLNameValue* lastname =  objectp->getNVPair("LastName"); -				if (firstname && lastname) -				{ -					object_owner.append(firstname->getString()); -					object_owner.append(1, ' '); -					object_owner.append(lastname->getString()); -				} -				else -				{ -					object_owner.append("Unknown"); -				} -				setFromAvatar(mObjectID, object_owner); +				setFromAvatarID(mObjectID);  			}  			else  			{ @@ -309,11 +295,11 @@ void LLFloaterReporter::onClickSelectAbuser()  	gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterReporter::callbackAvatarID, this, _1, _2), FALSE, TRUE ));  } -void LLFloaterReporter::callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)  {  	if (ids.empty() || names.empty()) return; -	childSetText("abuser_name_edit", names[0] ); +	childSetText("abuser_name_edit", names[0].getCompleteName());  	mAbuserID = ids[0]; @@ -321,18 +307,27 @@ void LLFloaterReporter::callbackAvatarID(const std::vector<std::string>& names,  } -void LLFloaterReporter::setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name) +void LLFloaterReporter::setFromAvatarID(const LLUUID& avatar_id)  {  	mAbuserID = mObjectID = avatar_id; -	mOwnerName = avatar_name; - -	std::string avatar_link = -	  LLSLURL("agent", mObjectID, "inspect").getSLURLString(); +	std::string avatar_link = LLSLURL("agent", mObjectID, "inspect").getSLURLString();  	childSetText("owner_name", avatar_link); -	childSetText("object_name", avatar_name); -	childSetText("abuser_name_edit", avatar_name); + +	LLAvatarNameCache::get(avatar_id, boost::bind(&LLFloaterReporter::onAvatarNameCache, this, _1, _2));  } +void LLFloaterReporter::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name) +{ +	if (mObjectID == avatar_id) +	{ +		mOwnerName = av_name.getCompleteName(); +		childSetText("object_name", av_name.getCompleteName()); +		childSetToolTip("object_name", av_name.getCompleteName()); +		childSetText("abuser_name_edit", av_name.getCompleteName()); +	} +} + +  // static  void LLFloaterReporter::onClickSend(void *userdata)  { @@ -472,16 +467,11 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_  {  	LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter"); -	// grab the user's name -	std::string fullname; -	LLAgentUI::buildFullname(fullname); -	f->childSetText("reporter_field", fullname); -  	if (avatar_name.empty())  		// Request info for this object  		f->getObjectInfo(object_id);  	else -		f->setFromAvatar(object_id, avatar_name); +		f->setFromAvatarID(object_id);  	// Need to deselect on close  	f->mDeselectOnClose = TRUE; diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index 23784b7650..1f8526b1de 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -38,6 +38,7 @@  #include "lluuid.h"  #include "v3math.h" +class LLAvatarName;  class LLMessageSystem;  class LLViewerTexture;  class LLInventoryItem; @@ -123,8 +124,9 @@ private:  	void setPosBox(const LLVector3d &pos);  	void enableControls(BOOL own_avatar);  	void getObjectInfo(const LLUUID& object_id); -	void callbackAvatarID(const std::vector<std::string>& names, const uuid_vec_t& ids); -	void setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name = LLStringUtil::null); +	void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names); +	void setFromAvatarID(const LLUUID& avatar_id); +	void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name);  private:  	EReportType		mReportType; diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 0a5499b166..775dda568f 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -34,6 +34,8 @@  #include "llviewerprecompiledheaders.h"  #include "llfloaterscriptlimits.h" +// library includes +#include "llavatarnamecache.h"  #include "llsdutil.h"  #include "llsdutil_math.h"  #include "message.h" @@ -295,7 +297,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");  		if(tab)  		{ -			LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); +		LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");  			if(panel_memory)  			{  				panel_memory->childSetValue("loading_text", LLSD(std::string(""))); @@ -306,9 +308,9 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)  					btn->setEnabled(true);  				} -				panel_memory->setRegionSummary(content); -			} -		} +		panel_memory->setRegionSummary(content); +	} +}  	}  } @@ -598,17 +600,24 @@ void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::stri  // callback from the name cache with an owner name to add to the list  void LLPanelScriptLimitsRegionMemory::onNameCache(  						 const LLUUID& id, -						 const std::string& first_name, -						 const std::string& last_name) +						 const std::string& full_name)  { -	std::string name = first_name + " " + last_name; -  	LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");	  	if(!list)  	{  		return;  	} +	std::string name; +	if (LLAvatarNameCache::useDisplayNames()) +	{ +		name = LLCacheName::buildUsername(full_name); +	} +	else +	{ +		name = full_name; +	} +  	std::vector<LLSD>::iterator id_itor;  	for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor)  	{ @@ -674,6 +683,9 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)  			std::string name_buf = content["parcels"][i]["objects"][j]["name"].asString();  			LLUUID task_id = content["parcels"][i]["objects"][j]["id"].asUUID();  			LLUUID owner_id = content["parcels"][i]["objects"][j]["owner_id"].asUUID(); +			// This field may not be sent by all server versions, but it's OK if +			// it uses the LLSD default of false +			bool is_group_owned = content["parcels"][i]["objects"][j]["is_group_owned"].asBoolean();  			F32 location_x = 0.0f;  			F32 location_y = 0.0f; @@ -699,15 +711,27 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)  			// ...and if not use the slightly more painful method of disovery:  			else  			{ -				BOOL name_is_cached = gCacheName->getFullName(owner_id, owner_buf); +				BOOL name_is_cached; +				if (is_group_owned) +				{ +					name_is_cached = gCacheName->getGroupName(owner_id, owner_buf); +				} +				else +				{ +					name_is_cached = gCacheName->getFullName(owner_id, owner_buf);  // username +					if (LLAvatarNameCache::useDisplayNames()) +					{ +						owner_buf = LLCacheName::buildUsername(owner_buf); +					} +				}  				if(!name_is_cached)  				{  					if(std::find(names_requested.begin(), names_requested.end(), owner_id) == names_requested.end())  					{  						names_requested.push_back(owner_id); -						gCacheName->get(owner_id, TRUE, -						boost::bind(&LLPanelScriptLimitsRegionMemory::onNameCache, -							this, _1, _2, _3)); +						gCacheName->get(owner_id, is_group_owned,  // username +							boost::bind(&LLPanelScriptLimitsRegionMemory::onNameCache, +							    this, _1, _2));  					}  				}  			} @@ -1309,7 +1333,7 @@ void LLPanelScriptLimitsAttachment::setAttachmentSummary(LLSD content)  // static  void LLPanelScriptLimitsAttachment::onClickRefresh(void* userdata) -{	 +{  	LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");  	if(instance)  	{ diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index 3c32b9f701..ba6f930bee 100644 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -170,10 +170,8 @@ public:  	void returnObjects();  private: -  	void onNameCache(const LLUUID& id, -			 const std::string& first_name, -			 const std::string& last_name); +						 const std::string& name);  	LLSD mContent;  	LLUUID mParcelId; diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 9dddbd998a..186debe40e 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -33,6 +33,7 @@  #include "llfloatersellland.h" +#include "llavatarnamecache.h"  #include "llfloateravatarpicker.h"  #include "llfloaterreg.h"  #include "llfloaterland.h" @@ -47,6 +48,8 @@  #include "lluictrlfactory.h"  #include "llviewerwindow.h" +class LLAvatarName; +  // defined in llfloaterland.cpp  void send_parcel_select_objects(S32 parcel_local_id, U32 return_type,  								uuid_list_t* return_ids = NULL); @@ -95,7 +98,9 @@ private:  	bool onConfirmSale(const LLSD& notification, const LLSD& response);  	static void doShowObjects(void *userdata); -	void callbackAvatarPick(const std::vector<std::string>& names, const uuid_vec_t& ids); +	void callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names); + +	void onBuyerNameCache(const LLAvatarName& av_name);  public:  	virtual BOOL postBuild(); @@ -230,12 +235,17 @@ void LLFloaterSellLandUI::updateParcelInfo()  	if(mSellToBuyer)  	{ -		std::string name; -		gCacheName->getFullName(mAuthorizedBuyer, name); -		childSetText("sell_to_agent", name); +		LLAvatarNameCache::get(mAuthorizedBuyer,  +			boost::bind(&LLFloaterSellLandUI::onBuyerNameCache, this, _2));  	}  } +void LLFloaterSellLandUI::onBuyerNameCache(const LLAvatarName& av_name) +{ +	childSetText("sell_to_agent", av_name.getCompleteName()); +	childSetToolTip("sell_to_agent", av_name.mUsername); +} +  void LLFloaterSellLandUI::setBadge(const char* id, Badge badge)  {  	static std::string badgeOK("badge_ok.j2c"); @@ -391,7 +401,7 @@ void LLFloaterSellLandUI::doSelectAgent()  	addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterSellLandUI::callbackAvatarPick, this, _1, _2), FALSE, TRUE));  } -void LLFloaterSellLandUI::callbackAvatarPick(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLFloaterSellLandUI::callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)  {	  	LLParcel* parcel = mParcelSelection->getParcel(); @@ -402,7 +412,7 @@ void LLFloaterSellLandUI::callbackAvatarPick(const std::vector<std::string>& nam  	mAuthorizedBuyer = ids[0]; -	childSetText("sell_to_agent", names[0]); +	childSetText("sell_to_agent", names[0].getCompleteName());  	refreshUI();  } diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index 84ea353dab..c7c3c2f7da 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -34,7 +34,9 @@  #include "llfloatertopobjects.h" +// library includes  #include "message.h" +#include "llavatarnamecache.h"  #include "llfontgl.h"  #include "llagent.h" @@ -196,37 +198,53 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data)  		LLSD element;  		element["id"] = task_id; -		element["object_name"] = name_buf; -		element["owner_name"] = owner_buf; -		element["columns"][0]["column"] = "score"; -		element["columns"][0]["value"] = llformat("%0.3f", score); -		element["columns"][0]["font"] = "SANSSERIF"; + +		LLSD columns; +		columns[0]["column"] = "score"; +		columns[0]["value"] = llformat("%0.3f", score); +		columns[0]["font"] = "SANSSERIF"; +		 +		columns[1]["column"] = "name"; +		columns[1]["value"] = name_buf; +		columns[1]["font"] = "SANSSERIF"; +		 +		// Owner names can have trailing spaces sent from server +		LLStringUtil::trim(owner_buf); -		element["columns"][1]["column"] = "name"; -		element["columns"][1]["value"] = name_buf; -		element["columns"][1]["font"] = "SANSSERIF"; -		element["columns"][2]["column"] = "owner"; -		element["columns"][2]["value"] = owner_buf; -		element["columns"][2]["font"] = "SANSSERIF"; -		element["columns"][3]["column"] = "location"; -		element["columns"][3]["value"] = llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z); -		element["columns"][3]["font"] = "SANSSERIF"; -		element["columns"][4]["column"] = "time"; -		element["columns"][4]["value"] = formatted_time((time_t)time_stamp); -		element["columns"][4]["font"] = "SANSSERIF"; +		if (LLAvatarNameCache::useDisplayNames()) +		{ +			// ...convert hard-coded name from server to a username +			// *TODO: Send owner_id from server and look up display name +			owner_buf = LLCacheName::buildUsername(owner_buf); +		} +		else +		{ +			// ...just strip out legacy "Resident" name +			owner_buf = LLCacheName::cleanFullName(owner_buf); +		} +		columns[2]["column"] = "owner"; +		columns[2]["value"] = owner_buf; +		columns[2]["font"] = "SANSSERIF"; + +		columns[3]["column"] = "location"; +		columns[3]["value"] = llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z); +		columns[3]["font"] = "SANSSERIF"; +		columns[4]["column"] = "time"; +		columns[4]["value"] = formatted_time((time_t)time_stamp); +		columns[4]["font"] = "SANSSERIF";  		if (mCurrentMode == STAT_REPORT_TOP_SCRIPTS  			&& have_extended_data)  		{ -			element["columns"][5]["column"] = "mono_time"; -			element["columns"][5]["value"] = llformat("%0.3f", mono_score); -			element["columns"][5]["font"] = "SANSSERIF"; +			columns[5]["column"] = "mono_time"; +			columns[5]["value"] = llformat("%0.3f", mono_score); +			columns[5]["font"] = "SANSSERIF"; -			element["columns"][6]["column"] = "URLs"; -			element["columns"][6]["value"] = llformat("%d", public_urls); -			element["columns"][6]["font"] = "SANSSERIF"; +			columns[6]["column"] = "URLs"; +			columns[6]["value"] = llformat("%d", public_urls); +			columns[6]["font"] = "SANSSERIF";  		} -		 +		element["columns"] = columns;  		list->addElement(element);  		mObjectListData.append(element); diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index f1d39a41ae..3bc64a3712 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -121,7 +121,7 @@ public:  	const std::string getFilterSubString(BOOL trim = FALSE);  	U32 getFilterObjectTypes() const;  	PermissionMask getFilterPermissions() const; -	// JAMESDEBUG use getFilter()->getShowFolderState(); +	// *NOTE: use getFilter()->getShowFolderState();  	//LLInventoryFilter::EFolderShow getShowFolderState();  	U32 getSortOrder() const;  	BOOL isFilterModified(); diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index 82f8a10cf3..d672978f46 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -31,7 +31,7 @@  #ifndef LLFOLDERVIEWEVENTLISTENER_H  #define LLFOLDERVIEWEVENTLISTENER_H -#include "lldarray.h"	// JAMESDEBUG convert to std::vector +#include "lldarray.h"	// *TODO: convert to std::vector  #include "llfoldertype.h"  #include "llfontgl.h"	// just for StyleFlags enum  #include "llinventorytype.h" diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index d6e4b2f556..b0fbcfd138 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -57,7 +57,7 @@ enum EInventorySortGroup  	SG_ITEM   }; -// JAMESDEBUG *TODO: do we really need one sort object per folder? +// *TODO: do we really need one sort object per folder?  // can we just have one of these per LLFolderView ?  class LLInventorySort  { diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index 7f28e09933..0a1b0b5df0 100644 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -32,13 +32,14 @@  #include "llviewerprecompiledheaders.h" +#include "llfriendcard.h" + +#include "llavatarnamecache.h"  #include "llinventory.h"  #include "llinventoryfunctions.h"  #include "llinventoryobserver.h"  #include "lltrans.h" -#include "llfriendcard.h" -  #include "llcallingcard.h" // for LLAvatarTracker  #include "llviewerinventory.h"  #include "llinventorymodel.h" @@ -536,8 +537,9 @@ void LLFriendCardsManager::addFriendCardToInventory(const LLUUID& avatarID)  {  	bool shouldBeAdded = true; -	std::string name; -	gCacheName->getFullName(avatarID, name); +	LLAvatarName av_name; +	LLAvatarNameCache::get(avatarID, &av_name); +	const std::string& name = av_name.mUsername;  	lldebugs << "Processing buddy name: " << name   		<< ", id: " << avatarID diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 2aba0b5c09..eec08301a8 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -54,6 +54,7 @@  #include "lltoolmgr.h"  #include "llselectmgr.h"  #include "llhudmanager.h" +#include "llhudtext.h"  #include "llrendersphere.h"  #include "llviewerobjectlist.h"  #include "lltoolselectrect.h" @@ -894,7 +895,7 @@ void LLViewerObjectList::renderObjectBeacons()  			color = debug_beacon.mTextColor;  			color.mV[3] *= 1.f; -			hud_textp->setString(utf8str_to_wstring(debug_beacon.mString)); +			hud_textp->setString(debug_beacon.mString);  			hud_textp->setColor(color);  			hud_textp->setPositionAgent(debug_beacon.mPositionAgent);  			debug_beacon.mHUDObject = hud_textp; diff --git a/indra/newview/llhudicon.h b/indra/newview/llhudicon.h index 770e3bbcd0..91b3a64250 100644 --- a/indra/newview/llhudicon.h +++ b/indra/newview/llhudicon.h @@ -50,6 +50,7 @@  // Renders a 2D icon billboard floating at the location specified.  class LLDrawable;  class LLViewerObject; +class LLViewerTexture;  class LLHUDIcon : public LLHUDObject  { diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp new file mode 100644 index 0000000000..303f048dfc --- /dev/null +++ b/indra/newview/llhudnametag.cpp @@ -0,0 +1,1072 @@ +/**  + * @file llhudnametag.cpp + * @brief Name tags for avatars + * @author James Cook + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llhudnametag.h" + +#include "llrender.h" + +#include "llagent.h" +#include "llviewercontrol.h" +#include "llcriticaldamp.h" +#include "lldrawable.h" +#include "llfontgl.h" +#include "llglheaders.h" +#include "llhudrender.h" +#include "llui.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewerobject.h" +#include "llvovolume.h" +#include "llviewerwindow.h" +#include "llstatusbar.h" +#include "llmenugl.h" +#include "pipeline.h" +#include <boost/tokenizer.hpp> + + +const F32 SPRING_STRENGTH = 0.7f; +const F32 RESTORATION_SPRING_TIME_CONSTANT = 0.1f; +const F32 HORIZONTAL_PADDING = 16.f; +const F32 VERTICAL_PADDING = 12.f; +const F32 LINE_PADDING = 3.f;			// aka "leading" +const F32 BUFFER_SIZE = 2.f; +const F32 MIN_EDGE_OVERLAP = 3.f; +const F32 HUD_TEXT_MAX_WIDTH = 190.f; +const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f; +const F32 RESIZE_TIME = 0.f; +const S32 NUM_OVERLAP_ITERATIONS = 10; +const F32 NEIGHBOR_FORCE_FRACTION = 1.f; +const F32 POSITION_DAMPING_TC = 0.2f; +const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f; +const F32 LOD_0_SCREEN_COVERAGE = 0.15f; +const F32 LOD_1_SCREEN_COVERAGE = 0.30f; +const F32 LOD_2_SCREEN_COVERAGE = 0.40f; + +std::set<LLPointer<LLHUDNameTag> > LLHUDNameTag::sTextObjects; +std::vector<LLPointer<LLHUDNameTag> > LLHUDNameTag::sVisibleTextObjects; +BOOL LLHUDNameTag::sDisplayText = TRUE ; + +bool llhudnametag_further_away::operator()(const LLPointer<LLHUDNameTag>& lhs, const LLPointer<LLHUDNameTag>& rhs) const +{ +	return lhs->getDistance() > rhs->getDistance(); +} + + +LLHUDNameTag::LLHUDNameTag(const U8 type) +:	LLHUDObject(type), +	mDoFade(TRUE), +	mFadeDistance(8.f), +	mFadeRange(4.f), +	mLastDistance(0.f), +	mZCompare(TRUE), +	mVisibleOffScreen(FALSE), +	mOffscreen(FALSE), +	mColor(1.f, 1.f, 1.f, 1.f), +//	mScale(), +	mWidth(0.f), +	mHeight(0.f), +	mFontp(LLFontGL::getFontSansSerifSmall()), +	mBoldFontp(LLFontGL::getFontSansSerifBold()), +	mSoftScreenRect(), +	mPositionAgent(), +	mPositionOffset(), +	mMass(10.f), +	mMaxLines(10), +	mOffsetY(0), +	mRadius(0.1f), +	mTextSegments(), +	mLabelSegments(), +	mTextAlignment(ALIGN_TEXT_CENTER), +	mVertAlignment(ALIGN_VERT_CENTER), +	mLOD(0), +	mHidden(FALSE) +{ +	LLPointer<LLHUDNameTag> ptr(this); +	sTextObjects.insert(ptr); +} + +LLHUDNameTag::~LLHUDNameTag() +{ +} + + +BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render) +{ +	if (!mVisible || mHidden) +	{ +		return FALSE; +	} + +	// don't pick text that isn't bound to a viewerobject +	if (!mSourceObject || mSourceObject->mDrawable.isNull()) +	{ +		return FALSE; +	} +	 +	F32 alpha_factor = 1.f; +	LLColor4 text_color = mColor; +	if (mDoFade) +	{ +		if (mLastDistance > mFadeDistance) +		{ +			alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange); +			text_color.mV[3] = text_color.mV[3]*alpha_factor; +		} +	} +	if (text_color.mV[3] < 0.01f) +	{ +		return FALSE; +	} + +	mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); + +	// scale screen size of borders down +	//RN: for now, text on hud objects is never occluded + +	LLVector3 x_pixel_vec; +	LLVector3 y_pixel_vec; +	 +	LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); + +	LLVector3 width_vec = mWidth * x_pixel_vec; +	LLVector3 height_vec = mHeight * y_pixel_vec; +	 +	LLCoordGL screen_pos; +	LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE); + +	LLVector2 screen_offset; +	screen_offset = updateScreenPos(mPositionOffset); +	 +	LLVector3 render_position = mPositionAgent   +			+ (x_pixel_vec * screen_offset.mV[VX]) +			+ (y_pixel_vec * screen_offset.mV[VY]); + + +	//if (mUseBubble) +	{ +		LLVector3 bg_pos = render_position +			+ (F32)mOffsetY * y_pixel_vec +			- (width_vec / 2.f) +			- (height_vec); +		//LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]); + +		LLVector3 v[] =  +		{ +			bg_pos, +			bg_pos + width_vec, +			bg_pos + width_vec + height_vec, +			bg_pos + height_vec, +		}; + +		if (debug_render) +		{ +			gGL.begin(LLRender::LINE_STRIP); +			gGL.vertex3fv(v[0].mV); +			gGL.vertex3fv(v[1].mV); +			gGL.vertex3fv(v[2].mV); +			gGL.vertex3fv(v[3].mV); +			gGL.vertex3fv(v[0].mV); +			gGL.vertex3fv(v[2].mV); +			gGL.end(); +		} + +		LLVector3 dir = end-start; +		F32 t = 0.f; + +		if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) || +			LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) ) +		{ +			if (t <= 1.f) +			{ +				intersection = start + dir*t; +				return TRUE; +			} +		} +	} + +	return FALSE; +} + +void LLHUDNameTag::render() +{ +	if (sDisplayText) +	{ +		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); +		renderText(FALSE); +	} +} + +void LLHUDNameTag::renderForSelect() +{ +	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); +	renderText(TRUE); +} + +void LLHUDNameTag::renderText(BOOL for_select) +{ +	if (!mVisible || mHidden) +	{ +		return; +	} + +	// don't pick text that isn't bound to a viewerobject +	if (for_select &&  +		(!mSourceObject || mSourceObject->mDrawable.isNull())) +	{ +		return; +	} +	 +	if (for_select) +	{ +		gGL.getTexUnit(0)->disable(); +	} +	else +	{ +		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); +	} + +	LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE); +	LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE); +	 +	LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f); +	F32 alpha_factor = 1.f; +	LLColor4 text_color = mColor; +	if (mDoFade) +	{ +		if (mLastDistance > mFadeDistance) +		{ +			alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange); +			text_color.mV[3] = text_color.mV[3]*alpha_factor; +		} +	} +	if (text_color.mV[3] < 0.01f) +	{ +		return; +	} +	shadow_color.mV[3] = text_color.mV[3]; + +	mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); + +	// *TODO: cache this image +	LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Rect"); + +	// *TODO: make this a per-text setting +	LLColor4 bg_color = LLUIColorTable::instance().getColor("NameTagBackground"); +	bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); + +	// maybe a no-op? +	//const S32 border_height = 16; +	//const S32 border_width = 16; +	const S32 border_height = 8; +	const S32 border_width = 8; + +	// *TODO move this into helper function +	F32 border_scale = 1.f; + +	if (border_height * 2 > mHeight) +	{ +		border_scale = (F32)mHeight / ((F32)border_height * 2.f); +	} +	if (border_width * 2 > mWidth) +	{ +		border_scale = llmin(border_scale, (F32)mWidth / ((F32)border_width * 2.f)); +	} + +	// scale screen size of borders down +	//RN: for now, text on hud objects is never occluded + +	LLVector3 x_pixel_vec; +	LLVector3 y_pixel_vec; +	 +	LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); + +	LLVector2 border_scale_vec((F32)border_width / (F32)imagep->getTextureWidth(), (F32)border_height / (F32)imagep->getTextureHeight()); +	LLVector3 width_vec = mWidth * x_pixel_vec; +	LLVector3 height_vec = mHeight * y_pixel_vec; +	LLVector3 scaled_border_width = (F32)llfloor(border_scale * (F32)border_width) * x_pixel_vec; +	LLVector3 scaled_border_height = (F32)llfloor(border_scale * (F32)border_height) * y_pixel_vec; + +	mRadius = (width_vec + height_vec).magVec() * 0.5f; + +	LLCoordGL screen_pos; +	LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE); + +	LLVector2 screen_offset; +//	if (!mUseBubble) +//	{ +//		screen_offset = mPositionOffset; +//	} +//	else +//	{ +		screen_offset = updateScreenPos(mPositionOffset); +//	} + +	LLVector3 render_position = mPositionAgent   +			+ (x_pixel_vec * screen_offset.mV[VX]) +			+ (y_pixel_vec * screen_offset.mV[VY]); + +//	if (mUseBubble) +	{ +		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); +		LLUI::pushMatrix(); +		{ +			LLVector3 bg_pos = render_position +				+ (F32)mOffsetY * y_pixel_vec +				- (width_vec / 2.f) +				- (height_vec); +			LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]); + +			if (for_select) +			{ +				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +				S32 name = mSourceObject->mGLName; +				LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name); +				gGL.color4ubv(coloru.mV); +				gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec); +				LLUI::popMatrix(); +				return; +			} +			else +			{ +				gGL.getTexUnit(0)->bind(imagep->getImage()); +				 +				gGL.color4fv(bg_color.mV); +				gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec); +		 +				if ( mLabelSegments.size()) +				{ +					LLUI::pushMatrix(); +					{ +						gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); +						LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec; +						LLVector3 label_offset = height_vec - label_height; +						LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]); +						gl_segmented_rect_3d_tex_top(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, label_height); +					} +					LLUI::popMatrix(); +				} +			} + +			BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f; +			BOOL outside_height = llabs(mPositionOffset.mV[VY] + (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.5f : 0.f)) > mHeight * (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.75f : 0.5f); + +			// draw line segments pointing to parent object +			if (!mOffscreen && (outside_width || outside_height)) +			{ +				LLUI::pushMatrix(); +				{ +					gGL.color4fv(bg_color.mV); +					LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec); +					target_pos += (width_vec / 2.f); +					target_pos += mVertAlignment == ALIGN_VERT_CENTER ? (height_vec * 0.5f) : LLVector3::zero; +					target_pos -= 3.f * x_pixel_vec; +					target_pos -= 6.f * y_pixel_vec; +					LLUI::translate(target_pos.mV[VX], target_pos.mV[VY], target_pos.mV[VZ]); +					gl_segmented_rect_3d_tex(border_scale_vec, 3.f * x_pixel_vec, 3.f * y_pixel_vec, 6.f * x_pixel_vec, 6.f * y_pixel_vec);	 +				} +				LLUI::popMatrix(); + +				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +				LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE); +				 +				LLVector3 box_center_offset; +				box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f); +				LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]); +				gGL.color4fv(bg_color.mV); +				LLUI::setLineWidth(2.0); +				gGL.begin(LLRender::LINES); +				{ +					if (outside_width) +					{ +						LLVector3 vert; +						// draw line in x then y +						if (mPositionOffset.mV[VX] < 0.f) +						{ +							// start at right edge +							vert = width_vec * 0.5f; +							gGL.vertex3fv(vert.mV); +						} +						else +						{ +							// start at left edge +							vert = width_vec * -0.5f; +							gGL.vertex3fv(vert.mV); +						} +						vert = -mPositionOffset.mV[VX] * x_pixel_vec; +						gGL.vertex3fv(vert.mV); +						gGL.vertex3fv(vert.mV); +						vert -= mPositionOffset.mV[VY] * y_pixel_vec; +						vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); +						gGL.vertex3fv(vert.mV); +					} +					else +					{ +						LLVector3 vert; +						// draw line in y then x +						if (mPositionOffset.mV[VY] < 0.f) +						{ +							// start at top edge +							vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec); +							gGL.vertex3fv(vert.mV); +						} +						else +						{ +							// start at bottom edge +							vert = (height_vec * -0.5f)  - (mPositionOffset.mV[VX] * x_pixel_vec); +							gGL.vertex3fv(vert.mV); +						} +						vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec; +						vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); +						gGL.vertex3fv(vert.mV); +					} +				} +				gGL.end(); +				LLUI::setLineWidth(1.0); + +			} +		} +		LLUI::popMatrix(); +	} + +	F32 y_offset = (F32)mOffsetY; +		 +	// Render label +	{ +		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + +		for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin(); +			segment_iter != mLabelSegments.end(); ++segment_iter ) +		{ +			// Label segments use default font +			const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp; +			y_offset -= fontp->getLineHeight(); + +			F32 x_offset; +			if (mTextAlignment == ALIGN_TEXT_CENTER) +			{ +				x_offset = -0.5f*segment_iter->getWidth(fontp); +			} +			else // ALIGN_LEFT +			{ +				x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f); +			} + +			LLColor4 label_color(0.f, 0.f, 0.f, 1.f); +			label_color.mV[VALPHA] = alpha_factor; +			hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, FALSE); +		} +	} + +	// Render text +	{ +		// -1 mMaxLines means unlimited lines. +		S32 start_segment; +		S32 max_lines = getMaxLines(); + +		if (max_lines < 0)  +		{ +			start_segment = 0; +		} +		else  +		{ +			start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines); +		} + +		for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment; +			 segment_iter != mTextSegments.end(); ++segment_iter ) +		{ +			const LLFontGL* fontp = segment_iter->mFont; +			y_offset -= fontp->getLineHeight(); +			y_offset -= LINE_PADDING; + +			U8 style = segment_iter->mStyle; +			LLFontGL::ShadowType shadow = LLFontGL::DROP_SHADOW; +	 +			F32 x_offset; +			if (mTextAlignment== ALIGN_TEXT_CENTER) +			{ +				x_offset = -0.5f*segment_iter->getWidth(fontp); +			} +			else // ALIGN_LEFT +			{ +				x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f); + +				// *HACK +				x_offset += 1; +			} + +			text_color = segment_iter->mColor; +			text_color.mV[VALPHA] *= alpha_factor; + +			hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, FALSE); +		} +	} +	/// Reset the default color to white.  The renderer expects this to be the default.  +	gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f); +	if (for_select) +	{ +		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); +	} +} + +void LLHUDNameTag::setString(const std::string &text_utf8) +{ +	mTextSegments.clear(); +	addLine(text_utf8, mColor); +} + +void LLHUDNameTag::clearString() +{ +	mTextSegments.clear(); +} + + +void LLHUDNameTag::addLine(const std::string &text_utf8, +						const LLColor4& color, +						const LLFontGL::StyleFlags style, +						const LLFontGL* font) +{ +	LLWString wline = utf8str_to_wstring(text_utf8); +	if (!wline.empty()) +	{ +		// use default font for segment if custom font not specified +		if (!font) +		{ +			font = mFontp; +		} +		typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer; +		LLWString seps(utf8str_to_wstring("\r\n")); +		boost::char_separator<llwchar> sep(seps.c_str()); + +		tokenizer tokens(wline, sep); +		tokenizer::iterator iter = tokens.begin(); + +		while (iter != tokens.end()) +		{ +			U32 line_length = 0; +			do	 +			{ +				F32 max_pixels = HUD_TEXT_MAX_WIDTH; +				S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); +				LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font); +				mTextSegments.push_back(segment); +				line_length += segment_length; +			} +			while (line_length != iter->size()); +			++iter; +		} +	} +} + +void LLHUDNameTag::setLabel(const std::string &label_utf8) +{ +	mLabelSegments.clear(); +	addLabel(label_utf8); +} + +void LLHUDNameTag::addLabel(const std::string& label_utf8) +{ +	LLWString wstr = utf8string_to_wstring(label_utf8); +	if (!wstr.empty()) +	{ +		LLWString seps(utf8str_to_wstring("\r\n")); +		LLWString empty; + +		typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer; +		boost::char_separator<llwchar> sep(seps.c_str(), empty.c_str(), boost::keep_empty_tokens); + +		tokenizer tokens(wstr, sep); +		tokenizer::iterator iter = tokens.begin(); + +		while (iter != tokens.end()) +		{ +			U32 line_length = 0; +			do	 +			{ +				S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(),  +					HUD_TEXT_MAX_WIDTH, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); +				LLHUDTextSegment segment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor, mFontp); +				mLabelSegments.push_back(segment); +				line_length += segment_length; +			} +			while (line_length != iter->size()); +			++iter; +		} +	} +} + +void LLHUDNameTag::setZCompare(const BOOL zcompare) +{ +	mZCompare = zcompare; +} + +void LLHUDNameTag::setFont(const LLFontGL* font) +{ +	mFontp = font; +} + + +void LLHUDNameTag::setColor(const LLColor4 &color) +{ +	mColor = color; +	for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin(); +		 segment_iter != mTextSegments.end(); ++segment_iter ) +	{ +		segment_iter->mColor = color; +	} +} + +void LLHUDNameTag::setAlpha(F32 alpha) +{ +	mColor.mV[VALPHA] = alpha; +	for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin(); +		 segment_iter != mTextSegments.end(); ++segment_iter ) +	{ +		segment_iter->mColor.mV[VALPHA] = alpha; +	} +} + + +void LLHUDNameTag::setDoFade(const BOOL do_fade) +{ +	mDoFade = do_fade; +} + +void LLHUDNameTag::updateVisibility() +{ +	if (mSourceObject) +	{ +		mSourceObject->updateText(); +	} +	 +	mPositionAgent = gAgent.getPosAgentFromGlobal(mPositionGlobal); + +	if (!mSourceObject) +	{ +		//llwarns << "LLHUDNameTag::updateScreenPos -- mSourceObject is NULL!" << llendl; +		mVisible = TRUE; +		sVisibleTextObjects.push_back(LLPointer<LLHUDNameTag> (this)); +		return; +	} + +	// Not visible if parent object is dead +	if (mSourceObject->isDead()) +	{ +		mVisible = FALSE; +		return; +	} + +	// push text towards camera by radius of object, but not past camera +	LLVector3 vec_from_camera = mPositionAgent - LLViewerCamera::getInstance()->getOrigin(); +	LLVector3 dir_from_camera = vec_from_camera; +	dir_from_camera.normVec(); + +	if (dir_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= 0.f) +	{ //text is behind camera, don't render +		mVisible = FALSE; +		return; +	} +		 +	if (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis() <= LLViewerCamera::getInstance()->getNear() + 0.1f + mSourceObject->getVObjRadius()) +	{ +		mPositionAgent = LLViewerCamera::getInstance()->getOrigin() + vec_from_camera * ((LLViewerCamera::getInstance()->getNear() + 0.1f) / (vec_from_camera * LLViewerCamera::getInstance()->getAtAxis())); +	} +	else +	{ +		mPositionAgent -= dir_from_camera * mSourceObject->getVObjRadius(); +	} + +	mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec(); + +	if (mLOD >= 3 || !mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange))) +	{ +		mVisible = FALSE; +		return; +	} + +	LLVector3 x_pixel_vec; +	LLVector3 y_pixel_vec; + +	LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); + +	LLVector3 render_position = mPositionAgent + 			 +			(x_pixel_vec * mPositionOffset.mV[VX]) + +			(y_pixel_vec * mPositionOffset.mV[VY]); + +	mOffscreen = FALSE; +	if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius)) +	{ +		if (!mVisibleOffScreen) +		{ +			mVisible = FALSE; +			return; +		} +		else +		{ +			mOffscreen = TRUE; +		} +	} + +	mVisible = TRUE; +	sVisibleTextObjects.push_back(LLPointer<LLHUDNameTag> (this)); +} + +LLVector2 LLHUDNameTag::updateScreenPos(LLVector2 &offset) +{ +	LLCoordGL screen_pos; +	LLVector2 screen_pos_vec; +	LLVector3 x_pixel_vec; +	LLVector3 y_pixel_vec; +	LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); +	LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec); +	if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen) +	{ +		// bubble off-screen, so find a spot for it along screen edge +		LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos); +	} + +	screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY); + +	LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); +	S32 bottom = world_rect.mBottom + STATUS_BAR_HEIGHT; + +	LLVector2 screen_center; +	screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], (F32)world_rect.mLeft + mWidth * 0.5f, (F32)world_rect.mRight - mWidth * 0.5f); + +	if(mVertAlignment == ALIGN_VERT_TOP) +	{ +		screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],  +			(F32)bottom,  +			(F32)world_rect.mTop - mHeight - (F32)MENU_BAR_HEIGHT); +		mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f,  +			screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE); +	} +	else +	{ +		screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY],  +			(F32)bottom + mHeight * 0.5f,  +			(F32)world_rect.mTop - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT); +		mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE); +	} + +	return offset + (screen_center - LLVector2((F32)screen_pos.mX, (F32)screen_pos.mY)); +} + +void LLHUDNameTag::updateSize() +{ +	F32 height = 0.f; +	F32 width = 0.f; + +	S32 max_lines = getMaxLines(); +	//S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines); +	//F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size()); + +	S32 start_segment; +	if (max_lines < 0) start_segment = 0; +	else start_segment = llmax((S32)0, (S32)mTextSegments.size() - max_lines); + +	std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment; +	while (iter != mTextSegments.end()) +	{ +		const LLFontGL* fontp = iter->mFont; +		height += fontp->getLineHeight(); +		height += LINE_PADDING; +		width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH)); +		++iter; +	} + +	// Don't want line spacing under the last line +	if (height > 0.f) +	{ +		height -= LINE_PADDING; +	} + +	iter = mLabelSegments.begin(); +	while (iter != mLabelSegments.end()) +	{ +		height += mFontp->getLineHeight(); +		width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH)); +		++iter; +	} +	 +	if (width == 0.f) +	{ +		return; +	} + +	width += HORIZONTAL_PADDING; +	height += VERTICAL_PADDING; + +	// *TODO: Could do a timer-based resize here +	//mWidth = llmax(width, lerp(mWidth, (F32)width, u)); +	//mHeight = llmax(height, lerp(mHeight, (F32)height, u)); +	mWidth = width; +	mHeight = height; +} + +void LLHUDNameTag::updateAll() +{ +	// iterate over all text objects, calculate their restoration forces, +	// and add them to the visible set if they are on screen and close enough +	sVisibleTextObjects.clear(); +	 +	TextObjectIterator text_it; +	for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it) +	{ +		LLHUDNameTag* textp = (*text_it); +		textp->mTargetPositionOffset.clearVec(); +		textp->updateSize(); +		textp->updateVisibility(); +	} +	 +	// sort back to front for rendering purposes +	std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), llhudnametag_further_away()); + +	// iterate from front to back, and set LOD based on current screen coverage +	F32 screen_area = (F32)(gViewerWindow->getWindowWidthScaled() * gViewerWindow->getWindowHeightScaled()); +	F32 current_screen_area = 0.f; +	std::vector<LLPointer<LLHUDNameTag> >::reverse_iterator r_it; +	for (r_it = sVisibleTextObjects.rbegin(); r_it != sVisibleTextObjects.rend(); ++r_it) +	{ +		LLHUDNameTag* textp = (*r_it); +//		if (textp->mUseBubble) +//		{ +			if (current_screen_area / screen_area > LOD_2_SCREEN_COVERAGE) +			{ +				textp->setLOD(3); +			} +			else if (current_screen_area / screen_area > LOD_1_SCREEN_COVERAGE) +			{ +				textp->setLOD(2); +			} +			else if (current_screen_area / screen_area > LOD_0_SCREEN_COVERAGE) +			{ +				textp->setLOD(1); +			} +			else +			{ +				textp->setLOD(0); +			} +			textp->updateSize(); +			// find on-screen position and initialize collision rectangle +			textp->mTargetPositionOffset = textp->updateScreenPos(LLVector2::zero); +			current_screen_area += (F32)(textp->mSoftScreenRect.getWidth() * textp->mSoftScreenRect.getHeight()); +//		} +	} + +	LLStat* camera_vel_stat = LLViewerCamera::getInstance()->getVelocityStat(); +	F32 camera_vel = camera_vel_stat->getCurrent(); +	if (camera_vel > MAX_STABLE_CAMERA_VELOCITY) +	{ +		return; +	} + +	VisibleTextObjectIterator src_it; + +	for (S32 i = 0; i < NUM_OVERLAP_ITERATIONS; i++) +	{ +		for (src_it = sVisibleTextObjects.begin(); src_it != sVisibleTextObjects.end(); ++src_it) +		{ +			LLHUDNameTag* src_textp = (*src_it); + +//			if (!src_textp->mUseBubble) +//			{ +//				continue; +//			} +			VisibleTextObjectIterator dst_it = src_it; +			++dst_it; +			for (; dst_it != sVisibleTextObjects.end(); ++dst_it) +			{ +				LLHUDNameTag* dst_textp = (*dst_it); + +//				if (!dst_textp->mUseBubble) +//				{ +//					continue; +//				} +				if (src_textp->mSoftScreenRect.overlaps(dst_textp->mSoftScreenRect)) +				{ +					LLRectf intersect_rect = src_textp->mSoftScreenRect; +					intersect_rect.intersectWith(dst_textp->mSoftScreenRect); +					intersect_rect.stretch(-BUFFER_SIZE * 0.5f); +					 +					F32 src_center_x = src_textp->mSoftScreenRect.getCenterX(); +					F32 src_center_y = src_textp->mSoftScreenRect.getCenterY(); +					F32 dst_center_x = dst_textp->mSoftScreenRect.getCenterX(); +					F32 dst_center_y = dst_textp->mSoftScreenRect.getCenterY(); +					F32 intersect_center_x = intersect_rect.getCenterX(); +					F32 intersect_center_y = intersect_rect.getCenterY(); +					LLVector2 force = lerp(LLVector2(dst_center_x - intersect_center_x, dst_center_y - intersect_center_y),  +										LLVector2(intersect_center_x - src_center_x, intersect_center_y - src_center_y), +										0.5f); +					force.setVec(dst_center_x - src_center_x, dst_center_y - src_center_y); +					force.normVec(); + +					LLVector2 src_force = -1.f * force; +					LLVector2 dst_force = force; + +					LLVector2 force_strength; +					F32 src_mult = dst_textp->mMass / (dst_textp->mMass + src_textp->mMass);  +					F32 dst_mult = 1.f - src_mult; +					F32 src_aspect_ratio = src_textp->mSoftScreenRect.getWidth() / src_textp->mSoftScreenRect.getHeight(); +					F32 dst_aspect_ratio = dst_textp->mSoftScreenRect.getWidth() / dst_textp->mSoftScreenRect.getHeight(); +					src_force.mV[VY] *= src_aspect_ratio; +					src_force.normVec(); +					dst_force.mV[VY] *= dst_aspect_ratio; +					dst_force.normVec(); + +					src_force.mV[VX] *= llmin(intersect_rect.getWidth() * src_mult, intersect_rect.getHeight() * SPRING_STRENGTH); +					src_force.mV[VY] *= llmin(intersect_rect.getHeight() * src_mult, intersect_rect.getWidth() * SPRING_STRENGTH); +					dst_force.mV[VX] *=  llmin(intersect_rect.getWidth() * dst_mult, intersect_rect.getHeight() * SPRING_STRENGTH); +					dst_force.mV[VY] *=  llmin(intersect_rect.getHeight() * dst_mult, intersect_rect.getWidth() * SPRING_STRENGTH); +					 +					src_textp->mTargetPositionOffset += src_force; +					dst_textp->mTargetPositionOffset += dst_force; +					src_textp->mTargetPositionOffset = src_textp->updateScreenPos(src_textp->mTargetPositionOffset); +					dst_textp->mTargetPositionOffset = dst_textp->updateScreenPos(dst_textp->mTargetPositionOffset); +				} +			} +		} +	} + +	VisibleTextObjectIterator this_object_it; +	for (this_object_it = sVisibleTextObjects.begin(); this_object_it != sVisibleTextObjects.end(); ++this_object_it) +	{ +//		if (!(*this_object_it)->mUseBubble) +//		{ +//			continue; +//		} +		(*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC)); +	} +} + +void LLHUDNameTag::setLOD(S32 lod) +{ +	mLOD = lod; +	//RN: uncomment this to visualize LOD levels +	//std::string label = llformat("%d", lod); +	//setLabel(label); +} + +S32 LLHUDNameTag::getMaxLines() +{ +	switch(mLOD) +	{ +	case 0: +		return mMaxLines; +	case 1: +		return mMaxLines > 0 ? mMaxLines / 2 : 5; +	case 2: +		return mMaxLines > 0 ? mMaxLines / 3 : 2; +	default: +		// label only +		return 0; +	} +} + +void LLHUDNameTag::markDead() +{ +	sTextObjects.erase(LLPointer<LLHUDNameTag>(this)); +	LLHUDObject::markDead(); +} + +void LLHUDNameTag::shiftAll(const LLVector3& offset) +{ +	TextObjectIterator text_it; +	for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it) +	{ +		LLHUDNameTag *textp = text_it->get(); +		textp->shift(offset); +	} +} + +void LLHUDNameTag::shift(const LLVector3& offset) +{ +	mPositionAgent += offset; +} + +//static  +void LLHUDNameTag::addPickable(std::set<LLViewerObject*> &pick_list) +{ +	//this might put an object on the pick list a second time, overriding it's mGLName, which is ok +	// *FIX: we should probably cull against pick frustum +	VisibleTextObjectIterator text_it; +	for (text_it = sVisibleTextObjects.begin(); text_it != sVisibleTextObjects.end(); ++text_it) +	{ +//		if (!(*text_it)->mUseBubble) +//		{ +//			continue; +//		} +		pick_list.insert((*text_it)->mSourceObject); +	} +} + +//static +// called when UI scale changes, to flush font width caches +void LLHUDNameTag::reshape() +{ +	TextObjectIterator text_it; +	for (text_it = sTextObjects.begin(); text_it != sTextObjects.end(); ++text_it) +	{ +		LLHUDNameTag* textp = (*text_it); +		std::vector<LLHUDTextSegment>::iterator segment_iter;  +		for (segment_iter = textp->mTextSegments.begin(); +			 segment_iter != textp->mTextSegments.end(); ++segment_iter ) +		{ +			segment_iter->clearFontWidthMap(); +		} +		for(segment_iter = textp->mLabelSegments.begin(); +			segment_iter != textp->mLabelSegments.end(); ++segment_iter ) +		{ +			segment_iter->clearFontWidthMap(); +		}		 +	} +} + +//============================================================================ + +F32 LLHUDNameTag::LLHUDTextSegment::getWidth(const LLFontGL* font) +{ +	std::map<const LLFontGL*, F32>::iterator iter = mFontWidthMap.find(font); +	if (iter != mFontWidthMap.end()) +	{ +		return iter->second; +	} +	else +	{ +		F32 width = font->getWidthF32(mText.c_str()); +		mFontWidthMap[font] = width; +		return width; +	} +} diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h new file mode 100644 index 0000000000..9a92307009 --- /dev/null +++ b/indra/newview/llhudnametag.h @@ -0,0 +1,191 @@ +/**  + * @file llhudnametag.h + * @brief Name tags for avatars + * @author James Cook + * + * $LicenseInfo:firstyear=2010&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 LLHUDNAMETAG_H +#define LLHUDNAMETAG_H + +#include "llpointer.h" + +#include "llhudobject.h" +#include "v4color.h" +//#include "v4coloru.h" +#include "v2math.h" +#include "llrect.h" +//#include "llframetimer.h" +#include "llfontgl.h" +#include <set> +#include <vector> + +class LLDrawable; +class LLHUDNameTag; + +struct llhudnametag_further_away +{ +	bool operator()(const LLPointer<LLHUDNameTag>& lhs, const LLPointer<LLHUDNameTag>& rhs) const; +}; + +class LLHUDNameTag : public LLHUDObject +{ +protected: +	class LLHUDTextSegment +	{ +	public: +		LLHUDTextSegment(const LLWString& text, const LLFontGL::StyleFlags style, const LLColor4& color, const LLFontGL* font) +		:	mColor(color), +			mStyle(style), +			mText(text), +			mFont(font) +		{} +		F32 getWidth(const LLFontGL* font); +		const LLWString& getText() const { return mText; } +		void clearFontWidthMap() { mFontWidthMap.clear(); } +		 +		LLColor4				mColor; +		LLFontGL::StyleFlags	mStyle; +		const LLFontGL*			mFont; +	private: +		LLWString				mText; +		std::map<const LLFontGL*, F32> mFontWidthMap; +	}; + +public: +	typedef enum e_text_alignment +	{ +		ALIGN_TEXT_LEFT, +		ALIGN_TEXT_CENTER +	} ETextAlignment; + +	typedef enum e_vert_alignment +	{ +		ALIGN_VERT_TOP, +		ALIGN_VERT_CENTER +	} EVertAlignment; + +public: +	// Set entire string, eliminating existing lines +	void setString(const std::string& text_utf8); + +	void clearString(); + +	// Add text a line at a time, allowing custom formatting +	void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL); + +	// For bubble chat, set the part above the chat text +	void setLabel(const std::string& label_utf8); +	void addLabel(const std::string& label_utf8); + +	// Sets the default font for lines with no font specified +	void setFont(const LLFontGL* font); +	void setColor(const LLColor4 &color); +	void setAlpha(F32 alpha); +	void setZCompare(const BOOL zcompare); +	void setDoFade(const BOOL do_fade); +	void setVisibleOffScreen(BOOL visible) { mVisibleOffScreen = visible; } +	 +	// mMaxLines of -1 means unlimited lines. +	void setMaxLines(S32 max_lines) { mMaxLines = max_lines; } +	void setFadeDistance(F32 fade_distance, F32 fade_range) { mFadeDistance = fade_distance; mFadeRange = fade_range; } +	void updateVisibility(); +	LLVector2 updateScreenPos(LLVector2 &offset_target); +	void updateSize(); +//	void setMass(F32 mass) { mMass = llmax(0.1f, mass); } +	void setTextAlignment(ETextAlignment alignment) { mTextAlignment = alignment; } +	void setVertAlignment(EVertAlignment alignment) { mVertAlignment = alignment; } +	/*virtual*/ void markDead(); +	friend class LLHUDObject; +	/*virtual*/ F32 getDistance() const { return mLastDistance; } +	//void setUseBubble(BOOL use_bubble) { mUseBubble = use_bubble; } +	S32  getLOD() { return mLOD; } +	BOOL getVisible() { return mVisible; } +	BOOL getHidden() const { return mHidden; } +	void setHidden( BOOL hide ) { mHidden = hide; } +	void shift(const LLVector3& offset); + +	BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render = FALSE); + +	static void shiftAll(const LLVector3& offset); +	static void addPickable(std::set<LLViewerObject*> &pick_list); +	static void reshape(); +	static void setDisplayText(BOOL flag) { sDisplayText = flag ; } + +protected: +	LLHUDNameTag(const U8 type); + +	/*virtual*/ void render(); +	/*virtual*/ void renderForSelect(); +	void renderText(BOOL for_select); +	static void updateAll(); +	void setLOD(S32 lod); +	S32 getMaxLines(); + +private: +	~LLHUDNameTag(); +	BOOL			mDoFade; +	F32				mFadeRange; +	F32				mFadeDistance; +	F32				mLastDistance; +	BOOL			mZCompare; +	BOOL			mVisibleOffScreen; +	BOOL			mOffscreen; +	LLColor4		mColor; +//	LLVector3		mScale; +	F32				mWidth; +	F32				mHeight; +//	LLColor4U		mPickColor; +	const LLFontGL*	mFontp; +	const LLFontGL*	mBoldFontp; +	LLRectf			mSoftScreenRect; +	LLVector3		mPositionAgent; +	LLVector2		mPositionOffset; +	LLVector2		mTargetPositionOffset; +	F32				mMass; +	S32				mMaxLines; +	S32				mOffsetY; +	F32				mRadius; +	std::vector<LLHUDTextSegment> mTextSegments; +	std::vector<LLHUDTextSegment> mLabelSegments; +//	LLFrameTimer	mResizeTimer; +	ETextAlignment	mTextAlignment; +	EVertAlignment	mVertAlignment; +	S32				mLOD; +	BOOL			mHidden; + +	static BOOL    sDisplayText ; +	static std::set<LLPointer<LLHUDNameTag> > sTextObjects; +	static std::vector<LLPointer<LLHUDNameTag> > sVisibleTextObjects; +//	static std::vector<LLPointer<LLHUDNameTag> > sVisibleHUDTextObjects; +	typedef std::set<LLPointer<LLHUDNameTag> >::iterator TextObjectIterator; +	typedef std::vector<LLPointer<LLHUDNameTag> >::iterator VisibleTextObjectIterator; +}; + +#endif diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp index 2b73ed1dcd..d66ac6c5b2 100644 --- a/indra/newview/llhudobject.cpp +++ b/indra/newview/llhudobject.cpp @@ -30,9 +30,6 @@   * $/LicenseInfo$   */ -// llhudobject.cpp -// Copyright 2002, Linden Research, Inc. -  #include "llviewerprecompiledheaders.h"  #include "llhudobject.h" @@ -44,7 +41,7 @@  #include "llhudeffecttrail.h"  #include "llhudeffectlookat.h"  #include "llhudeffectpointat.h" - +#include "llhudnametag.h"  #include "llvoicevisualizer.h"  #include "llagent.h" @@ -72,7 +69,6 @@ LLHUDObject::LLHUDObject(const U8 type) :  	mVisible = TRUE;  	mType = type;  	mDead = FALSE; -	mOnHUDAttachment = FALSE;  }  LLHUDObject::~LLHUDObject() @@ -151,6 +147,9 @@ LLHUDObject *LLHUDObject::addHUDObject(const U8 type)  	case LL_HUD_ICON:  		hud_objectp = new LLHUDIcon(type);  		break; +	case LL_HUD_NAME_TAG: +		hud_objectp = new LLHUDNameTag(type); +		break;  	default:  		llwarns << "Unknown type of hud object:" << (U32) type << llendl;  	} @@ -263,6 +262,7 @@ void LLHUDObject::updateAll()  	LLFastTimer ftm(FTM_HUD_UPDATE);  	LLHUDText::updateAll();  	LLHUDIcon::updateAll(); +	LLHUDNameTag::updateAll();  	sortObjects();  } @@ -311,6 +311,14 @@ void LLHUDObject::renderAllForSelect()  }  // static +void LLHUDObject::reshapeAll() +{ +	// only hud objects that use fonts care about window size/scale changes +	LLHUDText::reshape(); +	LLHUDNameTag::reshape(); +} + +// static  void LLHUDObject::sortObjects()  {  	sHUDObjects.sort(hud_object_further_away());	 diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h index d304ac41af..a370b31a20 100644 --- a/indra/newview/llhudobject.h +++ b/indra/newview/llhudobject.h @@ -42,7 +42,7 @@  #include "v4color.h"  #include "v3math.h"  #include "v3dmath.h" -#include "lldrawpool.h" +#include "lldrawpool.h"		// TODO: eliminate, unused below  #include <list>  class LLViewerCamera; @@ -76,6 +76,9 @@ public:  	static void renderAll();  	static void renderAllForSelect(); +	// Some objects may need to update when window shape changes +	static void reshapeAll(); +  	static void cleanupHUDObjects();  	enum @@ -96,7 +99,8 @@ public:  		LL_HUD_EFFECT_EDIT,  		LL_HUD_EFFECT_LOOKAT,  		LL_HUD_EFFECT_POINTAT, -		LL_HUD_EFFECT_VOICE_VISUALIZER	// Ventrella +		LL_HUD_EFFECT_VOICE_VISUALIZER,	// Ventrella +		LL_HUD_NAME_TAG  	};  protected:  	static void sortObjects(); @@ -112,7 +116,6 @@ protected:  	BOOL			mDead;  	BOOL			mVisible;  	LLVector3d		mPositionGlobal; -	BOOL			mOnHUDAttachment;  	LLPointer<LLViewerObject> mSourceObject;  	LLPointer<LLViewerObject> mTargetObject; diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 8d1d27444b..31522f6efb 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -1,7 +1,6 @@ -  /**    * @file llhudtext.cpp - * @brief LLHUDText class implementation + * @brief Floating text above objects, set via script with llSetText()   *   * $LicenseInfo:firstyear=2002&license=viewergpl$   *  @@ -62,16 +61,16 @@ const F32 HORIZONTAL_PADDING = 15.f;  const F32 VERTICAL_PADDING = 12.f;  const F32 BUFFER_SIZE = 2.f;  const F32 MIN_EDGE_OVERLAP = 3.f; -F32 HUD_TEXT_MAX_WIDTH = 190.f; +const F32 HUD_TEXT_MAX_WIDTH = 190.f;  const F32 HUD_TEXT_MAX_WIDTH_NO_BUBBLE = 1000.f;  const F32 RESIZE_TIME = 0.f;  const S32 NUM_OVERLAP_ITERATIONS = 10;  const F32 NEIGHBOR_FORCE_FRACTION = 1.f;  const F32 POSITION_DAMPING_TC = 0.2f;  const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f; -const F32 LOD_0_SCREEN_COVERAGE = 0.15f; -const F32 LOD_1_SCREEN_COVERAGE = 0.30f; -const F32 LOD_2_SCREEN_COVERAGE = 0.40f; +//const F32 LOD_0_SCREEN_COVERAGE = 0.15f; +//const F32 LOD_1_SCREEN_COVERAGE = 0.30f; +//const F32 LOD_2_SCREEN_COVERAGE = 0.40f;  std::set<LLPointer<LLHUDText> > LLHUDText::sTextObjects;  std::vector<LLPointer<LLHUDText> > LLHUDText::sVisibleTextObjects; @@ -80,15 +79,14 @@ BOOL LLHUDText::sDisplayText = TRUE ;  bool lltextobject_further_away::operator()(const LLPointer<LLHUDText>& lhs, const LLPointer<LLHUDText>& rhs) const  { -	return (lhs->getDistance() > rhs->getDistance()) ? true : false; +	return lhs->getDistance() > rhs->getDistance();  }  LLHUDText::LLHUDText(const U8 type) :  			LLHUDObject(type), -			mUseBubble(FALSE), -			mUsePixelSize(TRUE), -			mVisibleOffScreen(FALSE), +			mOnHUDAttachment(FALSE), +//			mVisibleOffScreen(FALSE),  			mWidth(0.f),  			mHeight(0.f),  			mFontp(LLFontGL::getFontSansSerifSmall()), @@ -98,7 +96,7 @@ LLHUDText::LLHUDText(const U8 type) :  			mOffsetY(0),  			mTextAlignment(ALIGN_TEXT_CENTER),  			mVertAlignment(ALIGN_VERT_CENTER), -			mLOD(0), +//			mLOD(0),  			mHidden(FALSE)  {  	mColor = LLColor4(1.f, 1.f, 1.f, 1.f); @@ -106,7 +104,6 @@ LLHUDText::LLHUDText(const U8 type) :  	mFadeDistance = 8.f;  	mFadeRange = 4.f;  	mZCompare = TRUE; -	mDropShadow = TRUE;  	mOffscreen = FALSE;  	mRadius = 0.1f;  	LLPointer<LLHUDText> ptr(this); @@ -117,112 +114,6 @@ LLHUDText::~LLHUDText()  {  } - -BOOL LLHUDText::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render) -{ -	if (!mVisible || mHidden) -	{ -		return FALSE; -	} - -	// don't pick text that isn't bound to a viewerobject or isn't in a bubble -	if (!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble) -	{ -		return FALSE; -	} -	 -	F32 alpha_factor = 1.f; -	LLColor4 text_color = mColor; -	if (mDoFade) -	{ -		if (mLastDistance > mFadeDistance) -		{ -			alpha_factor = llmax(0.f, 1.f - (mLastDistance - mFadeDistance)/mFadeRange); -			text_color.mV[3] = text_color.mV[3]*alpha_factor; -		} -	} -	if (text_color.mV[3] < 0.01f) -	{ -		return FALSE; -	} - -	mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); - -	// scale screen size of borders down -	//RN: for now, text on hud objects is never occluded - -	LLVector3 x_pixel_vec; -	LLVector3 y_pixel_vec; -	 -	if (mOnHUDAttachment) -	{ -		x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWindowWidthScaled(); -		y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWindowHeightScaled(); -	} -	else -	{ -		LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); -	} - -	LLVector3 width_vec = mWidth * x_pixel_vec; -	LLVector3 height_vec = mHeight * y_pixel_vec; -	 -	LLCoordGL screen_pos; -	LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE); - -	LLVector2 screen_offset; -	screen_offset = updateScreenPos(mPositionOffset); -	 -	LLVector3 render_position = mPositionAgent   -			+ (x_pixel_vec * screen_offset.mV[VX]) -			+ (y_pixel_vec * screen_offset.mV[VY]); - - -	if (mUseBubble) -	{ -		LLVector3 bg_pos = render_position -			+ (F32)mOffsetY * y_pixel_vec -			- (width_vec / 2.f) -			- (height_vec); -		//LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]); - -		LLVector3 v[] =  -		{ -			bg_pos, -			bg_pos + width_vec, -			bg_pos + width_vec + height_vec, -			bg_pos + height_vec, -		}; - -		if (debug_render) -		{ -			gGL.begin(LLRender::LINE_STRIP); -			gGL.vertex3fv(v[0].mV); -			gGL.vertex3fv(v[1].mV); -			gGL.vertex3fv(v[2].mV); -			gGL.vertex3fv(v[3].mV); -			gGL.vertex3fv(v[0].mV); -			gGL.vertex3fv(v[2].mV); -			gGL.end(); -		} - -		LLVector3 dir = end-start; -		F32 t = 0.f; - -		if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) || -			LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) ) -		{ -			if (t <= 1.f) -			{ -				intersection = start + dir*t; -				return TRUE; -			} -		} -	} - -	return FALSE; -} -  void LLHUDText::render()  {  	if (!mOnHUDAttachment && sDisplayText) @@ -248,21 +139,13 @@ void LLHUDText::renderText(BOOL for_select)  		return;  	} -	// don't pick text that isn't bound to a viewerobject or isn't in a bubble -	if (for_select &&  -		(!mSourceObject || mSourceObject->mDrawable.isNull() || !mUseBubble)) +	// don't pick text +	if (for_select)  	{  		return;  	} -	if (for_select) -	{ -		gGL.getTexUnit(0)->disable(); -	} -	else -	{ -		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); -	} +	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);  	LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE);  	LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE); @@ -290,7 +173,7 @@ void LLHUDText::renderText(BOOL for_select)  	LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square");  	// *TODO: make this a per-text setting -	LLColor4 bg_color = LLUIColorTable::instance().getColor("BackgroundChatColor"); +	LLColor4 bg_color = LLUIColorTable::instance().getColor("ObjectBubbleColor");  	bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor);  	const S32 border_height = 16; @@ -336,178 +219,17 @@ void LLHUDText::renderText(BOOL for_select)  	LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);  	LLVector2 screen_offset; -	if (!mUseBubble) -	{ -		screen_offset = mPositionOffset; -	} -	else -	{ -		screen_offset = updateScreenPos(mPositionOffset); -	} +	screen_offset = mPositionOffset;  	LLVector3 render_position = mPositionAgent    			+ (x_pixel_vec * screen_offset.mV[VX])  			+ (y_pixel_vec * screen_offset.mV[VY]); -	//if (mOnHUD) -	//{ -	//	render_position.mV[VY] -= fmodf(render_position.mV[VY], 1.f / (F32)gViewerWindow->getWindowWidthScaled()); -	//	render_position.mV[VZ] -= fmodf(render_position.mV[VZ], 1.f / (F32)gViewerWindow->getWindowHeightScaled()); -	//} -	//else -	//{ -	//	render_position = LLViewerCamera::getInstance()->roundToPixel(render_position); -	//} - -	if (mUseBubble) -	{ -		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); -		LLUI::pushMatrix(); -		{ -			LLVector3 bg_pos = render_position -				+ (F32)mOffsetY * y_pixel_vec -				- (width_vec / 2.f) -				- (height_vec); -			LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]); - -			if (for_select) -			{ -				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -				S32 name = mSourceObject->mGLName; -				LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name); -				gGL.color4ubv(coloru.mV); -				gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec); -				LLUI::popMatrix(); -				return; -			} -			else -			{ -				gGL.getTexUnit(0)->bind(imagep->getImage()); -				 -				gGL.color4fv(bg_color.mV); -				gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec); -		 -				if ( mLabelSegments.size()) -				{ -					LLUI::pushMatrix(); -					{ -						gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); -						LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec; -						LLVector3 label_offset = height_vec - label_height; -						LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]); -						gl_segmented_rect_3d_tex_top(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, label_height); -					} -					LLUI::popMatrix(); -				} -			} - -			BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f; -			BOOL outside_height = llabs(mPositionOffset.mV[VY] + (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.5f : 0.f)) > mHeight * (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.75f : 0.5f); - -			// draw line segments pointing to parent object -			if (!mOffscreen && (outside_width || outside_height)) -			{ -				LLUI::pushMatrix(); -				{ -					gGL.color4fv(bg_color.mV); -					LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec); -					target_pos += (width_vec / 2.f); -					target_pos += mVertAlignment == ALIGN_VERT_CENTER ? (height_vec * 0.5f) : LLVector3::zero; -					target_pos -= 3.f * x_pixel_vec; -					target_pos -= 6.f * y_pixel_vec; -					LLUI::translate(target_pos.mV[VX], target_pos.mV[VY], target_pos.mV[VZ]); -					gl_segmented_rect_3d_tex(border_scale_vec, 3.f * x_pixel_vec, 3.f * y_pixel_vec, 6.f * x_pixel_vec, 6.f * y_pixel_vec);	 -				} -				LLUI::popMatrix(); - -				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -				LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE); -				 -				LLVector3 box_center_offset; -				box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f); -				LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]); -				gGL.color4fv(bg_color.mV); -				LLUI::setLineWidth(2.0); -				gGL.begin(LLRender::LINES); -				{ -					if (outside_width) -					{ -						LLVector3 vert; -						// draw line in x then y -						if (mPositionOffset.mV[VX] < 0.f) -						{ -							// start at right edge -							vert = width_vec * 0.5f; -							gGL.vertex3fv(vert.mV); -						} -						else -						{ -							// start at left edge -							vert = width_vec * -0.5f; -							gGL.vertex3fv(vert.mV); -						} -						vert = -mPositionOffset.mV[VX] * x_pixel_vec; -						gGL.vertex3fv(vert.mV); -						gGL.vertex3fv(vert.mV); -						vert -= mPositionOffset.mV[VY] * y_pixel_vec; -						vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); -						gGL.vertex3fv(vert.mV); -					} -					else -					{ -						LLVector3 vert; -						// draw line in y then x -						if (mPositionOffset.mV[VY] < 0.f) -						{ -							// start at top edge -							vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec); -							gGL.vertex3fv(vert.mV); -						} -						else -						{ -							// start at bottom edge -							vert = (height_vec * -0.5f)  - (mPositionOffset.mV[VX] * x_pixel_vec); -							gGL.vertex3fv(vert.mV); -						} -						vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec; -						vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); -						gGL.vertex3fv(vert.mV); -					} -				} -				gGL.end(); -				LLUI::setLineWidth(1.0); - -			} -		} -		LLUI::popMatrix(); -	} -  	F32 y_offset = (F32)mOffsetY;  	// Render label  	{  		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - -		for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin(); -			segment_iter != mLabelSegments.end(); ++segment_iter ) -		{ -			const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp; -			y_offset -= fontp->getLineHeight(); - -			F32 x_offset; -			if (mTextAlignment == ALIGN_TEXT_CENTER) -			{ -				x_offset = -0.5f*segment_iter->getWidth(fontp); -			} -			else // ALIGN_LEFT -			{ -				x_offset = -0.5f * mWidth + (HORIZONTAL_PADDING / 2.f); -			} - -			LLColor4 label_color(0.f, 0.f, 0.f, 1.f); -			label_color.mV[VALPHA] = alpha_factor; -			hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, mOnHUDAttachment); -		}  	}  	// Render text @@ -528,15 +250,11 @@ void LLHUDText::renderText(BOOL for_select)  		for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;  			 segment_iter != mTextSegments.end(); ++segment_iter )  		{ -			const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp; +			const LLFontGL* fontp = segment_iter->mFont;  			y_offset -= fontp->getLineHeight();  			U8 style = segment_iter->mStyle; -			LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW; -			if (mDropShadow) -			{ -				shadow = LLFontGL::DROP_SHADOW; -			} +			LLFontGL::ShadowType shadow = LLFontGL::DROP_SHADOW;  			F32 x_offset;  			if (mTextAlignment== ALIGN_TEXT_CENTER) @@ -556,21 +274,12 @@ void LLHUDText::renderText(BOOL for_select)  	}  	/// Reset the default color to white.  The renderer expects this to be the default.   	gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f); -	if (for_select) -	{ -		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); -	} -} - -void LLHUDText::setStringUTF8(const std::string &wtext) -{ -	setString(utf8str_to_wstring(wtext));  } -void LLHUDText::setString(const LLWString &wtext) +void LLHUDText::setString(const std::string &text_utf8)  {  	mTextSegments.clear(); -	addLine(wtext, mColor); +	addLine(text_utf8, mColor);  }  void LLHUDText::clearString() @@ -579,21 +288,19 @@ void LLHUDText::clearString()  } -void LLHUDText::addLine(const std::string &str, const LLColor4& color, const LLFontGL::StyleFlags style) +void LLHUDText::addLine(const std::string &text_utf8, +						const LLColor4& color, +						const LLFontGL::StyleFlags style, +						const LLFontGL* font)  { -	addLine(utf8str_to_wstring(str), color, style); -} - - -void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFontGL::StyleFlags style) -{ -	if (gNoRender) -	{ -		return; -	} -	if (!wstr.empty()) +	LLWString wline = utf8str_to_wstring(text_utf8); +	if (!wline.empty())  	{ -		LLWString wline(wstr); +		// use default font for segment if custom font not specified +		if (!font) +		{ +			font = mFontp; +		}  		typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer;  		LLWString seps(utf8str_to_wstring("\r\n"));  		boost::char_separator<llwchar> sep(seps.c_str()); @@ -606,8 +313,10 @@ void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFo  			U32 line_length = 0;  			do	  			{ -				S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); -				mTextSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), style, color)); +				F32 max_pixels = HUD_TEXT_MAX_WIDTH_NO_BUBBLE; +				S32 segment_length = font->maxDrawableChars(iter->substr(line_length).c_str(), max_pixels, wline.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); +				LLHUDTextSegment segment(iter->substr(line_length, segment_length), style, color, font); +				mTextSegments.push_back(segment);  				line_length += segment_length;  			}  			while (line_length != iter->size()); @@ -616,47 +325,6 @@ void LLHUDText::addLine(const LLWString &wstr, const LLColor4& color, const LLFo  	}  } -void LLHUDText::setLabel(const std::string &label) -{ -	setLabel(utf8str_to_wstring(label)); -} - -void LLHUDText::setLabel(const LLWString &wlabel) -{ -	mLabelSegments.clear(); - -	if (!wlabel.empty()) -	{ -		LLWString wstr(wlabel); -		LLWString seps(utf8str_to_wstring("\r\n")); -		LLWString empty; - -		typedef boost::tokenizer<boost::char_separator<llwchar>, LLWString::const_iterator, LLWString > tokenizer; -		boost::char_separator<llwchar> sep(seps.c_str(), empty.c_str(), boost::keep_empty_tokens); - -		tokenizer tokens(wstr, sep); -		tokenizer::iterator iter = tokens.begin(); - -		while (iter != tokens.end()) -		{ -			U32 line_length = 0; -			do	 -			{ -				S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(), mUseBubble ? HUD_TEXT_MAX_WIDTH : HUD_TEXT_MAX_WIDTH_NO_BUBBLE, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); -				mLabelSegments.push_back(LLHUDTextSegment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor)); -				line_length += segment_length; -			} -			while (line_length != iter->size()); -			++iter; -		} -	} -} - -void LLHUDText::setDropShadow(const BOOL do_shadow) -{ -	mDropShadow = do_shadow; -} -  void LLHUDText::setZCompare(const BOOL zcompare)  {  	mZCompare = zcompare; @@ -678,12 +346,17 @@ void LLHUDText::setColor(const LLColor4 &color)  	}  } - -void LLHUDText::setUsePixelSize(const BOOL use_pixel_size) +void LLHUDText::setAlpha(F32 alpha)  { -	mUsePixelSize = use_pixel_size; +	mColor.mV[VALPHA] = alpha; +	for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin(); +		 segment_iter != mTextSegments.end(); ++segment_iter ) +	{ +		segment_iter->mColor.mV[VALPHA] = alpha; +	}  } +  void LLHUDText::setDoFade(const BOOL do_fade)  {  	mDoFade = do_fade; @@ -751,7 +424,7 @@ void LLHUDText::updateVisibility()  	mLastDistance = (mPositionAgent - LLViewerCamera::getInstance()->getOrigin()).magVec(); -	if (mLOD >= 3 || !mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange))) +	if (!mTextSegments.size() || (mDoFade && (mLastDistance > mFadeDistance + mFadeRange)))  	{  		mVisible = FALSE;  		return; @@ -769,15 +442,15 @@ void LLHUDText::updateVisibility()  	mOffscreen = FALSE;  	if (!LLViewerCamera::getInstance()->sphereInFrustum(render_position, mRadius))  	{ -		if (!mVisibleOffScreen) -		{ +//		if (!mVisibleOffScreen) +//		{  			mVisible = FALSE;  			return; -		} -		else -		{ -			mOffscreen = TRUE; -		} +//		} +//		else +//		{ +//			mOffscreen = TRUE; +//		}  	}  	mVisible = TRUE; @@ -792,11 +465,11 @@ LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)  	LLVector3 y_pixel_vec;  	LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec);  	LLVector3 world_pos = mPositionAgent + (offset.mV[VX] * x_pixel_vec) + (offset.mV[VY] * y_pixel_vec); -	if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen) -	{ -		// bubble off-screen, so find a spot for it along screen edge -		LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos); -	} +//	if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen) +//	{ +//		// bubble off-screen, so find a spot for it along screen edge +//		LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos); +//	}  	screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY); @@ -827,12 +500,12 @@ LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset)  void LLHUDText::updateSize()  { +	F32 height = 0.f;  	F32 width = 0.f;  	S32 max_lines = getMaxLines(); -	S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines); - -	F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size()); +	//S32 lines = (max_lines < 0) ? (S32)mTextSegments.size() : llmin((S32)mTextSegments.size(), max_lines); +	//F32 height = (F32)mFontp->getLineHeight() * (lines + mLabelSegments.size());  	S32 start_segment;  	if (max_lines < 0) start_segment = 0; @@ -841,17 +514,12 @@ void LLHUDText::updateSize()  	std::vector<LLHUDTextSegment>::iterator iter = mTextSegments.begin() + start_segment;  	while (iter != mTextSegments.end())  	{ -		width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH)); +		const LLFontGL* fontp = iter->mFont; +		height += fontp->getLineHeight(); +		width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH));  		++iter;  	} -	iter = mLabelSegments.begin(); -	while (iter != mLabelSegments.end()) -	{ -		width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH)); -		++iter; -	} -	  	if (width == 0.f)  	{  		return; @@ -860,18 +528,8 @@ void LLHUDText::updateSize()  	width += HORIZONTAL_PADDING;  	height += VERTICAL_PADDING; -	if (!mResizeTimer.getStarted() && (width != mWidth || height != mHeight)) -	{ -		mResizeTimer.start(); -	} - -	// *NOTE: removed logic which did a divide by zero. -	F32 u = 1.f;//llclamp(mResizeTimer.getElapsedTimeF32() / RESIZE_TIME, 0.f, 1.f); -	if (u == 1.f) -	{ -		mResizeTimer.stop(); -	} - +	// *TODO: Could do some sort of timer-based resize logic here +	F32 u = 1.f;  	mWidth = llmax(width, lerp(mWidth, (F32)width, u));  	mHeight = llmax(height, lerp(mHeight, (F32)height, u));  } @@ -895,146 +553,31 @@ void LLHUDText::updateAll()  	// sort back to front for rendering purposes  	std::sort(sVisibleTextObjects.begin(), sVisibleTextObjects.end(), lltextobject_further_away());  	std::sort(sVisibleHUDTextObjects.begin(), sVisibleHUDTextObjects.end(), lltextobject_further_away()); - -	// iterate from front to back, and set LOD based on current screen coverage -	F32 screen_area = (F32)(gViewerWindow->getWindowWidthScaled() * gViewerWindow->getWindowHeightScaled()); -	F32 current_screen_area = 0.f; -	std::vector<LLPointer<LLHUDText> >::reverse_iterator r_it; -	for (r_it = sVisibleTextObjects.rbegin(); r_it != sVisibleTextObjects.rend(); ++r_it) -	{ -		LLHUDText* textp = (*r_it); -		if (textp->mUseBubble) -		{ -			if (current_screen_area / screen_area > LOD_2_SCREEN_COVERAGE) -			{ -				textp->setLOD(3); -			} -			else if (current_screen_area / screen_area > LOD_1_SCREEN_COVERAGE) -			{ -				textp->setLOD(2); -			} -			else if (current_screen_area / screen_area > LOD_0_SCREEN_COVERAGE) -			{ -				textp->setLOD(1); -			} -			else -			{ -				textp->setLOD(0); -			} -			textp->updateSize(); -			// find on-screen position and initialize collision rectangle -			textp->mTargetPositionOffset = textp->updateScreenPos(LLVector2::zero); -			current_screen_area += (F32)(textp->mSoftScreenRect.getWidth() * textp->mSoftScreenRect.getHeight()); -		} -	} - -	LLStat* camera_vel_stat = LLViewerCamera::getInstance()->getVelocityStat(); -	F32 camera_vel = camera_vel_stat->getCurrent(); -	if (camera_vel > MAX_STABLE_CAMERA_VELOCITY) -	{ -		return; -	} - -	VisibleTextObjectIterator src_it; - -	for (S32 i = 0; i < NUM_OVERLAP_ITERATIONS; i++) -	{ -		for (src_it = sVisibleTextObjects.begin(); src_it != sVisibleTextObjects.end(); ++src_it) -		{ -			LLHUDText* src_textp = (*src_it); - -			if (!src_textp->mUseBubble) -			{ -				continue; -			} -			VisibleTextObjectIterator dst_it = src_it; -			++dst_it; -			for (; dst_it != sVisibleTextObjects.end(); ++dst_it) -			{ -				LLHUDText* dst_textp = (*dst_it); - -				if (!dst_textp->mUseBubble) -				{ -					continue; -				} -				if (src_textp->mSoftScreenRect.overlaps(dst_textp->mSoftScreenRect)) -				{ -					LLRectf intersect_rect = src_textp->mSoftScreenRect; -					intersect_rect.intersectWith(dst_textp->mSoftScreenRect); -					intersect_rect.stretch(-BUFFER_SIZE * 0.5f); -					 -					F32 src_center_x = src_textp->mSoftScreenRect.getCenterX(); -					F32 src_center_y = src_textp->mSoftScreenRect.getCenterY(); -					F32 dst_center_x = dst_textp->mSoftScreenRect.getCenterX(); -					F32 dst_center_y = dst_textp->mSoftScreenRect.getCenterY(); -					F32 intersect_center_x = intersect_rect.getCenterX(); -					F32 intersect_center_y = intersect_rect.getCenterY(); -					LLVector2 force = lerp(LLVector2(dst_center_x - intersect_center_x, dst_center_y - intersect_center_y),  -										LLVector2(intersect_center_x - src_center_x, intersect_center_y - src_center_y), -										0.5f); -					force.setVec(dst_center_x - src_center_x, dst_center_y - src_center_y); -					force.normVec(); - -					LLVector2 src_force = -1.f * force; -					LLVector2 dst_force = force; - -					LLVector2 force_strength; -					F32 src_mult = dst_textp->mMass / (dst_textp->mMass + src_textp->mMass);  -					F32 dst_mult = 1.f - src_mult; -					F32 src_aspect_ratio = src_textp->mSoftScreenRect.getWidth() / src_textp->mSoftScreenRect.getHeight(); -					F32 dst_aspect_ratio = dst_textp->mSoftScreenRect.getWidth() / dst_textp->mSoftScreenRect.getHeight(); -					src_force.mV[VY] *= src_aspect_ratio; -					src_force.normVec(); -					dst_force.mV[VY] *= dst_aspect_ratio; -					dst_force.normVec(); - -					src_force.mV[VX] *= llmin(intersect_rect.getWidth() * src_mult, intersect_rect.getHeight() * SPRING_STRENGTH); -					src_force.mV[VY] *= llmin(intersect_rect.getHeight() * src_mult, intersect_rect.getWidth() * SPRING_STRENGTH); -					dst_force.mV[VX] *=  llmin(intersect_rect.getWidth() * dst_mult, intersect_rect.getHeight() * SPRING_STRENGTH); -					dst_force.mV[VY] *=  llmin(intersect_rect.getHeight() * dst_mult, intersect_rect.getWidth() * SPRING_STRENGTH); -					 -					src_textp->mTargetPositionOffset += src_force; -					dst_textp->mTargetPositionOffset += dst_force; -					src_textp->mTargetPositionOffset = src_textp->updateScreenPos(src_textp->mTargetPositionOffset); -					dst_textp->mTargetPositionOffset = dst_textp->updateScreenPos(dst_textp->mTargetPositionOffset); -				} -			} -		} -	} - -	VisibleTextObjectIterator this_object_it; -	for (this_object_it = sVisibleTextObjects.begin(); this_object_it != sVisibleTextObjects.end(); ++this_object_it) -	{ -		if (!(*this_object_it)->mUseBubble) -		{ -			continue; -		} -		(*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC)); -	}  } -void LLHUDText::setLOD(S32 lod) -{ -	mLOD = lod; -	//RN: uncomment this to visualize LOD levels -	//std::string label = llformat("%d", lod); -	//setLabel(label); -} +//void LLHUDText::setLOD(S32 lod) +//{ +//	mLOD = lod; +//	//RN: uncomment this to visualize LOD levels +//	//std::string label = llformat("%d", lod); +//	//setLabel(label); +//}  S32 LLHUDText::getMaxLines()  { -	switch(mLOD) -	{ -	case 0: -		return mMaxLines; -	case 1: -		return mMaxLines > 0 ? mMaxLines / 2 : 5; -	case 2: -		return mMaxLines > 0 ? mMaxLines / 3 : 2; -	default: -		// label only -		return 0; -	} +	return mMaxLines; +	//switch(mLOD) +	//{ +	//case 0: +	//	return mMaxLines; +	//case 1: +	//	return mMaxLines > 0 ? mMaxLines / 2 : 5; +	//case 2: +	//	return mMaxLines > 0 ? mMaxLines / 3 : 2; +	//default: +	//	// label only +	//	return 0; +	//}  }  void LLHUDText::markDead() @@ -1085,22 +628,6 @@ void LLHUDText::shift(const LLVector3& offset)  	mPositionAgent += offset;  } -//static  -void LLHUDText::addPickable(std::set<LLViewerObject*> &pick_list) -{ -	//this might put an object on the pick list a second time, overriding it's mGLName, which is ok -	// *FIX: we should probably cull against pick frustum -	VisibleTextObjectIterator text_it; -	for (text_it = sVisibleTextObjects.begin(); text_it != sVisibleTextObjects.end(); ++text_it) -	{ -		if (!(*text_it)->mUseBubble) -		{ -			continue; -		} -		pick_list.insert((*text_it)->mSourceObject); -	} -} -  //static  // called when UI scale changes, to flush font width caches  void LLHUDText::reshape() @@ -1115,11 +642,6 @@ void LLHUDText::reshape()  		{  			segment_iter->clearFontWidthMap();  		} -		for(segment_iter = textp->mLabelSegments.begin(); -			segment_iter != textp->mLabelSegments.end(); ++segment_iter ) -		{ -			segment_iter->clearFontWidthMap(); -		}		  	}  } diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index dc14a8c764..27b8f07cca 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -34,18 +34,15 @@  #define LL_LLHUDTEXT_H  #include "llpointer.h" -#include "lldarrayptr.h"  #include "llhudobject.h"  #include "v4color.h"  #include "v4coloru.h"  #include "v2math.h"  #include "llrect.h" -#include "llframetimer.h"  #include "llfontgl.h"  #include <set>  #include <vector> -#include "lldarray.h"  // Renders a 2D text billboard floating at the location specified.  class LLDrawable; @@ -62,14 +59,19 @@ protected:  	class LLHUDTextSegment  	{  	public: -		LLHUDTextSegment(const LLWString& text, const LLFontGL::StyleFlags style, const LLColor4& color) -			: mColor(color), mStyle(style), mText(text) {} +		LLHUDTextSegment(const LLWString& text, const LLFontGL::StyleFlags style, const LLColor4& color, const LLFontGL* font) +		:	mColor(color), +			mStyle(style), +			mText(text), +			mFont(font) +		{}  		F32 getWidth(const LLFontGL* font); -		const LLWString& getText() const { return mText; }; +		const LLWString& getText() const { return mText; }  		void clearFontWidthMap() { mFontWidthMap.clear(); }  		LLColor4				mColor;  		LLFontGL::StyleFlags	mStyle; +		const LLFontGL*			mFont;  	private:  		LLWString				mText;  		std::map<const LLFontGL*, F32> mFontWidthMap; @@ -89,20 +91,21 @@ public:  	} EVertAlignment;  public: -	void setStringUTF8(const std::string &utf8string); -	void setString(const LLWString &wstring); +	// Set entire string, eliminating existing lines +	void setString(const std::string& text_utf8); +  	void clearString(); -	void addLine(const std::string &text, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL); -	void addLine(const LLWString &wtext, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL); -	void setLabel(const std::string &label); -	void setLabel(const LLWString &label); -	void setDropShadow(const BOOL do_shadow); + +	// Add text a line at a time, allowing custom formatting +	void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL); + +	// Sets the default font for lines with no font specified  	void setFont(const LLFontGL* font);  	void setColor(const LLColor4 &color); -	void setUsePixelSize(const BOOL use_pixel_size); +	void setAlpha(F32 alpha);  	void setZCompare(const BOOL zcompare);  	void setDoFade(const BOOL do_fade); -	void setVisibleOffScreen(BOOL visible) { mVisibleOffScreen = visible; } +//	void setVisibleOffScreen(BOOL visible) { mVisibleOffScreen = visible; }  	// mMaxLines of -1 means unlimited lines.  	void setMaxLines(S32 max_lines) { mMaxLines = max_lines; } @@ -116,21 +119,17 @@ public:  	/*virtual*/ void markDead();  	friend class LLHUDObject;  	/*virtual*/ F32 getDistance() const { return mLastDistance; } -	void setUseBubble(BOOL use_bubble) { mUseBubble = use_bubble; } -	S32  getLOD() { return mLOD; }  	BOOL getVisible() { return mVisible; }  	BOOL getHidden() const { return mHidden; }  	void setHidden( BOOL hide ) { mHidden = hide; }  	void setOnHUDAttachment(BOOL on_hud) { mOnHUDAttachment = on_hud; }  	void shift(const LLVector3& offset); -	BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render = FALSE); -  	static void shiftAll(const LLVector3& offset);  	static void renderAllHUD(); -	static void addPickable(std::set<LLViewerObject*> &pick_list);  	static void reshape();  	static void setDisplayText(BOOL flag) { sDisplayText = flag ; } +  protected:  	LLHUDText(const U8 type); @@ -138,21 +137,17 @@ protected:  	/*virtual*/ void renderForSelect();  	void renderText(BOOL for_select);  	static void updateAll(); -	void setLOD(S32 lod);  	S32 getMaxLines();  private:  	~LLHUDText(); -	BOOL			mOnHUD; -	BOOL			mUseBubble; -	BOOL			mDropShadow; +	BOOL			mOnHUDAttachment;  	BOOL			mDoFade;  	F32				mFadeRange;  	F32				mFadeDistance;  	F32				mLastDistance; -	BOOL			mUsePixelSize;  	BOOL			mZCompare; -	BOOL			mVisibleOffScreen; +//	BOOL			mVisibleOffScreen;  	BOOL			mOffscreen;  	LLColor4		mColor;  	LLVector3		mScale; @@ -170,11 +165,8 @@ private:  	S32				mOffsetY;  	F32				mRadius;  	std::vector<LLHUDTextSegment> mTextSegments; -	std::vector<LLHUDTextSegment> mLabelSegments; -	LLFrameTimer	mResizeTimer;  	ETextAlignment	mTextAlignment;  	EVertAlignment	mVertAlignment; -	S32				mLOD;  	BOOL			mHidden;  	static BOOL    sDisplayText ; diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 967f38bfd2..a8ec551e58 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -38,6 +38,7 @@  #include "llagent.h"  #include "llappviewer.h" +#include "llavatarnamecache.h"  #include "llbutton.h"  #include "llbottomtray.h"  #include "llchannelmanager.h" @@ -281,12 +282,6 @@ BOOL LLIMFloater::postBuild()  	mInputEditor->setReplaceNewlinesWithSpaces( FALSE );  	mInputEditor->setPassDelete( TRUE ); -	std::string session_name(LLIMModel::instance().getName(mSessionID)); - -	mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + session_name); - -	setTitle(session_name); -  	childSetCommitCallback("chat_editor", onSendMsg, this);  	mChatHistory = getChild<LLChatHistory>("chat_history"); @@ -304,6 +299,19 @@ BOOL LLIMFloater::postBuild()  		mInputEditor->setLabel(LLTrans::getString("IM_unavailable_text_label"));  	} +	if ( im_session && im_session->isP2PSessionType()) +	{ +		// look up display name for window title +		LLAvatarNameCache::get(im_session->mOtherParticipantID, +							   boost::bind(&LLIMFloater::onAvatarNameCache, +										   this, _1, _2)); +	} +	else +	{ +		std::string session_name(LLIMModel::instance().getName(mSessionID)); +		updateSessionName(session_name, session_name); +	} +	  	//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"  	//see LLFloaterIMPanel for how it is done (IB) @@ -317,6 +325,23 @@ BOOL LLIMFloater::postBuild()  	}  } +void LLIMFloater::updateSessionName(const std::string& ui_title, +									const std::string& ui_label) +{ +	mInputEditor->setLabel(LLTrans::getString("IM_to_label") + " " + ui_label); +	setTitle(ui_title);	 +} + +void LLIMFloater::onAvatarNameCache(const LLUUID& agent_id, +									const LLAvatarName& av_name) +{ +	// Use display name only for labels, as the extended name will be in the +	// floater title +	std::string ui_title = av_name.getCompleteName(); +	updateSessionName(ui_title, av_name.mDisplayName); +	mTypingStart.setArg("[NAME]", ui_title); +} +  // virtual  void LLIMFloater::draw()  { @@ -1077,13 +1102,9 @@ void LLIMFloater::addTypingIndicator(const LLIMInfo* im_info)  	{  		mOtherTyping = true; -		// Create typing is started title string -		LLUIString typing_start(mTypingStart); -		typing_start.setArg("[NAME]", im_info->mName); -  		// Save and set new title  		mSavedTitle = getTitle(); -		setTitle (typing_start); +		setTitle (mTypingStart);  		// Update speaker  		LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index f1e68a2b3d..89f57aa8bb 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -38,6 +38,7 @@  #include "lltooldraganddrop.h"  #include "lltransientdockablefloater.h" +class LLAvatarName;  class LLLineEditor;  class LLPanelChatControlPanel;  class LLChatHistory; @@ -130,6 +131,12 @@ private:  	/* virtual */ void onFocusLost();  	/* virtual */ void onFocusReceived(); +	// Update the window title, input field help text, etc. +	void updateSessionName(const std::string& ui_title, const std::string& ui_label); +	 +	// For display name lookups for IM window titles +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); +	  	BOOL dropCallingCard(LLInventoryItem* item, BOOL drop);  	BOOL dropCategory(LLInventoryCategory* category, BOOL drop); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 21313f9df7..7c951e3556 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -34,6 +34,7 @@  #include "llimview.h" +#include "llavatarnamecache.h"	// IDEVO  #include "llfloaterreg.h"  #include "llfontgl.h"  #include "llgl.h" @@ -70,11 +71,6 @@  #include "llviewerparcelmgr.h" -const static std::string IM_TIME("time"); -const static std::string IM_TEXT("message"); -const static std::string IM_FROM("from"); -const static std::string IM_FROM_ID("from_id"); -  const static std::string NO_SESSION("(IM Session Doesn't Exist)");  const static std::string ADHOC_NAME_SUFFIX(" Conference"); @@ -108,6 +104,20 @@ BOOL LLSessionTimeoutTimer::tick()  	return TRUE;  } +static void on_avatar_name_cache_toast(const LLUUID& agent_id, +									   const LLAvatarName& av_name, +									   LLSD msg) +{ +	LLSD args; +	args["MESSAGE"] = msg["message"]; +	args["TIME"] = msg["time"]; +	// *TODO: Can this ever be an object name or group name? +	args["FROM"] = av_name.getCompleteName(); +	args["FROM_ID"] = msg["from_id"]; +	args["SESSION_ID"] = msg["session_id"]; +	LLNotificationsUtil::add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID())); +} +  void toast_callback(const LLSD& msg){  	// do not show toast in busy mode or it goes from agent  	if (gAgent.getBusy() || gAgent.getID() == msg["from_id"]) @@ -135,14 +145,9 @@ void toast_callback(const LLSD& msg){  		return;  	} -	LLSD args; -	args["MESSAGE"] = msg["message"]; -	args["TIME"] = msg["time"]; -	args["FROM"] = msg["from"]; -	args["FROM_ID"] = msg["from_id"]; -	args["SESSION_ID"] = msg["session_id"]; - -	LLNotificationsUtil::add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID())); +	LLAvatarNameCache::get(msg["from_id"].asUUID(), +		boost::bind(&on_avatar_name_cache_toast, +			_1, _2, msg));  }  void LLIMModel::setActiveSessionID(const LLUUID& session_id) @@ -269,7 +274,7 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES  		// no text notifications  		break;  	case P2P_SESSION: -		gCacheName->getFullName(mOtherParticipantID, other_avatar_name); +		gCacheName->getFullName(mOtherParticipantID, other_avatar_name); // voice  		if(direction == LLVoiceChannel::INCOMING_CALL)  		{ @@ -404,13 +409,17 @@ void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& histo  		const LLSD& msg = *it;  		std::string from = msg[IM_FROM]; -		LLUUID from_id = LLUUID::null; -		if (msg[IM_FROM_ID].isUndefined()) +		LLUUID from_id; +		if (msg[IM_FROM_ID].isDefined())  		{ +			from_id = msg[IM_FROM_ID].asUUID(); +		} +		else +		{ +			// Legacy chat logs only wrote the legacy name, not the agent_id  			gCacheName->getUUID(from, from_id);  		} -  		std::string timestamp = msg[IM_TIME];  		std::string text = msg[IM_TEXT]; @@ -631,7 +640,7 @@ bool LLIMModel::clearSession(const LLUUID& session_id)  void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)  {  	LLIMSession* session = findIMSession(session_id); -	if (!session) +	if (!session)   	{  		llwarns << "session " << session_id << "does not exist " << llendl;  		return; @@ -639,7 +648,7 @@ void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& m  	int i = session->mMsgs.size() - start_index; -	for (std::list<LLSD>::iterator iter = session->mMsgs.begin(); +	for (std::list<LLSD>::iterator iter = session->mMsgs.begin();   		iter != session->mMsgs.end() && i > 0;  		iter++)  	{ @@ -1750,11 +1759,23 @@ void LLOutgoingCallDialog::show(const LLSD& key)  		callee_name = LLTextUtil::formatPhoneNumber(callee_name);  	} -	setTitle(callee_name); -  	LLSD callee_id = mPayload["other_user_id"]; -	childSetTextArg("calling", "[CALLEE_NAME]", callee_name); -	childSetTextArg("connecting", "[CALLEE_NAME]", callee_name); +	// Beautification:  Since you know who you called, just show display name +	std::string title = callee_name; +	std::string final_callee_name = callee_name; +	if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) +	{ +		LLAvatarName av_name; +		if (LLAvatarNameCache::get(callee_id, &av_name)) +		{ +			final_callee_name = av_name.mDisplayName; +			title = av_name.getCompleteName(); +		} +	} +	childSetTextArg("calling", "[CALLEE_NAME]", final_callee_name); +	childSetTextArg("connecting", "[CALLEE_NAME]", final_callee_name); + +	setTitle(title);  	// for outgoing group calls callee_id == group id == session id  	setIcon(callee_id, callee_id); @@ -1909,16 +1930,21 @@ BOOL LLIncomingCallDialog::postBuild()  	if (caller_name == "anonymous")  	{  		caller_name = getString("anonymous"); +		setCallerName(caller_name, caller_name, call_type);  	}  	else if (!is_avatar)  	{  		caller_name = LLTextUtil::formatPhoneNumber(caller_name); +		setCallerName(caller_name, caller_name, call_type); +	} +	else +	{ +		// Get the full name information +		LLAvatarNameCache::get(caller_id, +			boost::bind(&LLIncomingCallDialog::onAvatarNameCache, +				this, _1, _2, call_type));  	} -	setTitle(caller_name + " " + call_type); - -	LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name"); -	caller_name_widget->setValue(caller_name + " " + call_type);  	setIcon(session_id, caller_id);  	childSetAction("Accept", onAccept, this); @@ -1946,6 +1972,24 @@ BOOL LLIncomingCallDialog::postBuild()  	return TRUE;  } +void LLIncomingCallDialog::setCallerName(const std::string& ui_title, +										 const std::string& ui_label, +										 const std::string& call_type) +{ +	setTitle(ui_title); + +	// call_type may be a string like " is calling." +	LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name"); +	caller_name_widget->setValue(ui_label + " " + call_type); +} + +void LLIncomingCallDialog::onAvatarNameCache(const LLUUID& agent_id, +											 const LLAvatarName& av_name, +											 const std::string& call_type) +{ +	std::string title = av_name.getCompleteName(); +	setCallerName(title, av_name.mDisplayName, call_type); +}  void LLIncomingCallDialog::onOpen(const LLSD& key)  { @@ -2053,8 +2097,11 @@ void LLIncomingCallDialog::processCallResponse(S32 response)  					}  					else  					{ -						if (gCacheName->getFullName(caller_id, correct_session_name)) +						// *NOTE: really should be using callbacks here +						LLAvatarName av_name; +						if (LLAvatarNameCache::get(caller_id, &av_name))  						{ +							correct_session_name = av_name.mDisplayName + " (" + av_name.mUsername + ")";  							correct_session_name.append(ADHOC_NAME_SUFFIX);   						}  					} @@ -2575,7 +2622,8 @@ void LLIMMgr::inviteToSession(  	{  		if (caller_name.empty())  		{ -			gCacheName->get(caller_id, FALSE, boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2, _3, _4)); +			gCacheName->get(caller_id, false,  // voice +				boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2, _3));  		}  		else  		{ @@ -2585,9 +2633,9 @@ void LLIMMgr::inviteToSession(  	}  } -void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& name, bool is_group)  { -	payload["caller_name"] = first + " " + last; +	payload["caller_name"] = name;  	payload["session_name"] = payload["caller_name"].asString();  	std::string notify_box_type = payload["notify_box_type"].asString(); @@ -2808,13 +2856,14 @@ void LLIMMgr::noteOfflineUsers(  		for(S32 i = 0; i < count; ++i)  		{  			info = at.getBuddyInfo(ids.get(i)); -			std::string first, last; -			if(info && !info->isOnline() -			   && gCacheName->getName(ids.get(i), first, last)) +			LLAvatarName av_name; +			if (info +				&& !info->isOnline() +				&& LLAvatarNameCache::get(ids.get(i), &av_name))  			{  				LLUIString offline = LLTrans::getString("offline_message"); -				offline.setArg("[FIRST]", first); -				offline.setArg("[LAST]", last); +				// Use display name only because this user is your friend +				offline.setArg("[NAME]", av_name.mDisplayName);  				im_model.proccessOnlineOfflineNotification(session_id, offline);  			}  		} diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index ffa8a16797..c132ac328f 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -41,7 +41,7 @@  #include "llvoicechannel.h" - +class LLAvatarName;  class LLFriendObserver;  class LLCallDialogManager;	  class LLIMSpeakerMgr; @@ -458,7 +458,7 @@ private:  	void processIMTypingCore(const LLIMInfo* im_info, BOOL typing); -	static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); +	static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& name, bool is_group);  	void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);  	void notifyObserverSessionRemoved(const LLUUID& session_id); @@ -540,6 +540,13 @@ public:  	static void onStartIM(void* user_data);  private: +	void setCallerName(const std::string& ui_title, +		const std::string& ui_label, +		const std::string& call_type); +	void onAvatarNameCache(const LLUUID& agent_id, +		const LLAvatarName& av_name, +		const std::string& call_type); +  	/*virtual*/ void onLifetimeExpired();  	void processCallResponse(S32 response);  }; diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index d9fdc876db..1cd1dcc7f0 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -37,6 +37,7 @@  #include "llagent.h"  #include "llagentdata.h"  #include "llavataractions.h" +#include "llavatarnamecache.h"  #include "llavatarpropertiesprocessor.h"  #include "llcallingcard.h"  #include "lldateutil.h" @@ -143,17 +144,13 @@ private:  	// Is used to determine if "Add friend" option should be enabled in gear menu  	bool isNotFriend(); -	// Callback for gCacheName to look up avatar name -	void nameUpdatedCallback( -							 const LLUUID& id, -							 const std::string& first, -							 const std::string& last, -							 BOOL is_group); +	void onAvatarNameCache(const LLUUID& agent_id, +						   const LLAvatarName& av_name);  private:  	LLUUID				mAvatarID;  	// Need avatar name information to spawn friend add request -	std::string			mAvatarName; +	LLAvatarName		mAvatarName;  	// an in-flight request for avatar properties from LLAvatarPropertiesProcessor  	// is represented by this object  	LLFetchAvatarData*	mPropertiesRequest; @@ -336,6 +333,7 @@ void LLInspectAvatar::requestUpdate()  	// Clear out old data so it doesn't flash between old and new  	getChild<LLUICtrl>("user_name")->setValue(""); +	getChild<LLUICtrl>("user_slid")->setValue("");  	getChild<LLUICtrl>("user_subtitle")->setValue("");  	getChild<LLUICtrl>("user_details")->setValue(""); @@ -373,9 +371,9 @@ void LLInspectAvatar::requestUpdate()  	childSetValue("avatar_icon", LLSD(mAvatarID) ); -	gCacheName->get(mAvatarID, FALSE, -		boost::bind(&LLInspectAvatar::nameUpdatedCallback, -			this, _1, _2, _3, _4)); +	LLAvatarNameCache::get(mAvatarID, +			boost::bind(&LLInspectAvatar::onAvatarNameCache, +				this, _1, _2));  }  void LLInspectAvatar::processAvatarData(LLAvatarData* data) @@ -562,7 +560,7 @@ void LLInspectAvatar::updateVolumeSlider()  		LLUICtrl* mute_btn = getChild<LLUICtrl>("mute_btn"); -		bool is_linden = LLStringUtil::endsWith(mAvatarName, " Linden"); +		bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");  		mute_btn->setEnabled( !is_linden);  		mute_btn->setValue( is_muted ); @@ -593,7 +591,7 @@ void LLInspectAvatar::onClickMuteVolume()  	LLMuteList* mute_list = LLMuteList::getInstance();  	bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat); -	LLMute mute(mAvatarID, mAvatarName, LLMute::AGENT); +	LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT);  	if (!is_muted)  	{  		mute_list->add(mute, LLMute::flagVoiceChat); @@ -612,22 +610,21 @@ void LLInspectAvatar::onVolumeChange(const LLSD& data)  	LLVoiceClient::getInstance()->setUserVolume(mAvatarID, volume);  } -void LLInspectAvatar::nameUpdatedCallback( -	const LLUUID& id, -	const std::string& first, -	const std::string& last, -	BOOL is_group) +void LLInspectAvatar::onAvatarNameCache( +		const LLUUID& agent_id, +		const LLAvatarName& av_name)  { -	if (id == mAvatarID) +	if (agent_id == mAvatarID)  	{ -		mAvatarName = first + " " + last; -		childSetValue("user_name", LLSD(mAvatarName) ); +		getChild<LLUICtrl>("user_name")->setValue(av_name.mDisplayName); +		getChild<LLUICtrl>("user_slid")->setValue(av_name.mUsername); +		mAvatarName = av_name;  	}  }  void LLInspectAvatar::onClickAddFriend()  { -	LLAvatarActions::requestFriendshipDialog(mAvatarID, mAvatarName); +	LLAvatarActions::requestFriendshipDialog(mAvatarID, mAvatarName.getLegacyName());  	closeFloater();  } @@ -695,7 +692,7 @@ void LLInspectAvatar::onClickShare()  void LLInspectAvatar::onToggleMute()  { -	LLMute mute(mAvatarID, mAvatarName, LLMute::AGENT); +	LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT);  	if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))  	{ @@ -712,7 +709,7 @@ void LLInspectAvatar::onToggleMute()  void LLInspectAvatar::onClickReport()  { -	LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName); +	LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName.getCompleteName());  	closeFloater();  } @@ -736,17 +733,17 @@ void LLInspectAvatar::onClickZoomIn()  void LLInspectAvatar::onClickFindOnMap()  { -	gFloaterWorldMap->trackAvatar(mAvatarID, mAvatarName); +	gFloaterWorldMap->trackAvatar(mAvatarID, mAvatarName.mDisplayName);  	LLFloaterReg::showInstance("world_map");  }  bool LLInspectAvatar::enableMute()  { -		bool is_linden = LLStringUtil::endsWith(mAvatarName, " Linden"); +		bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");  		bool is_self = mAvatarID == gAgent.getID(); -		if (!is_linden && !is_self && !LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName)) +		if (!is_linden && !is_self && !LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getLegacyName()))  		{  			return true;  		} @@ -758,10 +755,10 @@ bool LLInspectAvatar::enableMute()  bool LLInspectAvatar::enableUnmute()  { -		bool is_linden = LLStringUtil::endsWith(mAvatarName, " Linden"); +		bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");  		bool is_self = mAvatarID == gAgent.getID(); -		if (!is_linden && !is_self && LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName)) +		if (!is_linden && !is_self && LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getLegacyName()))  		{  			return true;  		} diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp index 7fd7b69021..fa1640c4c7 100644 --- a/indra/newview/llinspectgroup.cpp +++ b/indra/newview/llinspectgroup.cpp @@ -84,9 +84,8 @@ public:  	// Callback for gCacheName to look up group name  	// Faster than waiting for group properties to return  	void nameUpdatedCallback(const LLUUID& id, -							 const std::string& first, -							 const std::string& last, -							 BOOL is_group); +							 const std::string& name, +							 bool is_group);  	// Button/menu callbacks  	void onClickViewProfile(); @@ -225,21 +224,19 @@ void LLInspectGroup::requestUpdate()  	mPropertiesRequest = new LLFetchGroupData(mGroupID, this);  	// Name lookup will be faster out of cache, use that -	gCacheName->get(mGroupID, TRUE, +	gCacheName->getGroup(mGroupID,  		boost::bind(&LLInspectGroup::nameUpdatedCallback, -			this, _1, _2, _3, _4)); +			this, _1, _2, _3));  }  void LLInspectGroup::nameUpdatedCallback(  	const LLUUID& id, -	const std::string& first, -	const std::string& last, -	BOOL is_group) +	const std::string& name, +	bool is_group)  {  	if (id == mGroupID)  	{ -		// group names are returned as a first name -		childSetValue("group_name", LLSD(first) ); +		childSetValue("group_name", LLSD(name) );  	}  	// Otherwise possibly a request for an older inspector, ignore it diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index be021df363..5fb918c1aa 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -66,12 +66,12 @@ public:  private:  	void update(); -	static void nameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data); +	void onNameCache(const LLUUID& id, const std::string& name, bool is_group);  private:  	LLUUID		 mObjectID;  	LLUUID		 mOwnerID; -	std::string  mOwner; +	std::string  mOwnerLegacyName;  	std::string  mSLurl;  	std::string  mName;  	bool         mGroupOwned; @@ -81,7 +81,7 @@ LLInspectRemoteObject::LLInspectRemoteObject(const LLSD& sd) :  	LLInspect(LLSD()),  	mObjectID(NULL),  	mOwnerID(NULL), -	mOwner(""), +	mOwnerLegacyName(),  	mSLurl(""),  	mName(""),  	mGroupOwned(false) @@ -118,10 +118,11 @@ void LLInspectRemoteObject::onOpen(const LLSD& data)  	mSLurl      = data["slurl"].asString();  	// work out the owner's name -	mOwner = ""; +	mOwnerLegacyName = "";  	if (gCacheName)  	{ -		gCacheName->get(mOwnerID, mGroupOwned, nameCallback, this); +		gCacheName->get(mOwnerID, mGroupOwned,  // muting +			boost::bind(&LLInspectRemoteObject::onNameCache, this, _1, _2, _3));  	}  	// update the inspector with the current object state @@ -150,7 +151,7 @@ void LLInspectRemoteObject::onClickMap()  void LLInspectRemoteObject::onClickBlock()  {  	LLMute::EType mute_type = mGroupOwned ? LLMute::GROUP : LLMute::AGENT; -	LLMute mute(mOwnerID, mOwner, mute_type); +	LLMute mute(mOwnerID, mOwnerLegacyName, mute_type);  	LLMuteList::getInstance()->add(mute);  	LLPanelBlockedList::showPanelAndSelect(mute.mID);  	closeFloater(); @@ -161,16 +162,10 @@ void LLInspectRemoteObject::onClickClose()  	closeFloater();  } -//static  -void LLInspectRemoteObject::nameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data) +void LLInspectRemoteObject::onNameCache(const LLUUID& id, const std::string& name, bool is_group)  { -	LLInspectRemoteObject *self = (LLInspectRemoteObject*)data; -	self->mOwner = first; -	if (!last.empty()) -	{ -		self->mOwner += " " + last; -	} -	self->update(); +	mOwnerLegacyName = name; +	update();  }  void LLInspectRemoteObject::update() @@ -180,7 +175,7 @@ void LLInspectRemoteObject::update()  	getChild<LLUICtrl>("object_name")->setValue("<nolink>" + mName + "</nolink>");  	// show the object's owner - click it to show profile -	std::string owner = mOwner; +	std::string owner;  	if (! mOwnerID.isNull())  	{  		if (mGroupOwned) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 38f3521b2d..301fff2e2b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -35,6 +35,7 @@  // external projects  #include "lltransfersourceasset.h" +#include "llavatarnamecache.h"	// IDEVO  #include "llagent.h"  #include "llagentcamera.h" @@ -3450,6 +3451,13 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act  		{  			std::string callingcard_name;  			gCacheName->getFullName(item->getCreatorUUID(), callingcard_name); +			// IDEVO +			LLAvatarName av_name; +			if (LLAvatarNameCache::useDisplayNames() +				&& LLAvatarNameCache::get(item->getCreatorUUID(), &av_name)) +			{ +				callingcard_name = av_name.mDisplayName + " (" + av_name.mUsername + ")"; +			}  			LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID());  			if (session_id != LLUUID::null)  			{ diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index be8b2363ad..d4ebdd768b 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,13 +32,18 @@  #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> @@ -62,12 +67,13 @@  const S32 LOG_RECALL_SIZE = 2048; -const static std::string IM_TIME("time"); -const static std::string IM_TEXT("message"); -const static std::string IM_FROM("from"); -const static std::string IM_FROM_ID("from_id"); -const static std::string IM_SEPARATOR(": "); +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");  const static std::string NEW_LINE_SPACE_PREFIX("\n ");  const static std::string TWO_SPACES("  "); @@ -190,7 +196,8 @@ std::string LLLogChat::makeLogFileName(std::string filename)  {  	filename = cleanFileName(filename);  	filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS,filename); -	filename += ".txt"; +	// new files are llsd notation format +	filename += ".llsd";  	return filename;  } @@ -240,6 +247,18 @@ 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()) @@ -260,89 +279,27 @@ void LLLogChat::saveHistory(const std::string& filename,  	LLSD item;  	if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) -		 item["time"] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")); +		 item[IM_TIME] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")); -	item["from_id"]	= from_id; -	item["message"]	= line; +	item[IM_FROM_ID] = chat.mFromID; +	item[IM_TEXT] = chat.mText; +	item[IM_SOURCE_TYPE] = chat.mSourceType;  	//adding "Second Life:" for all system messages to make chat log history parsing more reliable -	if (from.empty() && from_id.isNull()) +	if (chat.mFromName.empty() && chat.mFromID.isNull())  	{ -		item["from"] = SYSTEM_FROM;  +		item[IM_FROM] = SYSTEM_FROM;   	}  	else  	{ -		item["from"] = from; +		item[IM_FROM] = chat.mFromName;  	} -	file << LLChatLogFormatter(item) << std::endl; +	file << LLSDOStreamer<LLSDNotationFormatter>(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; @@ -352,6 +309,7 @@ void append_to_last_message(std::list<LLSD>& messages, const std::string& line)  	messages.back()[IM_TEXT] = im_text;  } +// static  void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& messages)  {  	if (file_name.empty()) @@ -415,53 +373,25 @@ void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& me  	fclose(fptr);  } -//*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 (!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; -	} - -	//*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; -		} -	} -	 -	if (im[IM_TEXT].isDefined()) -	{ -		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) +// static +bool LLChatLogParser::parse(const std::string& raw, LLSD& im)  {  	if (!raw.length()) return false;  	im = LLSD::emptyMap(); +	// In Viewer 2.1 we added UUID to chat/IM logging so we can look up +	// display names +	if (raw[0] == '{') +	{ +		// ...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); +	} +  	//matching a timestamp  	boost::match_results<std::string::const_iterator> matches;  	if (!boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 4290e4bbc0..674f27407e 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -30,10 +30,11 @@   * $/LicenseInfo$   */ -  #ifndef LL_LLLOGCHAT_H  #define LL_LLLOGCHAT_H +class LLChat; +  class LLLogChat  {  public: @@ -46,49 +47,22 @@ 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 @@ -106,11 +80,18 @@ public:  	 *  	 * @return false if failed to parse mandatory data - message text  	 */ -	static bool parse(std::string& raw, LLSD& im); +	static bool parse(const std::string& raw, LLSD& im);  protected:  	LLChatLogParser();  	virtual ~LLChatLogParser() {};  }; +// LLSD map lookup constants +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/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index ae8efc01a3..2a55a134d8 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -143,6 +143,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia  	requested_options.append("initial-outfit");  	requested_options.append("gestures"); +	requested_options.append("display_names");  	requested_options.append("event_categories");  	requested_options.append("event_notifications");  	requested_options.append("classified_categories"); diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 7cb192e026..7126914260 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -118,9 +118,8 @@ LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags)  		LLNameValue* lastname = mute_object->getNVPair("LastName");  		if (firstname && lastname)  		{ -			mName.assign( firstname->getString() ); -			mName.append(" "); -			mName.append( lastname->getString() ); +			mName = LLCacheName::buildFullName( +				firstname->getString(), lastname->getString());  		}  		mType = mute_object->isAvatar() ? AGENT : OBJECT;  	} @@ -416,7 +415,7 @@ void LLMuteList::updateRemove(const LLMute& mute)  	gAgent.sendReliableMessage();  } -void notify_automute_callback(const LLUUID& agent_id, const std::string& first_name, const std::string& last_name, BOOL is_group, LLMuteList::EAutoReason reason) +void notify_automute_callback(const LLUUID& agent_id, const std::string& full_name, bool is_group, LLMuteList::EAutoReason reason)  {  	std::string notif_name;  	switch (reason) @@ -434,8 +433,7 @@ void notify_automute_callback(const LLUUID& agent_id, const std::string& first_n  	}  	LLSD args; -	args["FIRST"] = first_name; -	args["LAST"] = last_name; +	args["NAME"] = full_name;  	LLNotificationPtr notif_ptr = LLNotifications::instance().add(notif_name, args, LLSD());  	if (notif_ptr) @@ -450,7 +448,7 @@ void notify_automute_callback(const LLUUID& agent_id, const std::string& first_n  } -BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason, const std::string& first_name, const std::string& last_name) +BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason)  {  	BOOL removed = FALSE; @@ -460,24 +458,17 @@ BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason, co  		removed = TRUE;  		remove(automute); -		if (first_name.empty() && last_name.empty()) -		{ -			std::string cache_first, cache_last; -			if (gCacheName->getName(agent_id, cache_first, cache_last)) +		std::string full_name; +		if (gCacheName->getFullName(agent_id, full_name))  			{  				// name in cache, call callback directly -				notify_automute_callback(agent_id, cache_first, cache_last, FALSE, reason); +			notify_automute_callback(agent_id, full_name, false, reason);  			}  			else  			{  				// not in cache, lookup name from cache -				gCacheName->get(agent_id, FALSE, boost::bind(¬ify_automute_callback, _1, _2, _3, _4, reason)); -			} -		} -		else -		{ -			// call callback directly -			notify_automute_callback(agent_id, first_name, last_name, FALSE, reason); +			gCacheName->get(agent_id, false, +				boost::bind(¬ify_automute_callback, _1, _2, _3, reason));  		}  	} diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index 79b556bdbb..ad4fd2345d 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -69,7 +69,7 @@ public:  public:  	LLUUID		mID;	// agent or object id -	std::string	mName;	// agent or object name +	std::string	mName;	// agent or object name, does not store last name "Resident"  	EType		mType;	// needed for UI display of existing mutes  	U32			mFlags;	// flags pertaining to this mute entry  }; @@ -102,7 +102,7 @@ public:  	// Remove both normal and legacy mutes, for any or all properties.  	BOOL remove(const LLMute& mute, U32 flags = 0); -	BOOL autoRemove(const LLUUID& agent_id, const EAutoReason reason, const std::string& first_name = LLStringUtil::null, const std::string& last_name = LLStringUtil::null); +	BOOL autoRemove(const LLUUID& agent_id, const EAutoReason reason);  	// Name is required to test against legacy text-only mutes.  	BOOL isMuted(const LLUUID& id, const std::string& name = LLStringUtil::null, U32 flags = 0) const; diff --git a/indra/newview/llnamebox.cpp b/indra/newview/llnamebox.cpp index cd810b9793..da3e95e947 100644 --- a/indra/newview/llnamebox.cpp +++ b/indra/newview/llnamebox.cpp @@ -87,26 +87,15 @@ void LLNameBox::setNameID(const LLUUID& name_id, BOOL is_group)  		setText(mInitialValue);  } -void LLNameBox::refresh(const LLUUID& id, const std::string& firstname, -						const std::string& lastname, BOOL is_group) +void LLNameBox::refresh(const LLUUID& id, const std::string& full_name, bool is_group)  {  	if (id == mNameID)  	{ -		std::string name; -		if (!is_group) -		{ -			name = firstname + " " + lastname; -		} -		else -		{ -			name = firstname; -		} -		setName(name, is_group); +		setName(full_name, is_group);  	}  } -void LLNameBox::refreshAll(const LLUUID& id, const std::string& firstname, -						   const std::string& lastname, BOOL is_group) +void LLNameBox::refreshAll(const LLUUID& id, const std::string& full_name, bool is_group)  {  	std::set<LLNameBox*>::iterator it;  	for (it = LLNameBox::sInstances.begin(); @@ -114,7 +103,7 @@ void LLNameBox::refreshAll(const LLUUID& id, const std::string& firstname,  		 ++it)  	{  		LLNameBox* box = *it; -		box->refresh(id, firstname, lastname, is_group); +		box->refresh(id, full_name, is_group);  	}  } diff --git a/indra/newview/llnamebox.h b/indra/newview/llnamebox.h index 48b54faec8..2fe8990653 100644 --- a/indra/newview/llnamebox.h +++ b/indra/newview/llnamebox.h @@ -59,10 +59,9 @@ public:  	void setNameID(const LLUUID& name_id, BOOL is_group); -	void refresh(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); +	void refresh(const LLUUID& id, const std::string& full_name, bool is_group); -	static void refreshAll(const LLUUID& id, const std::string& firstname, -						   const std::string& lastname, BOOL is_group); +	static void refreshAll(const LLUUID& id, const std::string& full_name, bool is_group);  protected:  	LLNameBox (const Params&); diff --git a/indra/newview/llnameeditor.cpp b/indra/newview/llnameeditor.cpp index 65601da7da..0c704a1f56 100644 --- a/indra/newview/llnameeditor.cpp +++ b/indra/newview/llnameeditor.cpp @@ -81,26 +81,15 @@ void LLNameEditor::setNameID(const LLUUID& name_id, BOOL is_group)  	setText(name);  } -void LLNameEditor::refresh(const LLUUID& id, const std::string& firstname, -						   const std::string& lastname, BOOL is_group) +void LLNameEditor::refresh(const LLUUID& id, const std::string& full_name, bool is_group)  {  	if (id == mNameID)  	{ -		std::string name; -		if (!is_group) -		{ -			name = firstname + " " + lastname; -		} -		else -		{ -			name = firstname; -		} -		setText(name); +		setText(full_name);  	}  } -void LLNameEditor::refreshAll(const LLUUID& id, const std::string& firstname, -							  const std::string& lastname, BOOL is_group) +void LLNameEditor::refreshAll(const LLUUID& id, const std::string& full_name, bool is_group)  {  	std::set<LLNameEditor*>::iterator it;  	for (it = LLNameEditor::sInstances.begin(); @@ -108,7 +97,7 @@ void LLNameEditor::refreshAll(const LLUUID& id, const std::string& firstname,  		 ++it)  	{  		LLNameEditor* box = *it; -		box->refresh(id, firstname, lastname, is_group); +		box->refresh(id, full_name, is_group);  	}  } diff --git a/indra/newview/llnameeditor.h b/indra/newview/llnameeditor.h index 99e03a1166..a75c492aca 100644 --- a/indra/newview/llnameeditor.h +++ b/indra/newview/llnameeditor.h @@ -65,10 +65,9 @@ public:  	void setNameID(const LLUUID& name_id, BOOL is_group); -	void refresh(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); +	void refresh(const LLUUID& id, const std::string& full_name, bool is_group); -	static void refreshAll(const LLUUID& id, const std::string& firstname, -						   const std::string& lastname, BOOL is_group); +	static void refreshAll(const LLUUID& id, const std::string& full_name, bool is_group);  	// Take/return agent UUIDs diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index d09f729943..fd0359368d 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -36,6 +36,7 @@  #include <boost/tokenizer.hpp> +#include "llavatarnamecache.h"  #include "llcachename.h"  #include "llfloaterreg.h"  #include "llinventory.h" @@ -44,6 +45,7 @@  #include "llscrolllistcolumn.h"  #include "llsdparam.h"  #include "lltooltip.h" +#include "lltrans.h"  static LLDefaultChildRegistry::Register<LLNameListCtrl> r("name_list"); @@ -58,7 +60,8 @@ void LLNameListCtrl::NameTypeNames::declareValues()  LLNameListCtrl::Params::Params()  :	name_column(""), -	allow_calling_card_drop("allow_calling_card_drop", false) +	allow_calling_card_drop("allow_calling_card_drop", false), +	short_names("short_names", false)  {  	name = "name_list";  } @@ -67,7 +70,8 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p)  :	LLScrollListCtrl(p),  	mNameColumnIndex(p.name_column.column_index),  	mNameColumn(p.name_column.column_name), -	mAllowCallingCardDrop(p.allow_calling_card_drop) +	mAllowCallingCardDrop(p.allow_calling_card_drop), +	mShortNames(p.short_names)  {}  // public @@ -297,10 +301,24 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(  		break;  	case INDIVIDUAL:  		{ -			std::string name; -			if (gCacheName->getFullName(id, name)) +			LLAvatarName av_name; +			if (id.isNull())  			{ -				fullname = name; +				fullname = LLTrans::getString("AvatarNameNobody"); +			} +			else if (LLAvatarNameCache::get(id, &av_name)) +			{ +				if (mShortNames) +					fullname = av_name.mDisplayName; +				else +					fullname = av_name.getCompleteName(); +			} +			else +			{ +				// ...schedule a callback +				LLAvatarNameCache::get(id, +					boost::bind(&LLNameListCtrl::onAvatarNameCache, +						this, _1, _2));  			}  			break;  		} @@ -355,34 +373,25 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id)  	}  } -// public -void LLNameListCtrl::refresh(const LLUUID& id, const std::string& first,  -							 const std::string& last, BOOL is_group) +void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, +									   const LLAvatarName& av_name)  { -	//llinfos << "LLNameListCtrl::refresh " << id << " '" << first << " " -	//	<< last << "'" << llendl; - -	std::string fullname; -	if (!is_group) -	{ -		fullname = first + " " + last; -	} +	std::string name; +	if (mShortNames) +		name = av_name.mDisplayName;  	else -	{ -		fullname = first; -	} +		name = av_name.getCompleteName(); -	// TODO: scan items for that ID, fix if necessary  	item_list::iterator iter;  	for (iter = getItemList().begin(); iter != getItemList().end(); iter++)  	{  		LLScrollListItem* item = *iter; -		if (item->getUUID() == id) +		if (item->getUUID() == agent_id)  		{  			LLScrollListCell* cell = item->getColumn(mNameColumnIndex);  			if (cell)  			{ -				cell->setValue(fullname); +				cell->setValue(name);  			}  		}  	} @@ -391,19 +400,6 @@ void LLNameListCtrl::refresh(const LLUUID& id, const std::string& first,  } -// static -void LLNameListCtrl::refreshAll(const LLUUID& id, const std::string& first, -								const std::string& last, BOOL is_group) -{ -	LLInstanceTrackerScopedGuard guard; -	LLInstanceTracker<LLNameListCtrl>::instance_iter it; -	for (it = guard.beginInstances(); it != guard.endInstances(); ++it) -	{ -		LLNameListCtrl& ctrl = *it; -		ctrl.refresh(id, first, last, is_group); -	} -} -  void LLNameListCtrl::updateColumns()  {  	LLScrollListCtrl::updateColumns(); diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index ee71db7540..64f595968c 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -37,6 +37,7 @@  #include "llscrolllistctrl.h" +class LLAvatarName;  class LLNameListCtrl  :	public LLScrollListCtrl, protected LLInstanceTracker<LLNameListCtrl> @@ -80,6 +81,7 @@ public:  	{  		Optional<NameColumn>	name_column;  		Optional<bool>	allow_calling_card_drop; +		Optional<bool>			short_names;  		Params();  	}; @@ -105,11 +107,6 @@ public:  	void removeNameItem(const LLUUID& agent_id); -	void refresh(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); - -	static void refreshAll(const LLUUID& id, const std::string& firstname, -						   const std::string& lastname, BOOL is_group); -  	// LLView interface  	/*virtual*/ BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask,  									  BOOL drop, EDragAndDropType cargo_type, void *cargo_data, @@ -124,11 +121,13 @@ public:  	/*virtual*/ void	mouseOverHighlightNthItem( S32 index );  private:  	void showInspector(const LLUUID& avatar_id, bool is_group); +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);  private:  	S32    			mNameColumnIndex;  	std::string		mNameColumn;  	BOOL			mAllowCallingCardDrop; +	bool			mShortNames;  // display name only, no SLID  };  /** diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 1beaaf3cb4..525c648555 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -61,12 +61,6 @@  static const S32 RESIZE_BAR_THICKNESS = 3; -const static std::string IM_TIME("time"); -const static std::string IM_TEXT("message"); -const static std::string IM_FROM("from"); -const static std::string IM_FROM_ID("from_id"); - -  LLNearbyChat::LLNearbyChat(const LLSD& key)   	: LLDockableFloater(NULL, false, false, key)  	,mChatHistory(NULL) @@ -191,7 +185,7 @@ void	LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args)  	if (gSavedPerAccountSettings.getBOOL("LogNearbyChat"))  	{ -		LLLogChat::saveHistory("chat", chat.mFromName, chat.mFromID, chat.mText); +		LLLogChat::saveHistory("chat", chat);  	}  } @@ -281,8 +275,12 @@ void LLNearbyChat::loadHistory()  		const LLSD& msg = *it;  		std::string from = msg[IM_FROM]; -		LLUUID from_id = LLUUID::null; -		if (msg[IM_FROM_ID].isUndefined()) +		LLUUID from_id; +		if (msg[IM_FROM_ID].isDefined()) +		{ +			from_id = msg[IM_FROM_ID].asUUID(); +		} +		else  		{  			gCacheName->getUUID(from, from_id);  		} @@ -294,11 +292,14 @@ void LLNearbyChat::loadHistory()  		chat.mTimeStr = msg[IM_TIME].asString();  		chat.mChatStyle = CHAT_STYLE_HISTORY; -		chat.mSourceType = CHAT_SOURCE_AGENT; -		if (from_id.isNull() && SYSTEM_FROM == from) +		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_SYSTEM; -			  		}  		else if (from_id.isNull())  		{ diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index a8dee8a24a..67b238ad58 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -37,6 +37,7 @@  // Library includes (should move below)  #include "indra_constants.h" +#include "llavatarnamecache.h"  #include "llmath.h"  #include "llfloaterreg.h"  #include "llfocusmgr.h" @@ -555,11 +556,14 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )  	// mToolTipMsg = "[AGENT][REGION](Double-click to open Map)" +	bool have_agent = false;  	LLStringUtil::format_map_t args; -	std::string fullname; -	if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, fullname)) +	LLAvatarName av_name; +	if(mClosestAgentToCursor.notNull() +	   && LLAvatarNameCache::get(mClosestAgentToCursor, &av_name))  	{ -		args["[AGENT]"] = fullname + "\n"; +		args["[AGENT]"] = av_name.getCompleteName() + "\n"; +		have_agent = true;  	}  	else  	{ @@ -567,7 +571,7 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )  	}  	LLViewerRegion*	region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); -	if( region ) +	if( region && !have_agent)  	{  		args["[REGION]"] = region->getName() + "\n";  	} diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 95b946f307..deb0cb6cfa 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -113,8 +113,11 @@ void LLSysHandler::removeExclusiveNotifications(const LLNotificationPtr& notif)  }  const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"), -		REVOKED_MODIFY_RIGHTS("RevokedModifyRights"), OBJECT_GIVE_ITEM( -				"ObjectGiveItem"), PAYMENT_RECIVED("PaymentRecived"), +		REVOKED_MODIFY_RIGHTS("RevokedModifyRights"), +		OBJECT_GIVE_ITEM("ObjectGiveItem"), +		OBJECT_GIVE_ITEM_UNKNOWN_USER("ObjectGiveItemUnknownUser"), +						PAYMENT_RECEIVED("PaymentReceived"), +						PAYMENT_SENT("PaymentSent"),  						ADD_FRIEND_WITH_MESSAGE("AddFriendWithMessage"),  						USER_GIVE_ITEM("UserGiveItem"),  						INVENTORY_ACCEPTED("InventoryAccepted"), @@ -136,7 +139,8 @@ bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification)  {  	return GRANTED_MODIFY_RIGHTS == notification->getName()  			|| REVOKED_MODIFY_RIGHTS == notification->getName() -			|| PAYMENT_RECIVED == notification->getName() +			|| PAYMENT_RECEIVED == notification->getName() +			|| PAYMENT_SENT == notification->getName()  			|| OFFER_FRIENDSHIP == notification->getName()  			|| FRIENDSHIP_OFFERED == notification->getName()  			|| FRIENDSHIP_ACCEPTED == notification->getName() @@ -317,34 +321,35 @@ void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification)  	logToIMP2P(notification, false);  } +void log_name_callback(const std::string& full_name, const std::string& from_name,  +					   const std::string& message, const LLUUID& from_id) + +{ +	LLHandlerUtil::logToIM(IM_NOTHING_SPECIAL, full_name, from_name, message, +					from_id, LLUUID()); +} +  // static  void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only)  { -	const std::string name = LLHandlerUtil::getSubstitutionName(notification); - -	const std::string& session_name = notification->getPayload().has( -			"SESSION_NAME") ? notification->getPayload()["SESSION_NAME"].asString() : name; -  	// don't create IM p2p session with objects, it's necessary condition to log  	if (notification->getName() != OBJECT_GIVE_ITEM)  	{  		LLUUID from_id = notification->getPayload()["from_id"]; -		//there still appears a log history file with weird name " .txt" -		if (" " == session_name || "{waiting}" == session_name || "{nobody}" == session_name) +		if (from_id.isNull())  		{ -			llwarning("Weird session name (" + session_name + ") for notification " + notification->getName(), 666) +			llwarns << " from_id for notification " << notification->getName() << " is null " << llendl; +			return;  		}  		if(to_file_only)  		{ -			logToIM(IM_NOTHING_SPECIAL, session_name, "", notification->getMessage(), -					LLUUID(), LLUUID()); +			gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, "", notification->getMessage(), LLUUID()));  		}  		else  		{ -			logToIM(IM_NOTHING_SPECIAL, session_name, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), -					from_id, LLUUID()); +			gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), from_id));  		}  	}  } diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 534bb6e3fc..40e7522b9b 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -50,7 +50,7 @@  #include "llfloaterreg.h"  #include "llnotificationsutil.h"  #include "llvoiceclient.h" -#include "llnamebox.h" +#include "lltextbox.h"  #include "lltrans.h"  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -224,13 +224,8 @@ void LLPanelAvatarNotes::rightsConfirmationCallback(const LLSD& notification,  void LLPanelAvatarNotes::confirmModifyRights(bool grant, S32 rights)  { -	std::string first, last;  	LLSD args; -	if (gCacheName->getName(getAvatarId(), first, last)) -	{ -		args["FIRST_NAME"] = first; -		args["LAST_NAME"] = last; -	} +	args["NAME"] = LLSLURL("agent", getAvatarId(), "displayname").getSLURLString();  	if (grant)  	{ @@ -568,8 +563,7 @@ void LLPanelAvatarProfile::resetData()  	childSetValue("homepage_edit",LLStringUtil::null);  	childSetValue("register_date",LLStringUtil::null);  	childSetValue("acc_status_text",LLStringUtil::null); -	childSetTextArg("partner_text", "[FIRST]", LLStringUtil::null); -	childSetTextArg("partner_text", "[LAST]", LLStringUtil::null); +	childSetValue("partner_text", LLStringUtil::null);  }  void LLPanelAvatarProfile::processProperties(void* data, EAvatarProcessorType type) @@ -660,15 +654,14 @@ void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)  void LLPanelAvatarProfile::fillPartnerData(const LLAvatarData* avatar_data)  { -	LLNameBox* name_box = getChild<LLNameBox>("partner_text"); +	LLTextBox* partner_text = getChild<LLTextBox>("partner_text");  	if (avatar_data->partner_id.notNull())  	{ -		name_box->setNameID(avatar_data->partner_id, FALSE); +		partner_text->setText(LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString());  	}  	else  	{ -		name_box->setNameID(LLUUID::null, FALSE); -		name_box->setText(getString("no_partner_text")); +		partner_text->setText(getString("no_partner_text"));  	}  } diff --git a/indra/newview/llpanelavatartag.cpp b/indra/newview/llpanelavatartag.cpp index 7563cc7f61..173fb851ce 100644 --- a/indra/newview/llpanelavatartag.cpp +++ b/indra/newview/llpanelavatartag.cpp @@ -86,7 +86,7 @@ void LLPanelAvatarTag::setAvatarId(const LLUUID& avatar_id)  	{  		mIcon->setValue(avatar_id);  	} -	setName(std::string(mIcon->getFirstName()+ " "+ mIcon->getLastName())); +	setName(std::string(mIcon->getFullName()));  }  boost::signals2::connection LLPanelAvatarTag::setLeftButtonClickCallback( diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp index c72f0f8012..c3c0af6d9e 100644 --- a/indra/newview/llpanelblockedlist.cpp +++ b/indra/newview/llpanelblockedlist.cpp @@ -35,6 +35,7 @@  #include "llpanelblockedlist.h"  // library include +#include "llavatarname.h"  #include "llfloater.h"  #include "llfloaterreg.h"  #include "llnotificationsutil.h" @@ -186,10 +187,10 @@ void LLPanelBlockedList::onBlockByNameClick()  	LLFloaterGetBlockedObjectName::show(&LLPanelBlockedList::callbackBlockByName);  } -void LLPanelBlockedList::callbackBlockPicked(const std::vector<std::string>& names, const uuid_vec_t& ids) +void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)  {  	if (names.empty() || ids.empty()) return; -	LLMute mute(ids[0], names[0], LLMute::AGENT); +	LLMute mute(ids[0], names[0].getLegacyName(), LLMute::AGENT);  	LLMuteList::getInstance()->add(mute);  	showPanelAndSelect(mute.mID);  } diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h index a100577e43..88c1edb1f8 100644 --- a/indra/newview/llpanelblockedlist.h +++ b/indra/newview/llpanelblockedlist.h @@ -42,7 +42,8 @@  // class LLLineEditor;  // class LLMessageSystem;  // class LLUUID; - class LLScrollListCtrl; +class LLAvatarName; +class LLScrollListCtrl;  class LLPanelBlockedList  	:	public LLPanel, public LLMuteListObserver @@ -78,7 +79,7 @@ private:  	void onPickBtnClick();  	void onBlockByNameClick(); -	void callbackBlockPicked(const std::vector<std::string>& names, const uuid_vec_t& ids); +	void callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);  	static void callbackBlockByName(const std::string& text);  private: diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 8e1b7ba4d9..61781eafb1 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -46,7 +46,6 @@  #include "llavataractions.h"  #include "llgroupactions.h"  #include "lllineeditor.h" -#include "llnamebox.h"  #include "llnamelistctrl.h"  #include "llnotificationsutil.h"  #include "llscrolllistitem.h" @@ -213,7 +212,7 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group)  	{  		mInsignia->setCommitCallback(onCommitAny, this);  	} -	mFounderName = getChild<LLNameBox>("founder_name"); +	mFounderName = getChild<LLTextBox>("founder_name");  	mGroupNameEditor = panel_group->getChild<LLLineEditor>("group_name_editor"); @@ -648,7 +647,7 @@ void LLPanelGroupGeneral::update(LLGroupChange gc)  	if (mEditCharter) mEditCharter->setEnabled(mAllowEdit && can_change_ident);  	if (mGroupNameEditor) mGroupNameEditor->setVisible(FALSE); -	if (mFounderName) mFounderName->setNameID(gdatap->mFounderID,FALSE); +	if (mFounderName) mFounderName->setText(LLSLURL("agent", gdatap->mFounderID, "inspect").getSLURLString());  	if (mInsignia)  	{  		if (gdatap->mInsigniaID.notNull()) diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h index 6f4fa994da..066c002634 100644 --- a/indra/newview/llpanelgroupgeneral.h +++ b/indra/newview/llpanelgroupgeneral.h @@ -43,7 +43,6 @@ class LLButton;  class LLNameListCtrl;  class LLCheckBoxCtrl;  class LLComboBox; -class LLNameBox;  class LLSpinCtrl;  class LLPanelGroupGeneral : public LLPanelGroupTab @@ -98,7 +97,7 @@ private:  	// Group information (include any updates in updateChanged)  	LLLineEditor		*mGroupNameEditor; -	LLNameBox			*mFounderName; +	LLTextBox			*mFounderName;  	LLTextureCtrl		*mInsignia;  	LLTextEditor		*mEditCharter; diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index 11d3768a3d..a28e0c2123 100644 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -34,6 +34,7 @@  #include "llpanelgroupinvite.h"  #include "llagent.h" +#include "llavatarnamecache.h"  #include "llfloateravatarpicker.h"  #include "llbutton.h"  #include "llcallingcard.h" @@ -68,9 +69,13 @@ public:  	static void callbackClickAdd(void* userdata);  	static void callbackClickRemove(void* userdata);  	static void callbackSelect(LLUICtrl* ctrl, void* userdata); -	static void callbackAddUsers(const std::vector<std::string>& names, -								 const uuid_vec_t& agent_ids, +	static void callbackAddUsers(const uuid_vec_t& agent_ids,  								 void* user_data); +	 +	static void onAvatarNameCache(const LLUUID& agent_id, +											 const LLAvatarName& av_name, +											 void* user_data); +  	bool inviteOwnerCallback(const LLSD& notification, const LLSD& response);  public: @@ -293,7 +298,7 @@ void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata)  		LLFloater* parentp;  		parentp = gFloaterView->getParentFloater(panelp); -		parentp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(impl::callbackAddUsers, _1, _2, +		parentp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(impl::callbackAddUsers, _1,  																panelp->mImplementation),  																 TRUE));  	} @@ -359,16 +364,38 @@ void LLPanelGroupInvite::impl::callbackClickOK(void* userdata)  	if ( selfp ) selfp->submitInvitations();  } + +  //static -void LLPanelGroupInvite::impl::callbackAddUsers(const std::vector<std::string>& names, -												const uuid_vec_t& ids, -												void* user_data) +void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data) +{	 +	std::vector<std::string> names; +	for (S32 i = 0; i < (S32)agent_ids.size(); i++) +	{ +		LLAvatarNameCache::get(agent_ids[i], +			boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, _1, _2, user_data)); +	}	 +	 +} + +void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id, +											 const LLAvatarName& av_name, +											 void* user_data)  {  	impl* selfp = (impl*) user_data; -	if ( selfp) selfp->addUsers(names, ids); +	if (selfp) +	{ +		std::vector<std::string> names; +		uuid_vec_t agent_ids; +		agent_ids.push_back(agent_id); +		names.push_back(av_name.getCompleteName()); +		 +		selfp->addUsers(names, agent_ids); +	}  } +  LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id)  	: LLPanel(),  	  mImplementation(new impl(group_id)), @@ -404,16 +431,18 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)  	std::vector<std::string> names;  	for (S32 i = 0; i < (S32)agent_ids.size(); i++)  	{ +		std::string fullname;  		LLUUID agent_id = agent_ids[i];  		LLViewerObject* dest = gObjectList.findObject(agent_id); -		std::string fullname;  		if(dest && dest->isAvatar())  		{  			LLNameValue* nvfirst = dest->getNVPair("FirstName");  			LLNameValue* nvlast = dest->getNVPair("LastName");  			if(nvfirst && nvlast)  			{ -				fullname = std::string(nvfirst->getString()) + " " + std::string(nvlast->getString()); +				fullname = LLCacheName::buildFullName( +					nvfirst->getString(), nvlast->getString()); +  			}  			if (!fullname.empty())  			{ @@ -436,8 +465,7 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)  				{  					// actually it should happen, just in case  					gCacheName->get(LLUUID(agent_id), false, boost::bind( -							&LLPanelGroupInvite::addUserCallback, this, _1, _2, -							_3)); +							&LLPanelGroupInvite::addUserCallback, this, _1, _2));  					// for this special case!  					//when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence  					// removed id will be added in callback @@ -453,16 +481,16 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)  	mImplementation->addUsers(names, agent_ids);  } -void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const std::string& first_name, const std::string& last_name) +void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const std::string& full_name)  {  	std::vector<std::string> names;  	uuid_vec_t agent_ids; -	std::string full_name = first_name + " " + last_name;  	agent_ids.push_back(id); -	names.push_back(first_name + " " + last_name); +	names.push_back(full_name);  	mImplementation->addUsers(names, agent_ids);  } +  void LLPanelGroupInvite::draw()  {  	LLPanel::draw(); diff --git a/indra/newview/llpanelgroupinvite.h b/indra/newview/llpanelgroupinvite.h index 2ed443ed46..520107c33a 100644 --- a/indra/newview/llpanelgroupinvite.h +++ b/indra/newview/llpanelgroupinvite.h @@ -46,7 +46,7 @@ public:  	/**  	 * this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers().  	 */   -	void addUserCallback(const LLUUID& id, const std::string& first_name, const std::string& last_name); +	void addUserCallback(const LLUUID& id, const std::string& full_name);  	void clear();  	void update(); diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index ba50081fb2..18a38880ef 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -36,6 +36,7 @@  #include "llview.h" +#include "llavatarnamecache.h"  #include "llinventory.h"  #include "llviewerinventory.h"  #include "llinventorydefines.h" @@ -546,6 +547,12 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg)  		msg->getU8("Data","AssetType",asset_type,i);  		msg->getU32("Data","Timestamp",timestamp,i); +		// we only have the legacy name here, convert it to a username +		if (LLAvatarNameCache::useDisplayNames()) +		{ +			name = LLCacheName::buildUsername(name); +		} +  		LLSD row;  		row["id"] = id; diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 7a28d10baf..76883fe173 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1116,11 +1116,7 @@ void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, c  		for (uuid_vec_t::const_iterator i = selected_members.begin(); i != selected_members.end(); ++i)  		{  			LLSD args; -			std::string name; -			 -			gCacheName->getFullName(*i, name); - -			args["AVATAR_NAME"] = name; +			args["AVATAR_NAME"] = LLSLURL("agent", *i, "displayname").getSLURLString();  			args["GROUP_NAME"] = group_data->mName;  			LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index b79a4f359a..88b8ff324c 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -186,7 +186,7 @@ void LLPanelIMControlPanel::onViewProfileButtonClicked()  void LLPanelIMControlPanel::onAddFriendButtonClicked()  {  	LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon"); -	std::string full_name = avatar_icon->getFirstName() + " " + avatar_icon->getLastName(); +	std::string full_name = avatar_icon->getFullName();  	LLAvatarActions::requestFriendshipDialog(mAvatarID, full_name);  } @@ -237,6 +237,15 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id)  		childSetEnabled("share_btn", FALSE);  		childSetEnabled("teleport_btn", FALSE);  		childSetEnabled("pay_btn", FALSE); + +        getChild<LLTextBox>("avatar_name")->setValue(im_session->mName); +        getChild<LLTextBox>("avatar_name")->setToolTip(im_session->mName); +	} +	else +	{ +		// If the participant is an avatar, fetch the currect name +		gCacheName->get(mAvatarID, false, +			boost::bind(&LLPanelIMControlPanel::onNameCache, this, _1, _2, _3));  	}  } @@ -252,6 +261,16 @@ void LLPanelIMControlPanel::changed(U32 mask)  	}  } +void LLPanelIMControlPanel::onNameCache(const LLUUID& id, const std::string& full_name, bool is_group) +{ +	if ( id == mAvatarID ) +	{ +		std::string avatar_name = full_name; +		getChild<LLTextBox>("avatar_name")->setValue(avatar_name); +		getChild<LLTextBox>("avatar_name")->setToolTip(avatar_name); +	} +} +  LLPanelGroupControlPanel::LLPanelGroupControlPanel(const LLUUID& session_id):  mParticipantList(NULL)  { diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h index 0a1fd70c08..4594a0d021 100644 --- a/indra/newview/llpanelimcontrolpanel.h +++ b/indra/newview/llpanelimcontrolpanel.h @@ -89,6 +89,9 @@ public:  	// LLFriendObserver trigger  	virtual void changed(U32 mask); +protected: +	void onNameCache(const LLUUID& id, const std::string& full_name, bool is_group); +  private:  	void onViewProfileButtonClicked();  	void onAddFriendButtonClicked(); diff --git a/indra/newview/llpanellandmarkinfo.cpp b/indra/newview/llpanellandmarkinfo.cpp index 4ffd43cb0f..f6c70c82da 100644 --- a/indra/newview/llpanellandmarkinfo.cpp +++ b/indra/newview/llpanellandmarkinfo.cpp @@ -45,6 +45,7 @@  #include "llagent.h"  #include "llagentui.h"  #include "lllandmarkactions.h" +#include "llslurl.h"  #include "llviewerinventory.h"  #include "llviewerparcelmgr.h"  #include "llviewerregion.h" @@ -231,13 +232,10 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem)  	//////////////////  	if (pItem->getCreatorUUID().notNull())  	{ -		std::string name; +		// IDEVO  		LLUUID creator_id = pItem->getCreatorUUID(); -		if (!gCacheName->getFullName(creator_id, name)) -		{ -			gCacheName->get(creator_id, FALSE, -							boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mCreator, _2, _3)); -		} +		std::string name = +			LLSLURL("agent", creator_id, "inspect").getSLURLString();  		mCreator->setText(name);  	}  	else @@ -254,20 +252,12 @@ void LLPanelLandmarkInfo::displayItemInfo(const LLInventoryItem* pItem)  		if (perm.isGroupOwned())  		{  			LLUUID group_id = perm.getGroup(); -			if (!gCacheName->getGroupName(group_id, name)) -			{ -				gCacheName->get(group_id, TRUE, -								boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mOwner, _2, _3)); -			} +			name = LLSLURL("group", group_id, "inspect").getSLURLString();  		}  		else  		{  			LLUUID owner_id = perm.getOwner(); -			if (!gCacheName->getFullName(owner_id, name)) -			{ -				gCacheName->get(owner_id, FALSE, -								boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mOwner, _2, _3)); -			} +			name = LLSLURL("agent", owner_id, "inspect").getSLURLString();  		}  		mOwner->setText(name);  	} diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 144839b554..d5c640ad25 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -211,7 +211,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	}  #if !USE_VIEWER_AUTH -	childSetPrevalidate("username_edit", LLTextValidate::validateASCIIPrintableNoPipe);  	getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);  	// change z sort of clickable text to be behind buttons @@ -514,8 +513,16 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential,  	LLSD identifier = credential->getIdentifier();  	if((std::string)identifier["type"] == "agent")   	{ -		sInstance->childSetText("username_edit", (std::string)identifier["first_name"] + " " +  -								(std::string)identifier["last_name"]);	 +		std::string firstname = identifier["first_name"].asString(); +		std::string lastname = identifier["last_name"].asString(); +	    std::string login_id = firstname; +	    if (!lastname.empty() && lastname != "Resident") +	    { +		    // support traditional First Last name SLURLs +		    login_id += " "; +		    login_id += lastname; +	    } +		sInstance->childSetText("username_edit", login_id);	  	}  	else if((std::string)identifier["type"] == "account")  	{ @@ -579,7 +586,8 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,  	LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL;  	// determine if the username is a first/last form or not.  	size_t separator_index = username.find_first_of(' '); -	if (separator_index == username.npos) +	if (separator_index == username.npos +		&& !LLGridManager::getInstance()->isSystemGrid())  	{  		LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL;  		// single username, so this is a 'clear' identifier @@ -596,9 +604,23 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,  	}  	else  	{ +		// Be lenient in terms of what separators we allow for two-word names +		// and allow legacy users to login with firstname.lastname +		separator_index = username.find_first_of(" ._");  		std::string first = username.substr(0, separator_index); -		std::string last = username.substr(separator_index, username.npos); +		std::string last; +		if (separator_index != username.npos) +		{ +			last = username.substr(separator_index+1, username.npos);  		LLStringUtil::trim(last); +		} +		else +		{ +			// ...on Linden grids, single username users as considered to have +			// last name "Resident" +			// *TODO: Make login.cgi support "account_name" like above +			last = "Resident"; +		}  		if (last.find_first_of(' ') == last.npos)  		{ diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp index 3f620869e0..5e8e07b962 100644 --- a/indra/newview/llpanelme.cpp +++ b/indra/newview/llpanelme.cpp @@ -32,17 +32,25 @@  #include "llviewerprecompiledheaders.h" +#include "llpanelme.h" + +// Viewer includes  #include "llpanelprofile.h"  #include "llavatarconstants.h" -#include "llpanelme.h"  #include "llagent.h"  #include "llagentcamera.h"  #include "llagentwearables.h" -#include "lliconctrl.h"  #include "llsidetray.h" +#include "llviewercontrol.h" +#include "llviewerdisplayname.h" + +// Linden libraries +#include "llavatarnamecache.h"		// IDEVO +#include "lliconctrl.h" +#include "llnotifications.h" +#include "llnotificationsutil.h"	// IDEVO  #include "lltabcontainer.h"  #include "lltexturectrl.h" -#include "llviewercontrol.h"  #define PICKER_SECOND_LIFE "2nd_life_pic"  #define PICKER_FIRST_LIFE "real_world_pic" @@ -180,6 +188,13 @@ void LLPanelMyProfileEdit::onOpen(const LLSD& key)  	// Disable editing until data is loaded, or edited fields will be overwritten when data  	// is loaded.  	enableEditing(false); + +	// Only allow changing name if this region/grid supports it +	bool use_display_names = LLAvatarNameCache::useDisplayNames(); +	LLUICtrl* set_name = getChild<LLUICtrl>("set_name"); +	set_name->setVisible(use_display_names); +	set_name->setEnabled(use_display_names); +  	LLPanelMyProfile::onOpen(getAvatarId());  } @@ -213,13 +228,14 @@ void LLPanelMyProfileEdit::processProfileProperties(const LLAvatarData* avatar_d  	childSetValue("show_in_search_checkbox", (BOOL)(avatar_data->flags & AVATAR_ALLOW_PUBLISH)); -	std::string first, last; -	BOOL found = gCacheName->getName(avatar_data->avatar_id, first, last); -	if (found) -	{ -		childSetTextArg("name_text", "[FIRST]", first); -		childSetTextArg("name_text", "[LAST]", last); -	} +	LLAvatarNameCache::get(avatar_data->avatar_id, +		boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2)); +} + +void LLPanelMyProfileEdit::onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ +	getChild<LLUICtrl>("user_name")->setValue( av_name.mDisplayName ); +	getChild<LLUICtrl>("user_slid")->setValue( av_name.mUsername );  }  BOOL LLPanelMyProfileEdit::postBuild() @@ -229,6 +245,9 @@ BOOL LLPanelMyProfileEdit::postBuild()  	childSetTextArg("partner_edit_link", "[URL]", getString("partner_edit_link_url"));  	childSetTextArg("my_account_link", "[URL]", getString("my_account_link_url")); +	getChild<LLUICtrl>("set_name")->setCommitCallback( +		boost::bind(&LLPanelMyProfileEdit::onClickSetName, this)); +  	return LLPanelAvatarProfile::postBuild();  }  /** @@ -256,8 +275,10 @@ void LLPanelMyProfileEdit::resetData()  {  	LLPanelMyProfile::resetData(); -	childSetTextArg("name_text", "[FIRST]", LLStringUtil::null); -	childSetTextArg("name_text", "[LAST]", LLStringUtil::null); +	//childSetTextArg("name_text", "[FIRST]", LLStringUtil::null); +	//childSetTextArg("name_text", "[LAST]", LLStringUtil::null); +	getChild<LLUICtrl>("user_name")->setValue( LLSD() ); +	getChild<LLUICtrl>("user_slid")->setValue( LLSD() );  }  void LLPanelMyProfileEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl) @@ -269,6 +290,144 @@ void LLPanelMyProfileEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl)  	mTextureEditIconMap[ctrl->getName()]->setVisible(FALSE);  } +void LLPanelMyProfileEdit::onCacheSetName(bool success, +										  const std::string& reason, +										  const LLSD& content) +{ +	if (success) +	{ +		// Inform the user that the change took place, but will take a while +		// to percolate. +		LLSD args; +		args["DISPLAY_NAME"] = content["display_name"]; +		LLNotificationsUtil::add("SetDisplayNameSuccess", args); + +		// Re-fetch my name, as it may have been sanitized by the service +		LLAvatarNameCache::get(getAvatarId(), +			boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2)); +		return; +	} + +	// Request failed, notify the user +	std::string error_tag = content["error_tag"].asString(); +	llinfos << "set name failure error_tag " << error_tag << llendl; + +	// We might have a localized string for this message +	// error_args will usually be empty from the server. +	if (!error_tag.empty() +		&& LLNotifications::getInstance()->templateExists(error_tag)) +	{ +		LLNotificationsUtil::add(error_tag); +		return; +	} + +	// The server error might have a localized message for us +	std::string lang_code = LLUI::getLanguage(); +	LLSD error_desc = content["error_description"]; +	if (error_desc.has( lang_code )) +	{ +		LLSD args; +		args["MESSAGE"] = error_desc[lang_code].asString(); +		LLNotificationsUtil::add("GenericAlert", args); +		return; +	} + +	// No specific error, throw a generic one +	LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); +} + +void LLPanelMyProfileEdit::onDialogSetName(const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	if (option == 0 || option == 1) +	{ +		LLUUID agent_id = notification["payload"]["agent_id"]; +		if (agent_id.isNull()) return; + +		std::string display_name_utf8; +		if (option == 0) +		{ +			// user gave us a name +			display_name_utf8 = response["display_name"].asString(); +		} +		else +		{ +			// reset back to People API default +			display_name_utf8 = ""; +		} + +		const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes +		LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8); +		if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH) +		{ +			LLSD args; +			args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH); +			LLNotificationsUtil::add("SetDisplayNameFailedLength", args); +			return; +		} + +		LLViewerDisplayName::set(display_name_utf8, +			boost::bind(&LLPanelMyProfileEdit::onCacheSetName, this, +				_1, _2, _3)); +	} +} + +void LLPanelMyProfileEdit::onClickSetName() +{ +	LLUUID agent_id = getAvatarId(); +	std::string display_name; +	LLAvatarName av_name; +	if (!LLAvatarNameCache::get(agent_id, &av_name)) +	{ +		// something is wrong, tell user to try again later +		LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); +		return; +	} +		 +	display_name = av_name.mDisplayName; +	if (display_name.empty()) +	{ +		// something is wrong, tell user to try again later +		LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); +		return;		 +	} + +	llinfos << "name-change now " << LLDate::now() << " next_update " +		<< LLDate(av_name.mNextUpdate) << llendl; +	F64 now_secs = LLDate::now().secondsSinceEpoch(); + +	if (now_secs < av_name.mNextUpdate) +	{ +		// if the update time is more than a year in the future, it means updates have been blocked +		// show a more general message +        const int YEAR = 60*60*24*365;  +		if (now_secs + YEAR < av_name.mNextUpdate) +		{ +			LLNotificationsUtil::add("SetDisplayNameBlocked"); +			return; +		} +	 +		// ...can't update until some time in the future +		F64 next_update_local_secs = +			av_name.mNextUpdate - LLStringOps::getLocalTimeOffset(); +		LLDate next_update_local(next_update_local_secs); +		// display as "July 18 12:17 PM" +		std::string next_update_string = +		next_update_local.toHTTPDateString("%B %d %I:%M %p"); +		LLSD args; +		args["TIME"] = next_update_string; +		LLNotificationsUtil::add("SetDisplayNameFailedLockout", args); +		return; +	} +	 +	LLSD args; +	args["DISPLAY_NAME"] = display_name; +	LLSD payload; +	payload["agent_id"] = agent_id; +	LLNotificationsUtil::add("SetDisplayName", args, payload,  +		boost::bind(&LLPanelMyProfileEdit::onDialogSetName, this, _1, _2)); +} +  void LLPanelMyProfileEdit::enableEditing(bool enable)  {  	childSetEnabled("2nd_life_pic", enable); diff --git a/indra/newview/llpanelme.h b/indra/newview/llpanelme.h index f2b38de3d6..f3caf026dc 100644 --- a/indra/newview/llpanelme.h +++ b/indra/newview/llpanelme.h @@ -34,8 +34,9 @@  #define LL_LLPANELMEPROFILE_H  #include "llpanel.h" -#include "llpanelavatar.h" +#include "llpanelprofile.h" +class LLAvatarName;  class LLPanelMyProfileEdit;  class LLPanelProfile;  class LLIconCtrl; @@ -89,11 +90,15 @@ protected:  	/*virtual*/void resetData();  	void processProfileProperties(const LLAvatarData* avatar_data); +	void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);  private:  	void initTexturePickerMouseEvents();  	void onTexturePickerMouseEnter(LLUICtrl* ctrl);  	void onTexturePickerMouseLeave(LLUICtrl* ctrl); +	void onClickSetName(); +	void onDialogSetName(const LLSD& notification, const LLSD& response); +	void onCacheSetName(bool success, const std::string& reason, const LLSD& content);  	/**  	 * Enabled/disables controls to prevent overwriting edited data upon receiving diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp index e5caaaaffc..227dbb3da7 100644 --- a/indra/newview/llpanelmediasettingspermissions.cpp +++ b/indra/newview/llpanelmediasettingspermissions.cpp @@ -115,7 +115,7 @@ void LLPanelMediaSettingsPermissions::draw()  		if(mPermsGroupName)  		{  			mPermsGroupName->setNameID(LLUUID::null, TRUE); -			mPermsGroupName->refresh(LLUUID::null, LLStringUtil::null, LLStringUtil::null, true); +			mPermsGroupName->refresh(LLUUID::null, std::string(), true);  			mPermsGroupName->setEnabled(false);  		};  	}; @@ -194,7 +194,7 @@ void LLPanelMediaSettingsPermissions::initValues( void* userdata, const LLSD& me              data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );          };      }; -	 +  	// *NOTE: If any of a particular flavor is tentative, we have to disable   	// them all because of an architectural issue: namely that we represent   	// these as a bit field, and we can't selectively apply only one bit to all selected @@ -238,21 +238,21 @@ void LLPanelMediaSettingsPermissions::getValues( LLSD &fill_me_in, bool include_  {  	// moved over from the 'General settings' tab  	if (include_tentative || !mControls->getTentative()) fill_me_in[LLMediaEntry::CONTROLS_KEY] = (LLSD::Integer)mControls->getCurrentIndex(); -	 -	// *NOTE: For some reason, gcc does not like these symbol references in the  -	// expressions below (inside the static_casts).	 I have NO idea why :(. -	// For some reason, assigning them to const temp vars here fixes the link -	// error.  Bizarre. -	const U8 none = LLMediaEntry::PERM_NONE; -	const U8 owner = LLMediaEntry::PERM_OWNER; -	const U8 group = LLMediaEntry::PERM_GROUP; -	const U8 anyone = LLMediaEntry::PERM_ANYONE;  -	const LLSD::Integer control = static_cast<LLSD::Integer>( + +    // *NOTE: For some reason, gcc does not like these symbol references in the  +    // expressions below (inside the static_casts).  I have NO idea why :(. +    // For some reason, assigning them to const temp vars here fixes the link +    // error.  Bizarre. +    const U8 none = LLMediaEntry::PERM_NONE; +    const U8 owner = LLMediaEntry::PERM_OWNER; +    const U8 group = LLMediaEntry::PERM_GROUP; +    const U8 anyone = LLMediaEntry::PERM_ANYONE; +    const LLSD::Integer control = static_cast<LLSD::Integer>(  		(mPermsOwnerControl->getValue() ? owner : none ) |  		(mPermsGroupControl->getValue() ? group: none  ) |  		(mPermsWorldControl->getValue() ? anyone : none )); -	const LLSD::Integer interact = static_cast<LLSD::Integer>( -		(mPermsOwnerInteract->getValue() ? owner: none	) | +    const LLSD::Integer interact = static_cast<LLSD::Integer>( +		(mPermsOwnerInteract->getValue() ? owner: none  ) |  		(mPermsGroupInteract->getValue() ? group : none ) |  		(mPermsWorldInteract->getValue() ? anyone : none )); @@ -266,15 +266,15 @@ void LLPanelMediaSettingsPermissions::getValues( LLSD &fill_me_in, bool include_  		!mPermsGroupControl->getTentative() ||   		!mPermsWorldControl->getTentative())  	{ -		fill_me_in[LLMediaEntry::PERMS_CONTROL_KEY] = control; +    fill_me_in[LLMediaEntry::PERMS_CONTROL_KEY] = control;  	}  	if (include_tentative ||   		!mPermsOwnerInteract->getTentative() ||   		!mPermsGroupInteract->getTentative() ||   		!mPermsWorldInteract->getTentative())  	{ -		fill_me_in[LLMediaEntry::PERMS_INTERACT_KEY] = interact; -	} +    fill_me_in[LLMediaEntry::PERMS_INTERACT_KEY] = interact; +}  } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 6dd800c0c6..08f412721d 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -33,6 +33,7 @@  #include "llviewerprecompiledheaders.h"  // libs +#include "llavatarname.h"  #include "llfloaterreg.h"  #include "llmenugl.h"  #include "llnotificationsutil.h" @@ -1161,12 +1162,10 @@ void LLPanelPeople::onActivateButtonClicked()  }  // static -void LLPanelPeople::onAvatarPicked( -		const std::vector<std::string>& names, -		const uuid_vec_t& ids) +void LLPanelPeople::onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)  {  	if (!names.empty() && !ids.empty()) -		LLAvatarActions::requestFriendshipDialog(ids[0], names[0]); +		LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName());  }  void LLPanelPeople::onGroupPlusButtonClicked() diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 17c45a034b..54b53fc12c 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -38,10 +38,11 @@  #include "llcallingcard.h" // for avatar tracker  #include "llvoiceclient.h" -class LLFilterEditor; -class LLTabContainer;  class LLAvatarList; +class LLAvatarName; +class LLFilterEditor;  class LLGroupList; +class LLTabContainer;  class LLPanelPeople   	: public LLPanel @@ -133,9 +134,7 @@ private:  	bool					onNearbyViewSortMenuItemCheck(const LLSD& userdata);  	// misc callbacks -	static void				onAvatarPicked( -								const std::vector<std::string>& names, -								const uuid_vec_t& ids); +	static void				onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);  	void					onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list); diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index 71d16a08b4..6bac4ae196 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -385,7 +385,7 @@ void LLPanelPermissions::refresh()  		if (mLabelGroupName)  		{  			mLabelGroupName->setNameID(LLUUID::null, TRUE); -			mLabelGroupName->refresh(LLUUID::null,LLStringUtil::null, LLStringUtil::null, TRUE); +			mLabelGroupName->refresh(LLUUID::null, std::string(), true);  			mLabelGroupName->setEnabled(FALSE);  		}  	} diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index bde8d02885..291da5fdd2 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -235,9 +235,9 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type)  		LLAvatarPicks* avatar_picks = static_cast<LLAvatarPicks*>(data);  		if(avatar_picks && getAvatarId() == avatar_picks->target_id)  		{ -			std::string name, second_name; -			gCacheName->getName(getAvatarId(),name,second_name); -			childSetTextArg("pick_title", "[NAME]",name); +			std::string full_name; +			gCacheName->getFullName(getAvatarId(), full_name); +			childSetTextArg("pick_title", "[NAME]", full_name);  			// Save selection, to be able to edit same item after saving changes. See EXT-3023.  			LLUUID selected_id = mPicksList->getSelectedValue()[PICK_ID]; diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 99e48cca6d..73f71bd47e 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -34,6 +34,7 @@  #include "llpanelplaceinfo.h" +#include "llavatarname.h"  #include "llsdutil.h"  #include "llsdutil_math.h" @@ -292,9 +293,15 @@ void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit*  }  // static -void LLPanelPlaceInfo::nameUpdatedCallback(LLTextBox* text, -										   const std::string& first, -										   const std::string& last) +void LLPanelPlaceInfo::onNameCache(LLTextBox* text, const std::string& full_name)  { -	text->setText(first + " " + last); +	text->setText(full_name); +} + +// static +void LLPanelPlaceInfo::onAvatarNameCache(const LLUUID& agent_id, +										 const LLAvatarName& av_name, +										 LLTextBox* text) +{ +	text->setText( av_name.getCompleteName() );  } diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index deedbd2b0f..0c08c5059b 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -40,6 +40,7 @@  #include "llremoteparcelrequest.h" +class LLAvatarName;  class LLExpandableTextBox;  class LLIconCtrl;  class LLInventoryItem; @@ -102,9 +103,10 @@ public:  	void createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel);  protected: -	static void nameUpdatedCallback(LLTextBox* text, -									const std::string& first, -									const std::string& last); +	static void onNameCache(LLTextBox* text, const std::string& full_name); +	static void onAvatarNameCache(const LLUUID& agent_id, +								  const LLAvatarName& av_name, +								  LLTextBox* text);  	/**  	 * mParcelID is valid only for remote places, in other cases it's null. See resetLocation()  diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp index 08835dc2b8..b39a13c4e4 100644 --- a/indra/newview/llpanelplaceprofile.cpp +++ b/indra/newview/llpanelplaceprofile.cpp @@ -34,6 +34,7 @@  #include "llpanelplaceprofile.h" +#include "llavatarnamecache.h"  #include "llparcel.h"  #include "message.h" @@ -51,6 +52,7 @@  #include "llappviewer.h"  #include "llcallbacklist.h"  #include "llbuycurrencyhtml.h" +#include "llslurl.h"  #include "llstatusbar.h"  #include "llviewercontrol.h"  #include "llviewerparcelmgr.h" @@ -436,11 +438,11 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,  			if(!parcel->getGroupID().isNull())  			{  				// FIXME: Using parcel group as region group. -				gCacheName->get(parcel->getGroupID(), TRUE, -								boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mRegionGroupText, _2, _3)); +				gCacheName->getGroup(parcel->getGroupID(), +								boost::bind(&LLPanelPlaceInfo::onNameCache, mRegionGroupText, _2)); -				gCacheName->get(parcel->getGroupID(), TRUE, -								boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mParcelOwner, _2, _3)); +				gCacheName->getGroup(parcel->getGroupID(), +								boost::bind(&LLPanelPlaceInfo::onNameCache, mParcelOwner, _2));  			}  			else  			{ @@ -452,10 +454,12 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,  		else  		{  			// Figure out the owner's name -			gCacheName->get(parcel->getOwnerID(), FALSE, -							boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mParcelOwner, _2, _3)); -			gCacheName->get(region->getOwner(), FALSE, -							boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mRegionOwnerText, _2, _3)); +			std::string parcel_owner = +				LLSLURL("agent", parcel->getOwnerID(), "inspect").getSLURLString(); +			mParcelOwner->setText(parcel_owner); +			LLAvatarNameCache::get(region->getOwner(), +								   boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, +											   _1, _2, mRegionOwnerText));  		}  		if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus()) @@ -477,9 +481,10 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,  		const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();  		if(auth_buyer_id.notNull())  		{ -			gCacheName->get(auth_buyer_id, TRUE, -							boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, mSaleToText, _2, _3)); - +			LLAvatarNameCache::get(auth_buyer_id, +								   boost::bind(&LLPanelPlaceInfo::onAvatarNameCache, +											   _1, _2, mSaleToText)); +			  			// Show sales info to a specific person or a group he belongs to.  			if (auth_buyer_id != gAgent.getID() && !gAgent.isInGroup(auth_buyer_id))  			{ diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index f1aa3f10f8..be5b440050 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -33,7 +33,6 @@  #ifndef LL_LLPANELPROFILE_H  #define LL_LLPANELPROFILE_H -#include "llviewerprecompiledheaders.h"  #include "llpanel.h"  #include "llpanelavatar.h" diff --git a/indra/newview/llpanelprofileview.cpp b/indra/newview/llpanelprofileview.cpp index 044036ea50..d22d8d2718 100644 --- a/indra/newview/llpanelprofileview.cpp +++ b/indra/newview/llpanelprofileview.cpp @@ -32,11 +32,12 @@  #include "llviewerprecompiledheaders.h" +#include "llpanelprofileview.h" +  #include "llavatarconstants.h" +#include "llavatarnamecache.h"	// IDEVO  #include "lluserrelations.h" -#include "llpanelprofileview.h" -  #include "llavatarpropertiesprocessor.h"  #include "llcallingcard.h"  #include "llpanelavatar.h" @@ -104,11 +105,15 @@ void LLPanelProfileView::onOpen(const LLSD& key)  	if(id.notNull() && getAvatarId() != id)  	{  		setAvatarId(id); + +		// clear name fields, which might have old data +		getChild<LLUICtrl>("user_name")->setValue( LLSD() ); +		getChild<LLUICtrl>("user_slid")->setValue( LLSD() );  	}  	// Update the avatar name. -	gCacheName->get(getAvatarId(), FALSE, -		boost::bind(&LLPanelProfileView::onAvatarNameCached, this, _1, _2, _3, _4)); +	LLAvatarNameCache::get(getAvatarId(), +		boost::bind(&LLPanelProfileView::onAvatarNameCache, this, _1, _2));  	updateOnlineStatus(); @@ -198,10 +203,11 @@ void LLPanelProfileView::processOnlineStatus(bool online)  	mStatusText->setValue(status);  } -void LLPanelProfileView::onAvatarNameCached(const LLUUID& id, const std::string& first_name, const std::string& last_name, BOOL is_group) +void LLPanelProfileView::onAvatarNameCache(const LLUUID& agent_id, +										   const LLAvatarName& av_name)  { -	llassert(getAvatarId() == id); -	getChild<LLUICtrl>("user_name", FALSE)->setValue(first_name + " " + last_name); +	getChild<LLUICtrl>("user_name")->setValue( av_name.mDisplayName ); +	getChild<LLUICtrl>("user_slid")->setValue( av_name.mUsername );  }  // EOF diff --git a/indra/newview/llpanelprofileview.h b/indra/newview/llpanelprofileview.h index 9b87e146a8..dedb617c27 100644 --- a/indra/newview/llpanelprofileview.h +++ b/indra/newview/llpanelprofileview.h @@ -39,6 +39,7 @@  #include "llagent.h"  #include "lltooldraganddrop.h" +class LLAvatarName;  class LLPanelProfile;  class LLPanelProfileTab;  class LLTextBox; @@ -99,11 +100,11 @@ protected:  private:  	// LLCacheName will call this function when avatar name is loaded from server.  	// This is required to display names that have not been cached yet. -	void onAvatarNameCached( -		const LLUUID& id,  -		const std::string& first_name, -		const std::string& last_name, -		BOOL is_group); +//	void onNameCache( +//		const LLUUID& id,  +//		const std::string& full_name, +//		bool is_group); +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);  	LLTextBox* mStatusText;  	AvatarStatusObserver* mAvatarStatusObserver; diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index f2e6969998..17934afab4 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -337,11 +337,18 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param)  			if ( item )  			{  				std::string name = item->getAvatarName(); +				std::string tooltip = item->getAvatarToolTip();  				size_t found = name.find(moderator_indicator);  				if (found != std::string::npos)  				{  					name.erase(found, moderator_indicator_len); -					item->setName(name); +					item->setAvatarName(name); +				} +				found = tooltip.find(moderator_indicator); +				if (found != tooltip.npos) +				{ +					tooltip.erase(found, moderator_indicator_len); +					item->setAvatarToolTip(tooltip);  				}  			}  		} @@ -357,12 +364,20 @@ void LLParticipantList::onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param)  			if ( item )  			{  				std::string name = item->getAvatarName(); +				std::string tooltip = item->getAvatarToolTip();  				size_t found = name.find(moderator_indicator);  				if (found == std::string::npos)  				{  					name += " ";  					name += moderator_indicator; -					item->setName(name); +					item->setAvatarName(name); +				} +				found = tooltip.find(moderator_indicator); +				if (found == std::string::npos) +				{ +					tooltip += " "; +					tooltip += moderator_indicator; +					item->setAvatarToolTip(tooltip);  				}  			}  		} diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index d9870e81c5..153112bc54 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -281,11 +281,12 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)  	if (item->getCreatorUUID().notNull())  	{ -		std::string name; -		gCacheName->getFullName(item->getCreatorUUID(), name); +		LLUUID creator_id = item->getCreatorUUID(); +		std::string name = +			LLSLURL("agent", creator_id, "completename").getSLURLString();  		childSetEnabled("BtnCreator",TRUE);  		childSetEnabled("LabelCreatorTitle",TRUE); -		childSetEnabled("LabelCreatorName",TRUE); +		childSetEnabled("LabelCreatorName",FALSE);  		childSetText("LabelCreatorName",name);  	}  	else @@ -308,11 +309,12 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)  		}  		else  		{ -			gCacheName->getFullName(perm.getOwner(), name); +			LLUUID owner_id = perm.getOwner(); +			name = LLSLURL("agent", owner_id, "completename").getSLURLString();  		}  		childSetEnabled("BtnOwner",TRUE);  		childSetEnabled("LabelOwnerTitle",TRUE); -		childSetEnabled("LabelOwnerName",TRUE); +		childSetEnabled("LabelOwnerName",FALSE);  		childSetText("LabelOwnerName",name);  	}  	else diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp index 3ab71eac64..f71a4a475b 100644 --- a/indra/newview/llsidepaneltaskinfo.cpp +++ b/indra/newview/llsidepaneltaskinfo.cpp @@ -351,7 +351,7 @@ void LLSidepanelTaskInfo::refresh()  		if (mLabelGroupName)  		{  			mLabelGroupName->setNameID(LLUUID::null, TRUE); -			mLabelGroupName->refresh(LLUUID::null,LLStringUtil::null, LLStringUtil::null, TRUE); +			mLabelGroupName->refresh(LLUUID::null, std::string(), true);  			mLabelGroupName->setEnabled(FALSE);  		}  	} diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index bf00b47c21..b844d230a1 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -74,12 +74,13 @@ LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerTy  void LLSpeaker::lookupName()  { -	gCacheName->get(mID, FALSE, boost::bind(&LLSpeaker::onAvatarNameLookup, this, _1, _2, _3, _4)); +	gCacheName->get(mID, false, +		boost::bind(&LLSpeaker::onNameCache, this, _1, _2, _3));  } -void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +void LLSpeaker::onNameCache(const LLUUID& id, const std::string& full_name, bool is_group)  { -	mDisplayName = first + " " + last; +	mDisplayName = full_name;  }  bool LLSpeaker::isInVoiceChannel() diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 4a250de82f..29638319ad 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -66,7 +66,7 @@ public:  	~LLSpeaker() {};  	void lookupName(); -	void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); +	void onNameCache(const LLUUID& id, const std::string& full_name, bool is_group);  	bool isInVoiceChannel(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 96088fed9c..07e61fcc92 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -52,6 +52,7 @@  #endif  #include "llares.h" +#include "llavatarnamecache.h"  #include "lllandmark.h"  #include "llcachename.h"  #include "lldir.h" @@ -269,11 +270,10 @@ void apply_udp_blacklist(const std::string& csv);  bool process_login_success_response();  void transition_back_to_login_panel(const std::string& emsg); -void callback_cache_name(const LLUUID& id, const std::string& firstname, const std::string& lastname, BOOL is_group) +void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group)  { -	LLNameListCtrl::refreshAll(id, firstname, lastname, is_group); -	LLNameBox::refreshAll(id, firstname, lastname, is_group); -	LLNameEditor::refreshAll(id, firstname, lastname, is_group); +	LLNameBox::refreshAll(id, full_name, is_group); +	LLNameEditor::refreshAll(id, full_name, is_group);  	// TODO: Actually be intelligent about the refresh.  	// For now, just brute force refresh the dialogs. @@ -1287,16 +1287,7 @@ bool idle_startup()  		gXferManager->registerCallbacks(gMessageSystem); -		if ( gCacheName == NULL ) -		{ -			gCacheName = new LLCacheName(gMessageSystem); -			gCacheName->addObserver(&callback_cache_name); -			gCacheName->LocalizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); -			gCacheName->LocalizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); -			gCacheName->LocalizeCacheName("none", LLTrans::getString("GroupNameNone")); -			// Load stored cache if possible -            LLAppViewer::instance()->loadNameCache(); -		} +		LLStartUp::initNameCache();  		// update the voice settings *after* gCacheName initialization  		// so that we can construct voice UI that relies on the name cache @@ -1638,7 +1629,6 @@ bool idle_startup()  			LLClassifiedInfo::loadCategories(classified_categories);  		} -  		// This method MUST be called before gInventory.findCategoryUUIDForType because of   		// gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.  		gInventory.buildParentChildMap(); @@ -2689,6 +2679,33 @@ void LLStartUp::fontInit()  	LLFontGL::loadDefaultFonts();  } +void LLStartUp::initNameCache() +{ +	// Can be called multiple times +	if ( gCacheName ) return; + +	gCacheName = new LLCacheName(gMessageSystem); +	gCacheName->addObserver(&callback_cache_name); +	gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); +	gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); +	gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); +	// Load stored cache if possible +	LLAppViewer::instance()->loadNameCache(); + +	// Start cache in not-running state until we figure out if we have +	// capabilities for display name lookup +	LLAvatarNameCache::initClass(false); +	LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); +} + +void LLStartUp::cleanupNameCache() +{ +	LLAvatarNameCache::cleanupClass(); + +	delete gCacheName; +	gCacheName = NULL; +} +  bool LLStartUp::dispatchURL()  {  	// ok, if we've gotten this far and have a startup URL diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index cf3c030f08..e73e774a61 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -93,8 +93,12 @@ public:  	// Load default fonts not already loaded at start screen  	static void fontInit(); +	static void initNameCache(); +	  	static void copyLibraryGestures(const std::string& same_gender_gestures); +	static void cleanupNameCache(); +  	// outfit_folder_name can be a folder anywhere in your inventory,   	// but the name must be a case-sensitive exact match.  	// gender_name is either "male" or "female" diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 1a8c2b8fc0..2020e2aa9f 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -32,14 +32,15 @@  #include "llviewerprecompiledheaders.h" // must be first include +#include "llsyswellwindow.h" +  #include "llagent.h" +#include "llavatarnamecache.h"  #include "llflatlistview.h"  #include "llfloaterreg.h"  #include "llnotifications.h" -#include "llsyswellwindow.h" -  #include "llbottomtray.h"  #include "llscriptfloater.h"  #include "llviewercontrol.h" @@ -284,14 +285,31 @@ LLIMWellWindow::RowPanel::RowPanel(const LLSysWellWindow* parent, const LLUUID&  	mChiclet->setOtherParticipantId(otherParticipantId);  	mChiclet->setVisible(true); -	LLTextBox* contactName = getChild<LLTextBox>("contact_name"); -	contactName->setValue(name); +	if (im_chiclet_type == LLIMChiclet::TYPE_IM) +	{ +		LLAvatarNameCache::get(otherParticipantId, +			boost::bind(&LLIMWellWindow::RowPanel::onAvatarNameCache, +				this, _1, _2)); +	} +	else +	{ +		LLTextBox* contactName = getChild<LLTextBox>("contact_name"); +		contactName->setValue(name); +	}  	mCloseBtn = getChild<LLButton>("hide_btn");  	mCloseBtn->setCommitCallback(boost::bind(&LLIMWellWindow::RowPanel::onClosePanel, this));  }  //--------------------------------------------------------------------------------- +void LLIMWellWindow::RowPanel::onAvatarNameCache(const LLUUID& agent_id, +												 const LLAvatarName& av_name) +{ +	LLTextBox* contactName = getChild<LLTextBox>("contact_name"); +	contactName->setValue( av_name.getCompleteName() ); +} + +//---------------------------------------------------------------------------------  void LLIMWellWindow::RowPanel::onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param)  {  	LLTextBox* text = getChild<LLTextBox>("contact_name"); diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index c8215c71ee..9d8fe536e2 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -43,6 +43,7 @@  #include "boost/shared_ptr.hpp" +class LLAvatarName;  class LLFlatListView;  class LLChiclet;  class LLIMChiclet; @@ -208,6 +209,7 @@ private:  	private:  		static const S32 CHICLET_HPAD = 10; +		void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);  		void onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param);  		void onClosePanel();  	public: diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index 7eac3867d5..ab4071110e 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -42,6 +42,7 @@  #include "llnotifications.h"  #include "llviewertexteditor.h" +#include "llavatarnamecache.h"  #include "lluiconstants.h"  #include "llui.h"  #include "llviewercontrol.h" @@ -73,7 +74,11 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification  	pGroupIcon->setValue(groupData.mInsigniaID);  	//header title -	const std::string& from_name = payload["sender_name"].asString(); +	std::string from_name = payload["sender_name"].asString(); +	if (LLAvatarNameCache::useDisplayNames()) +	{ +		from_name = LLCacheName::buildUsername(from_name); +	}  	std::stringstream from;  	from << from_name << "/" << groupData.mName;  	LLTextBox* pTitleText = getChild<LLTextBox>("title"); diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index 26d3bd5192..2c5438c47d 100644 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -147,7 +147,8 @@ void LLToastIMPanel::spawnNameToolTip()  {  	// Spawn at right side of the name textbox.  	LLRect sticky_rect = mAvatarName->calcScreenRect(); -	S32 icon_x = llmin(sticky_rect.mLeft + mAvatarName->getTextPixelWidth() + 3, sticky_rect.mRight - 16); +	S32 icon_x = +		llmin(sticky_rect.mLeft + mAvatarName->getTextPixelWidth() + 3, sticky_rect.mRight);  	LLCoordGL pos(icon_x, sticky_rect.mTop);  	LLToolTip::Params params; diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 95c4f01e46..535f41a3aa 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -40,6 +40,7 @@  #include "llagent.h"  #include "llagentcamera.h" +#include "llavatarnamecache.h"  #include "llviewercontrol.h"  #include "llfocusmgr.h"  //#include "llfirstuse.h" @@ -861,23 +862,39 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l  			|| !existing_inspector->getVisible()  			|| existing_inspector->getKey()["avatar_id"].asUUID() != hover_object->getID())  		{ -			std::string avatar_name; +			// IDEVO: try to get display name + username +			std::string final_name; +			std::string full_name; +			if (!gCacheName->getFullName(hover_object->getID(), full_name)) +			{  			LLNameValue* firstname = hover_object->getNVPair("FirstName");  			LLNameValue* lastname =  hover_object->getNVPair("LastName");  			if (firstname && lastname)  			{ -				avatar_name = llformat("%s %s", firstname->getString(), lastname->getString()); +					full_name = LLCacheName::buildFullName( +						firstname->getString(), lastname->getString()); +				} +				else +				{ +					full_name = LLTrans::getString("TooltipPerson"); +				} +			} +			LLAvatarName av_name; +			if (LLAvatarNameCache::useDisplayNames() +				&& LLAvatarNameCache::get(hover_object->getID(), &av_name)) +			{ +				final_name = av_name.mDisplayName + " (" + av_name.mUsername + ")";  			}  			else  			{ -				avatar_name = LLTrans::getString("TooltipPerson"); +				final_name = full_name;  			}  			// *HACK: We may select this object, so pretend it was clicked  			mPick = mHoverPick;  			LLInspector::Params p;  			p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); -			p.message(avatar_name); +			p.message(final_name);  			p.image.name("Inspector_I");  			p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));  			p.visible_time_near(6.f); diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index cc074287c4..c81a062ade 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -570,16 +570,16 @@ void LLTracker::renderBeacon(LLVector3d pos_global,  	std::string text;  	text = llformat( "%.0f m", to_vec.magVec()); -	LLWString wstr; -	wstr += utf8str_to_wstring(label); -	wstr += '\n'; -	wstr += utf8str_to_wstring(text); +	std::string str; +	str += label; +	str += '\n'; +	str += text;  	hud_textp->setFont(LLFontGL::getFontSansSerif());  	hud_textp->setZCompare(FALSE);  	hud_textp->setColor(LLColor4(1.f, 1.f, 1.f, llmax(0.2f, llmin(1.f,(dist-FADE_DIST)/FADE_DIST)))); -	hud_textp->setString(wstr); +	hud_textp->setString(str);  	hud_textp->setVertAlignment(LLHUDText::ALIGN_VERT_CENTER);  	hud_textp->setPositionAgent(pos_agent);  } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index ab6ff88073..41667007d6 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -323,7 +323,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  	LLImageGL::updateStats(gFrameTimeSeconds);  	LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode"); -	LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("RenderShowGroupTitleAll") && gSavedSettings.getS32("AvatarNameTagMode")); +	LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));  	gPipeline.mBackfaceCull = TRUE;  	gFrameCount++; diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp new file mode 100644 index 0000000000..bda0fe9737 --- /dev/null +++ b/indra/newview/llviewerdisplayname.cpp @@ -0,0 +1,205 @@ +/**  + * @file llviewerdisplayname.cpp + * @brief Wrapper for display name functionality + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, 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 "llviewerdisplayname.h" + +// viewer includes +#include "llagent.h" +#include "llviewerregion.h" +#include "llvoavatar.h" + +// library includes +#include "llavatarnamecache.h" +#include "llhttpclient.h" +#include "llhttpnode.h" +#include "llnotificationsutil.h" +#include "llui.h"					// getLanguage() + +namespace LLViewerDisplayName +{ +	// Fired when viewer receives server response to display name change +	set_name_signal_t sSetDisplayNameSignal; +} + +class LLSetDisplayNameResponder : public LLHTTPClient::Responder +{ +public: +	// only care about errors +	/*virtual*/ void error(U32 status, const std::string& reason) +	{ +		LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); +		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); +	} +}; + +void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) +{ +	// TODO: simple validation here + +	LLViewerRegion* region = gAgent.getRegion(); +	llassert(region); +	std::string cap_url = region->getCapability("SetDisplayName"); +	if (cap_url.empty()) +	{ +		// this server does not support display names, report error +		slot(false, "unsupported", LLSD()); +		return; +	} + +	// People API can return localized error messages.  Indicate our +	// language preference via header. +	LLSD headers; +	headers["Accept-Language"] = LLUI::getLanguage(); + +	// People API requires both the old and new value to change a variable. +	// Our display name will be in cache before the viewer's UI is available +	// to request a change, so we can use direct lookup without callback. +	LLAvatarName av_name; +	if (!LLAvatarNameCache::get( gAgent.getID(), &av_name)) +	{ +		slot(false, "name unavailable", LLSD()); +		return; +	} + +	// People API expects array of [ "old value", "new value" ] +	LLSD change_array = LLSD::emptyArray(); +	change_array.append(av_name.mDisplayName); +	change_array.append(display_name); +	 +	llinfos << "Set name POST to " << cap_url << llendl; + +	// Record our caller for when the server sends back a reply +	sSetDisplayNameSignal.connect(slot); +	 +	// POST the requested change.  The sim will not send a response back to +	// this request directly, rather it will send a separate message after it +	// communicates with the back-end. +	LLSD body; +	body["display_name"] = change_array; +	LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); +} + +class LLSetDisplayNameReply : public LLHTTPNode +{ +	LOG_CLASS(LLSetDisplayNameReply); +public: +	/*virtual*/ void post( +		LLHTTPNode::ResponsePtr response, +		const LLSD& context, +		const LLSD& input) const +	{ +		LLSD body = input["body"]; + +		S32 status = body["status"].asInteger(); +		bool success = (status == 200); +		std::string reason = body["reason"].asString(); +		LLSD content = body["content"]; + +		llinfos << "status " << status << " reason " << reason << llendl; + +		// If viewer's concept of display name is out-of-date, the set request +		// will fail with 409 Conflict.  If that happens, fetch up-to-date +		// name information. +		if (status == 409) +		{ +			LLUUID agent_id = gAgent.getID(); +			// Flush stale data +			LLAvatarNameCache::erase( agent_id ); +			// Queue request for new data +			LLAvatarName ignored; +			LLAvatarNameCache::get( agent_id, &ignored ); +			// Kill name tag, as it is wrong +			LLVOAvatar::invalidateNameTag( agent_id ); +		} + +		// inform caller of result +		LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content); +		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); +	} +}; + + +class LLDisplayNameUpdate : public LLHTTPNode +{ +	/*virtual*/ void post( +		LLHTTPNode::ResponsePtr response, +		const LLSD& context, +		const LLSD& input) const +	{ +		LLSD body = input["body"]; +		LLUUID agent_id = body["agent_id"]; +		std::string old_display_name = body["old_display_name"]; +		// By convention this record is called "agent" in the People API +		LLSD name_data = body["agent"]; + +		// Inject the new name data into cache +		LLAvatarName av_name; +		av_name.fromLLSD( name_data ); + +		llinfos << "name-update now " << LLDate::now() +			<< " next_update " << LLDate(av_name.mNextUpdate) +			<< llendl; + +		// Name expiration time may be provided in headers, or we may use a +		// default value +		// *TODO: get actual headers out of ResponsePtr +		//LLSD headers = response->mHeaders; +		LLSD headers; +		av_name.mExpires =  +			LLAvatarNameCache::nameExpirationFromHeaders(headers); + +		LLAvatarNameCache::insert(agent_id, av_name); + +		// force name tag to update +		LLVOAvatar::invalidateNameTag(agent_id); + +		// Don't show a notification for my name, because we'll show a nicer +		// dialog +		if (agent_id != gAgent.getID()) +		{ +			LLSD args; +			args["OLD_NAME"] = old_display_name; +			args["SLID"] = av_name.mUsername; +			args["NEW_NAME"] = av_name.mDisplayName; +			LLNotificationsUtil::add("DisplayNameUpdate", args); +		} +	} +}; + +LLHTTPRegistration<LLSetDisplayNameReply> +    gHTTPRegistrationMessageSetDisplayNameReply( +		"/message/SetDisplayNameReply"); + +LLHTTPRegistration<LLDisplayNameUpdate> +    gHTTPRegistrationMessageDisplayNameUpdate( +		"/message/DisplayNameUpdate"); diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h new file mode 100644 index 0000000000..c77388531b --- /dev/null +++ b/indra/newview/llviewerdisplayname.h @@ -0,0 +1,53 @@ +/**  + * @file llviewerdisplayname.h + * @brief Wrapper for display name functionality + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + *  + * Copyright (c) 2010, 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 LLVIEWERDISPLAYNAME_H +#define LLVIEWERDISPLAYNAME_H + +#include <boost/signals2.hpp> + +class LLSD; +class LLUUID; + +namespace LLViewerDisplayName +{ +	typedef boost::signals2::signal< +		void (bool success, const std::string& reason, const LLSD& content)> +			set_name_signal_t; +	typedef set_name_signal_t::slot_type set_name_slot_t; + +	// Sends an update to the server to change a display name +	// and call back when done.  May not succeed due to service +	// unavailable or name not available. +	void set(const std::string& display_name, const set_name_slot_t& slot); +} + +#endif // LLVIEWERDISPLAYNAME_H diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 9926c8d15f..2d4f36cdcf 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1782,9 +1782,9 @@ PermissionMask LLViewerInventoryItem::getPermissionMask() const  //---------- -void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name) +void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group)  { -	rename(first_name + " " + last_name); +	rename(name);  	gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID());  	gInventory.notifyObservers();  } diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index ef3586537b..a18311858e 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -163,7 +163,7 @@ public:  	PermissionMask getPermissionMask() const;  	// callback -	void onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name); +	void onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group);  	// If this is a broken link, try to fix it and any other identical link.  	BOOL regenerateLink(); diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 2b4b78d82d..b230203561 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -39,6 +39,7 @@  #include "llviewercontrol.h"  #include "lldrawable.h"  #include "llgl.h" +#include "llhudtext.h"  #include "llrender.h"  #include "llvoavatar.h"  #include "llvolume.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 23e502c76f..1019a67d0d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -34,6 +34,7 @@  #include "llviewermenu.h"   // linden library includes +#include "llavatarnamecache.h"	// IDEVO  #include "llfloaterreg.h"  #include "llcombobox.h"  #include "llinventorypanel.h" @@ -2804,9 +2805,8 @@ class LLObjectMute : public view_listener_t  			LLNameValue *lastname = avatar->getNVPair("LastName");  			if (firstname && lastname)  			{ -				name = firstname->getString(); -				name += " "; -				name += lastname->getString(); +				name = LLCacheName::buildFullName( +					firstname->getString(), lastname->getString());  			}  			type = LLMute::AGENT; @@ -3152,58 +3152,6 @@ bool enable_freeze_eject(const LLSD& avatar_id)  	return new_value;  } -class LLAvatarGiveCard : public view_listener_t -{ -	bool handleEvent(const LLSD& userdata) -	{ -		llinfos << "handle_give_card()" << llendl; -		LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -		if(dest && dest->isAvatar()) -		{ -			bool found_name = false; -			LLSD args; -			LLSD old_args; -			LLNameValue* nvfirst = dest->getNVPair("FirstName"); -			LLNameValue* nvlast = dest->getNVPair("LastName"); -			if(nvfirst && nvlast) -			{ -				args["FIRST"] = nvfirst->getString(); -				args["LAST"] = nvlast->getString(); -				old_args["FIRST"] = nvfirst->getString(); -				old_args["LAST"] = nvlast->getString(); -				found_name = true; -			} -			LLViewerRegion* region = dest->getRegion(); -			LLHost dest_host; -			if(region) -			{ -				dest_host = region->getHost(); -			} -			if(found_name && dest_host.isOk()) -			{ -				LLMessageSystem* msg = gMessageSystem; -				msg->newMessage("OfferCallingCard"); -				msg->nextBlockFast(_PREHASH_AgentData); -				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -				msg->nextBlockFast(_PREHASH_AgentBlock); -				msg->addUUIDFast(_PREHASH_DestID, dest->getID()); -				LLUUID transaction_id; -				transaction_id.generate(); -				msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); -				msg->sendReliable(dest_host); -				LLNotificationsUtil::add("OfferedCard", args); -			} -			else -			{ -				LLNotificationsUtil::add("CantOfferCallingCard", old_args); -			} -		} -		return true; -	} -}; - -  void login_done(S32 which, void *user)  { @@ -3613,21 +3561,17 @@ void request_friendship(const LLUUID& dest_id)  	LLViewerObject* dest = gObjectList.findObject(dest_id);  	if(dest && dest->isAvatar())  	{ -		std::string fullname; -		LLSD args; +		std::string full_name;  		LLNameValue* nvfirst = dest->getNVPair("FirstName");  		LLNameValue* nvlast = dest->getNVPair("LastName");  		if(nvfirst && nvlast)  		{ -			args["FIRST"] = nvfirst->getString(); -			args["LAST"] = nvlast->getString(); -			fullname = nvfirst->getString(); -			fullname += " "; -			fullname += nvlast->getString(); +			full_name = LLCacheName::buildFullName( +				nvfirst->getString(), nvlast->getString());  		} -		if (!fullname.empty()) +		if (!full_name.empty())  		{ -			LLAvatarActions::requestFriendshipDialog(dest_id, fullname); +			LLAvatarActions::requestFriendshipDialog(dest_id, full_name);  		}  		else  		{ @@ -7652,6 +7596,16 @@ class LLWorldToggleCameraControls : public view_listener_t  	}  }; +void handle_flush_name_caches() +{ +	// Toggle display names on and off to flush +	bool use_display_names = LLAvatarNameCache::useDisplayNames(); +	LLAvatarNameCache::setUseDisplayNames(!use_display_names); +	LLAvatarNameCache::setUseDisplayNames(use_display_names); + +	if (gCacheName) gCacheName->clear(); +} +  class LLUploadCostCalculator : public view_listener_t  {  	std::string mCostStr; @@ -7883,6 +7837,7 @@ void initialize_menus()  	view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole");  	view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole");  	view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); +	  	// Advanced > HUD Info  	view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo");  	view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); @@ -7963,6 +7918,7 @@ void initialize_menus()  	view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames");  	view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames");  	view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); +	commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches));  	// Advanced > Character > Grab Baked Texture  	view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); @@ -8061,7 +8017,6 @@ void initialize_menus()  	view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug");  	view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug");  	view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); -	view_listener_t::addMenu(new LLAvatarGiveCard(), "Avatar.GiveCard");  	commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));  	view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");  	view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index fa0e860ae9..0c61e52bc2 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -34,9 +34,11 @@  #include "llviewermessage.h"  #include "boost/lexical_cast.hpp" +// Linden libraries  #include "llanimationstates.h"  #include "llaudioengine.h"   #include "llavataractions.h" +#include "llavatarnamecache.h"		// IDEVO HACK  #include "lscript_byteformat.h"  #include "lleconomy.h"  #include "lleventtimer.h" @@ -84,6 +86,7 @@  #include "llspeakers.h"  #include "lltrans.h"  #include "llviewerfoldertype.h" +#include "llvoavatar.h"				// IDEVO HACK  #include "lluri.h"  #include "llviewergenericmessage.h"  #include "llviewermenu.h" @@ -132,6 +135,7 @@ extern BOOL gDebugClicks;  // function prototypes  bool check_offer_throttle(const std::string& from_name, bool check_only); +static void process_money_balance_reply_extended(LLMessageSystem* msg);  //inventory offer throttle globals  LLFrameTimer gThrottleTimer; @@ -1229,28 +1233,26 @@ bool highlight_offered_object(const LLUUID& obj_id)  }  void inventory_offer_mute_callback(const LLUUID& blocked_id, -								   const std::string& first_name, -								   const std::string& last_name, -								   BOOL is_group, boost::shared_ptr<LLNotificationResponderInterface> offer_ptr) +								   const std::string& full_name, +								   bool is_group, +								   boost::shared_ptr<LLNotificationResponderInterface> offer_ptr)  {  	LLOfferInfo* offer =  dynamic_cast<LLOfferInfo*>(offer_ptr.get()); -	std::string from_name; +	 +	std::string from_name = full_name;  	LLMute::EType type;  	if (is_group)  	{  		type = LLMute::GROUP; -		from_name = first_name;  	}  	else if(offer && offer->mFromObject)  	{  		//we have to block object by name because blocked_id is an id of owner  		type = LLMute::BY_NAME; -		from_name = offer->mFromName;  	}  	else  	{  		type = LLMute::AGENT; -		from_name = first_name + " " + last_name;  	}  	// id should be null for BY_NAME mute, see  LLMuteList::add for details   @@ -1428,7 +1430,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&  		llassert(notification_ptr != NULL);  		if (notification_ptr != NULL)  		{ -			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4, notification_ptr->getResponderPtr())); +			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr()));  		}  	} @@ -1568,7 +1570,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const  		llassert(notification_ptr != NULL);  		if (notification_ptr != NULL)  		{ -			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4, notification_ptr->getResponderPtr())); +			gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr()));  		}  	} @@ -1617,12 +1619,12 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const  		}  		else  		{ -			std::string first_name, last_name; -			if (gCacheName->getName(mFromID, first_name, last_name)) +			std::string full_name; +			if (gCacheName->getFullName(mFromID, full_name))  			{  				from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName  -				+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name; -				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name; +					+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + full_name; +				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + full_name;  			}  			else  			{ @@ -1826,7 +1828,14 @@ void inventory_offer_handler(LLOfferInfo* info)  	payload["give_inventory_notification"] = FALSE;  	args["OBJECTFROMNAME"] = info->mFromName;  	args["NAME"] = info->mFromName; -	args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString(); +	if (info->mFromGroup) +	{ +		args["NAME_SLURL"] = LLSLURL("group", info->mFromID, "about").getSLURLString(); +	} +	else +	{ +		args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString(); +	}  	std::string verb = "select?name=" + LLURI::escape(msg);  	args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString(); @@ -1946,7 +1955,6 @@ protected:  	void modifyNotificationParams()  	{  		LLSD payload = mParams.payload; -		payload["SESSION_NAME"] = mName;  		mParams.payload = payload;  	}  }; @@ -2009,6 +2017,99 @@ static bool parse_lure_bucket(const std::string& bucket,  	return true;  } +// Strip out "Resident" for display, but only if the message came from a user +// (rather than a script) +static std::string clean_name_from_im(const std::string& name, EInstantMessage type) +{ +	switch(type) +	{ +	case IM_NOTHING_SPECIAL: +	case IM_MESSAGEBOX: +	case IM_GROUP_INVITATION: +	case IM_INVENTORY_OFFERED: +	case IM_INVENTORY_ACCEPTED: +	case IM_INVENTORY_DECLINED: +	case IM_GROUP_VOTE: +	case IM_GROUP_MESSAGE_DEPRECATED: +	//IM_TASK_INVENTORY_OFFERED +	//IM_TASK_INVENTORY_ACCEPTED +	//IM_TASK_INVENTORY_DECLINED +	case IM_NEW_USER_DEFAULT: +	case IM_SESSION_INVITE: +	case IM_SESSION_P2P_INVITE: +	case IM_SESSION_GROUP_START: +	case IM_SESSION_CONFERENCE_START: +	case IM_SESSION_SEND: +	case IM_SESSION_LEAVE: +	//IM_FROM_TASK +	case IM_BUSY_AUTO_RESPONSE: +	case IM_CONSOLE_AND_CHAT_HISTORY: +	case IM_LURE_USER: +	case IM_LURE_ACCEPTED: +	case IM_LURE_DECLINED: +	case IM_GODLIKE_LURE_USER: +	case IM_YET_TO_BE_USED: +	case IM_GROUP_ELECTION_DEPRECATED: +	//IM_GOTO_URL +	//IM_FROM_TASK_AS_ALERT +	case IM_GROUP_NOTICE: +	case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: +	case IM_GROUP_NOTICE_INVENTORY_DECLINED: +	case IM_GROUP_INVITATION_ACCEPT: +	case IM_GROUP_INVITATION_DECLINE: +	case IM_GROUP_NOTICE_REQUESTED: +	case IM_FRIENDSHIP_OFFERED: +	case IM_FRIENDSHIP_ACCEPTED: +	case IM_FRIENDSHIP_DECLINED_DEPRECATED: +	//IM_TYPING_START +	//IM_TYPING_STOP +		return LLCacheName::cleanFullName(name); +	default: +		return name; +	} +} + +static std::string clean_name_from_task_im(const std::string& msg, +										   BOOL from_group) +{ +	boost::smatch match; +	static const boost::regex returned_exp( +		"(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); +	if (boost::regex_match(msg, match, returned_exp)) +	{ +		// match objects are 1-based for groups +		std::string final = match[1].str(); +		std::string name = match[2].str(); +		// Don't try to clean up group names +		if (!from_group) +		{ +			if (LLAvatarNameCache::useDisplayNames()) +			{ +				// ...just convert to username +				final += LLCacheName::buildUsername(name); +			} +			else +			{ +				// ...strip out legacy "Resident" name +				final += LLCacheName::cleanFullName(name); +			} +		} +		final += match[3].str(); +		return final; +	} +	return msg; +} + +void notification_display_name_callback(const LLUUID& id, +					  const LLAvatarName& av_name, +					  const std::string& name,  +					  LLSD& substitutions,  +					  const LLSD& payload) +{ +	substitutions["NAME"] = av_name.mDisplayName; +	LLNotificationsUtil::add(name, substitutions, payload); +} +  class LLPostponedIMSystemTipNotification: public LLPostponedNotification  {  protected: @@ -2019,8 +2120,28 @@ protected:  		payload["SESSION_NAME"] = mName;  		mParams.payload = payload;  	} +  }; +// Callback for name resolution of a god/estate message +void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) +{	 +	LLSD args; +	args["NAME"] = av_name.getCompleteName(); +	args["MESSAGE"] = message; +	LLNotificationsUtil::add("GodMessage", args); + +	// Treat like a system message and put in chat history. +	chat.mText = av_name.getCompleteName() + ": " + message; + +	LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); +	if(nearby_chat) +	{ +		nearby_chat->addMessage(chat); +	} + +} +  void process_improved_im(LLMessageSystem *msg, void **user_data)  {  	if (gNoRender) @@ -2068,6 +2189,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  	{          name = LLTrans::getString("Unnamed");  	} +	// IDEVO convert new-style "Resident" names for display +	name = clean_name_from_im(name, dialog);  	BOOL is_busy = gAgent.getBusy();  	BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat); @@ -2097,7 +2220,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  	{  	case IM_CONSOLE_AND_CHAT_HISTORY:  		args["MESSAGE"] = message; -		args["NAME"] = name;  		payload["from_id"] = from_id;  		params.name = "IMSystemMessageTip"; @@ -2167,21 +2289,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  		}  		else if (to_id.isNull())  		{ -			// Message to everyone from GOD -			args["NAME"] = name; -			args["MESSAGE"] = message; -			LLNotificationsUtil::add("GodMessage", args); - -			// Treat like a system message and put in chat history. -			// Claim to be from a local agent so it doesn't go into -			// console. -			chat.mText = name + separator_string + message; - -			LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); -			if(nearby_chat) -			{ -				nearby_chat->addMessage(chat); -			} +			// Message to everyone from GOD, look up the fullname since +			// server always slams name to legacy names +			LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message));  		}  		else  		{ @@ -2379,6 +2489,15 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  				invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];  				S32 membership_fee = ntohl(invite_bucket->membership_fee); +				// IDEVO Clean up legacy name "Resident" in message constructed in +				// lldatagroups.cpp +				U32 pos = message.find(" has invited you to join a group.\n"); +				if (pos != std::string::npos) +				{ +					// use cleaned-up name from above +					message = name + message.substr(pos); +				} +  				LLSD payload;  				payload["transaction_id"] = session_id;  				payload["group_id"] = from_id; @@ -2466,7 +2585,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  	case IM_INVENTORY_ACCEPTED:  	{ -		args["NAME"] = name; +		args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;  		LLSD payload;  		payload["from_id"] = from_id;  		LLNotificationsUtil::add("InventoryAccepted", args, payload); @@ -2474,7 +2593,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  	}  	case IM_INVENTORY_DECLINED:  	{ -		args["NAME"] = name; +		args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;  		LLSD payload;  		payload["from_id"] = from_id;  		LLNotificationsUtil::add("InventoryDeclined", args, payload); @@ -2566,6 +2685,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  				chat.mSourceType = CHAT_SOURCE_SYSTEM;  			} +			// IDEVO Some messages have embedded resident names +			message = clean_name_from_task_im(message, from_group); +  			LLSD query_string;  			query_string["owner"] = from_id;  			query_string["slurl"] = location; @@ -2774,7 +2896,12 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  			args["NAME"] = name;  			LLSD payload;  			payload["from_id"] = from_id; -			LLNotificationsUtil::add("FriendshipAccepted", args, payload); +			LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, +														 _1, +														 _2, +														 "FriendshipAccepted", +														 args, +														 payload));  		}  		break; @@ -2878,9 +3005,8 @@ void process_offer_callingcard(LLMessageSystem* msg, void**)  		LLNameValue* nvlast  = source->getNVPair("LastName");  		if (nvfirst && nvlast)  		{ -			args["FIRST"] = nvfirst->getString(); -			args["LAST"] = nvlast->getString(); -			source_name = std::string(nvfirst->getString()) + " " + nvlast->getString(); +			source_name = LLCacheName::buildFullName( +				nvfirst->getString(), nvlast->getString());  		}  	} @@ -2913,7 +3039,6 @@ void process_decline_callingcard(LLMessageSystem* msg, void**)  	LLNotificationsUtil::add("CallingCardDeclined");  } -  void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)  {  	LLChat	chat; @@ -2929,7 +3054,6 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)  	LLViewerObject*	chatter;  	msg->getString("ChatData", "FromName", from_name); -	chat.mFromName = from_name;  	msg->getUUID("ChatData", "SourceID", from_id);  	chat.mFromID = from_id; @@ -2948,6 +3072,27 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)  	chat.mTime = LLFrameTimer::getElapsedSeconds(); +	// IDEVO Correct for new-style "Resident" names +	if (chat.mSourceType == CHAT_SOURCE_AGENT) +	{ +		// I don't know if it's OK to change this here, if  +		// anything downstream does lookups by name, for instance +		LLAvatarName av_name; +		if (LLAvatarNameCache::useDisplayNames() +			&& LLAvatarNameCache::get(from_id, &av_name)) +		{ +			chat.mFromName = av_name.mDisplayName; +		} +		else +		{ +			chat.mFromName = LLCacheName::cleanFullName(from_name); +		} +	} +	else +	{ +		chat.mFromName = from_name; +	} +  	BOOL is_busy = gAgent.getBusy();  	BOOL is_muted = FALSE; @@ -4804,168 +4949,287 @@ void process_time_dilation(LLMessageSystem *msg, void **user_data)  */ -  void process_money_balance_reply( LLMessageSystem* msg, void** )  {  	S32 balance = 0;  	S32 credit = 0;  	S32 committed = 0;  	std::string desc; +	LLUUID tid; +	msg->getUUID("MoneyData", "TransactionID", tid);  	msg->getS32("MoneyData", "MoneyBalance", balance);  	msg->getS32("MoneyData", "SquareMetersCredit", credit);  	msg->getS32("MoneyData", "SquareMetersCommitted", committed);  	msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc);  	LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " "  			<< committed << LL_ENDL; - +      	if (gStatusBar)  	{ -	//	S32 old_balance = gStatusBar->getBalance(); - -		// This is an update, not the first transmission of balance -	/*	if (old_balance != 0) -		{ -			// this is actually an update -			if (balance > old_balance) -			{ -				LLFirstUse::useBalanceIncrease(balance - old_balance); -			} -			else if (balance < old_balance) -			{ -				LLFirstUse::useBalanceDecrease(balance - old_balance); -			} -		} -	 */  		gStatusBar->setBalance(balance);  		gStatusBar->setLandCredit(credit);  		gStatusBar->setLandCommitted(committed);  	} -	LLUUID tid; -	msg->getUUID("MoneyData", "TransactionID", tid); +	if (desc.empty() +		|| !gSavedSettings.getBOOL("NotifyMoneyChange")) +	{ +		// ...nothing to display +		return; +	} + +	// Suppress duplicate messages about the same transaction  	static std::deque<LLUUID> recent; -	if(!desc.empty() && gSavedSettings.getBOOL("NotifyMoneyChange") -	   && (std::find(recent.rbegin(), recent.rend(), tid) == recent.rend())) +	if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend())  	{ -		// Make the user confirm the transaction, since they might -		// have missed something during an event. -		// *TODO: Translate -		LLSD args; -		 +		return; +	} -		// this is a marker to retrieve avatar name from server message: -		// "<avatar name> paid you L$" -		const std::string marker = "paid you L$"; +	// Once the 'recent' container gets large enough, chop some +	// off the beginning. +	const U32 MAX_LOOKBACK = 30; +	const S32 POP_FRONT_SIZE = 12; +	if(recent.size() > MAX_LOOKBACK) +	{ +		LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; +		recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); +	} +	//LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL; +	recent.push_back(tid); +	if (msg->has("TransactionInfo")) +	{ +		// ...message has extended info for localization +		process_money_balance_reply_extended(msg); +	} +	else +	{ +		// Only old dev grids will not supply the TransactionInfo block, +		// so we can just use the hard-coded English string. +		LLSD args;  		args["MESSAGE"] = desc; +		LLNotificationsUtil::add("SystemMessage", args); +	} +} + +static std::string reason_from_transaction_type(S32 transaction_type, +												const std::string& item_desc) +{ +	// *NOTE: The keys for the reason strings are unusual because +	// an earlier version of the code used English language strings +	// extracted from hard-coded server English descriptions. +	// Keeping them so we don't have to re-localize them. +	switch (transaction_type) +	{ +		case TRANS_OBJECT_SALE: +		{ +			LLStringUtil::format_map_t arg; +			arg["ITEM"] = item_desc; +			return LLTrans::getString("for item", arg); +		} +		case TRANS_LAND_SALE: +			return LLTrans::getString("for a parcel of land"); +			 +		case TRANS_LAND_PASS_SALE: +			return LLTrans::getString("for a land access pass"); +			 +		case TRANS_GROUP_LAND_DEED: +			return LLTrans::getString("for deeding land"); +			 +		case TRANS_GROUP_CREATE: +			return LLTrans::getString("to create a group"); +			 +		case TRANS_GROUP_JOIN: +			return LLTrans::getString("to join a group"); +			 +		case TRANS_UPLOAD_CHARGE: +			return LLTrans::getString("to upload"); -		// extract avatar name from system message -		S32 marker_pos = desc.find(marker, 0); +		case TRANS_CLASSIFIED_CHARGE: +			return LLTrans::getString("to publish a classified ad"); +			 +		// These have no reason to display, but are expected and should not +		// generate warnings +		case TRANS_GIFT: +		case TRANS_PAY_OBJECT: +		case TRANS_OBJECT_PAYS: +			return std::string(); -		std::string base_name = desc.substr(0, marker_pos); -		 -		std::string name = base_name; -		LLStringUtil::trim(name); +		default: +			llwarns << "Unknown transaction type "  +				<< transaction_type << llendl; +			return std::string(); +	} +} -		// if name extracted and name cache contains avatar id send loggable notification -		LLUUID from_id; -		if(name.size() > 0 && gCacheName->getUUID(name, from_id)) -		{ -			//description always comes not localized. lets fix this +static void money_balance_group_notify(const LLUUID& group_id, +									   const std::string& name, +									   bool is_group, +									   std::string notification, +									   LLSD args, +									   LLSD payload) +{ +	// Message uses name SLURLs, don't actually have to substitute in +	// the name.  We're just making sure it's available. +	// Notification is either PaymentReceived or PaymentSent +	LLNotificationsUtil::add(notification, args, payload); +} -			//ammount paid -			std::string ammount = desc.substr(marker_pos + marker.length(),desc.length() - marker.length() - marker_pos); -	 -			//reform description -			LLStringUtil::format_map_t str_args; -			str_args["NAME"] = base_name; -			str_args["AMOUNT"] = ammount; -			std::string new_description = LLTrans::getString("paid_you_ldollars", str_args); +static void money_balance_avatar_notify(const LLUUID& agent_id, +										const LLAvatarName& av_name, +									   	std::string notification, +									   	LLSD args, +									   	LLSD payload) +{ +	// Message uses name SLURLs, don't actually have to substitute in +	// the name.  We're just making sure it's available. +	// Notification is either PaymentReceived or PaymentSent +	LLNotificationsUtil::add(notification, args, payload); +} +static void process_money_balance_reply_extended(LLMessageSystem* msg) +{ +    // Added in server 1.40 and viewer 2.1, support for localization +    // and agent ids for name lookup. +    S32 transaction_type = 0; +    LLUUID source_id; +	BOOL is_source_group = FALSE; +    LLUUID dest_id; +	BOOL is_dest_group = FALSE; +    S32 amount = 0; +    std::string item_description; + +    msg->getS32("TransactionInfo", "TransactionType", transaction_type); +    msg->getUUID("TransactionInfo", "SourceID", source_id); +	msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group); +    msg->getUUID("TransactionInfo", "DestID", dest_id); +	msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group); +    msg->getS32("TransactionInfo", "Amount", amount); +    msg->getString("TransactionInfo", "ItemDescription", item_description); +    LL_INFOS("Money") << "MoneyBalanceReply source " << source_id  +		<< " dest " << dest_id +		<< " type " << transaction_type +		<< " item " << item_description << LL_ENDL; + +	if (source_id.isNull() && dest_id.isNull()) +	{ +		// this is a pure balance update, no notification required +		return; +	} -			args["MESSAGE"] = new_description; -			args["NAME"] = name; -			LLSD payload; -			payload["from_id"] = from_id; -			LLNotificationsUtil::add("PaymentRecived", args, payload); +	std::string source_slurl; +	if (is_source_group) +	{ +		source_slurl = +			LLSLURL( "group", source_id, "inspect").getSLURLString(); +	} +	else +	{ +		source_slurl = +			LLSLURL( "agent", source_id, "completename").getSLURLString(); +	} + +	std::string dest_slurl; +	if (is_dest_group) +	{ +		dest_slurl = +			LLSLURL( "group", dest_id, "inspect").getSLURLString(); +	} +	else +	{ +		dest_slurl = +			LLSLURL( "agent", dest_id, "completename").getSLURLString(); +	} + +	std::string reason = +		reason_from_transaction_type(transaction_type, item_description); +	 +	LLStringUtil::format_map_t args; +	args["REASON"] = reason; // could be empty +	args["AMOUNT"] = llformat("%d", amount); +	 +	// Need to delay until name looked up, so need to know whether or not +	// is group +	bool is_name_group = false; +	LLUUID name_id; +	std::string message; +	std::string notification; +	LLSD final_args; +	LLSD payload; +	 +	bool you_paid_someone = (source_id == gAgentID); +	if (you_paid_someone) +	{ +		args["NAME"] = dest_slurl; +		is_name_group = is_dest_group; +		name_id = dest_id; +		if (!reason.empty()) +		{ +			if (dest_id.notNull()) +			{ +				message = LLTrans::getString("you_paid_ldollars", args); +			} +			else +			{ +				// transaction fee to the system, eg, to create a group +				message = LLTrans::getString("you_paid_ldollars_no_name", args); +			}  		} -		//AD *HACK: Parsing incoming string to localize messages that come from server! EXT-5986 -		// It's only a temporarily and ineffective measure. It doesn't affect performance much -		// because we get here only for specific type of messages, but anyway it is not right to do it! -		// *TODO: Server-side changes should be made and this code removed.  		else  		{ -			if(desc.find("You paid")==0) +			if (dest_id.notNull())  			{ -				// Regular expression for message parsing- change it in case of server-side changes. -				// Each set of parenthesis will later be used to find arguments of message we generate -				// in the end of this if- (.*) gives us name of money receiver, (\\d+)-amount of money we pay -				// and ([^$]*)- reason of payment -				boost::regex expr("You paid (?:.{0}|(.*) )L\\$(\\d+)\\s?([^$]*)\\."); -				boost::match_results <std::string::const_iterator> matches; -				if(boost::regex_match(desc, matches, expr)) -				{ -					// Name of full localizable notification string -					// there are four types of this string- with name of receiver and reason of payment, -					// without name and without reason (both may also be absent simultaneously). -					// example of string without name - You paid L$100 to create a group. -					// example of string without reason - You paid Smdby Linden L$100. -					// example of string with reason and name - You paid Smbdy Linden L$100 for a land access pass. -					// example of string with no info - You paid L$50. -					std::string line = "you_paid_ldollars_no_name"; - -					// arguments of string which will be in notification -					LLStringUtil::format_map_t str_args; - -					// extracting amount of money paid (without L$ symbols). It is always present. -					str_args["[AMOUNT]"] = std::string(matches[2]); - -					// extracting name of person/group you are paying (it may be absent) -					std::string name = std::string(matches[1]); -					if(!name.empty()) -					{ -						str_args["[NAME]"] = name; -						line = "you_paid_ldollars"; -					} - -					// extracting reason of payment (it may be absent) -					std::string reason = std::string(matches[3]); -					if (reason.empty()) -					{ -						line = name.empty() ? "you_paid_ldollars_no_info" : "you_paid_ldollars_no_reason"; -					} -					else -					{ -						std::string localized_reason; -						// if we haven't found localized string for reason of payment leave it as it was -						str_args["[REASON]"] =  LLTrans::findString(localized_reason, reason) ? localized_reason : reason; -					} - -					// forming final message string by retrieving localized version from xml -					// and applying previously found arguments -					line = LLTrans::getString(line, str_args); -					args["MESSAGE"] = line; -				} +				message = LLTrans::getString("you_paid_ldollars_no_reason", args); +			} +			else +			{ +				// no target, no reason, you just paid money +				message = LLTrans::getString("you_paid_ldollars_no_info", args);  			} - -			LLNotificationsUtil::add("SystemMessage", args);  		} - -		// Once the 'recent' container gets large enough, chop some -		// off the beginning. -		const U32 MAX_LOOKBACK = 30; -		const S32 POP_FRONT_SIZE = 12; -		if(recent.size() > MAX_LOOKBACK) +		final_args["MESSAGE"] = message; +		notification = "PaymentSent"; +	} +	else { +		// ...someone paid you +		args["NAME"] = source_slurl; +		is_name_group = is_source_group; +		name_id = source_id; +		if (!reason.empty())  		{ -			LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; -			recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); +			message = LLTrans::getString("paid_you_ldollars", args);  		} -		//LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL; -		recent.push_back(tid); +		else { +			message = LLTrans::getString("paid_you_ldollars_no_reason", args); +		} +		final_args["MESSAGE"] = message; + +		// make notification loggable +		payload["from_id"] = source_id; +		notification = "PaymentReceived"; +	} + +	// Despite using SLURLs, wait until the name is available before +	// showing the notification, otherwise the UI layout is strange and +	// the user sees a "Loading..." message +	if (is_name_group) +	{ +		gCacheName->getGroup(name_id, +						boost::bind(&money_balance_group_notify, +									_1, _2, _3, +									notification, final_args, payload)); +	} +	else { +		LLAvatarNameCache::get(name_id, +							   boost::bind(&money_balance_avatar_notify, +										   _1, _2, +										   notification, final_args, payload));										     	}  } + +  bool handle_special_notification_callback(const LLSD& notification, const LLSD& response)  {  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -5207,7 +5471,7 @@ void handle_show_mean_events(void *)  	//LLFloaterBump::showInstance();  } -void mean_name_callback(const LLUUID &id, const std::string& first, const std::string& last, BOOL always_false) +void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group)  {  	if (gNoRender)  	{ @@ -5229,8 +5493,7 @@ void mean_name_callback(const LLUUID &id, const std::string& first, const std::s  		LLMeanCollisionData *mcd = *iter;  		if (mcd->mPerp == id)  		{ -			mcd->mFirstName = first; -			mcd->mLastName = last; +			mcd->mFullName = full_name;  		}  	}  } @@ -5284,8 +5547,7 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use  		{  			LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag);  			gMeanCollisionList.push_front(mcd); -			const BOOL is_group = FALSE; -			gCacheName->get(perp, is_group, &mean_name_callback); +			gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3));  		}  	}  } @@ -5507,7 +5769,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)  	// so we'll reuse the same namespace for both throttle types.  	std::string throttle_name = owner_name;  	std::string self_name; -	LLAgentUI::buildName( self_name ); +	LLAgentUI::buildFullname( self_name );  	if( owner_name == self_name )  	{  		throttle_name = taskid.getString(); @@ -5543,7 +5805,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)  		S32 count = 0;  		LLSD args;  		args["OBJECTNAME"] = object_name; -		args["NAME"] = owner_name; +		args["NAME"] = LLCacheName::cleanFullName(owner_name);  		// check the received permission flags against each permission  		for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) @@ -5936,15 +6198,14 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)  			// Record the offer.  			{  				std::string target_name; -				gCacheName->getFullName(target_id, target_name); +				gCacheName->getFullName(target_id, target_name);  // for im log filenames  				LLSD args; -				args["TO_NAME"] = target_name; +				args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;  				LLSD payload;  				//*TODO please rewrite all keys to the same case, lower or upper  				payload["from_id"] = target_id; -				payload["SESSION_NAME"] = target_name;  				payload["SUPPRESS_TOAST"] = true;  				LLNotificationsUtil::add("TeleportOfferSent", args, payload);  			} @@ -6158,8 +6419,7 @@ void process_script_dialog(LLMessageSystem* msg, void**)  	LLNotificationPtr notification;  	if (!first_name.empty())  	{ -		args["FIRST"] = first_name; -		args["LAST"] = last_name; +		args["NAME"] = LLCacheName::buildFullName(first_name, last_name);  		notification = LLNotifications::instance().add(  			LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD()));  	} @@ -6192,7 +6452,7 @@ static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", ca  // We've got the name of the person who owns the object hurling the url.  // Display confirmation dialog. -void callback_load_url_name(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool is_group)  {  	std::vector<LLSD>::iterator it;  	for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) @@ -6205,11 +6465,11 @@ void callback_load_url_name(const LLUUID& id, const std::string& first, const st  			std::string owner_name;  			if (is_group)  			{ -				owner_name = first + LLTrans::getString("Group"); +				owner_name = full_name + LLTrans::getString("Group");  			}  			else  			{ -				owner_name = first + " " + last; +				owner_name = full_name;  			}  			// For legacy name-only mutes. @@ -6269,7 +6529,8 @@ void process_load_url(LLMessageSystem* msg, void**)  	// Add to list of pending name lookups  	gLoadUrlList.push_back(payload); -	gCacheName->get(owner_id, owner_is_group, &callback_load_url_name); +	gCacheName->get(owner_id, owner_is_group, +		boost::bind(&callback_load_url_name, _1, _2, _3));  } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 15bdf126c5..5655eed5c4 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -69,6 +69,7 @@  #include "llface.h"  #include "llfloaterproperties.h"  #include "llfollowcam.h" +#include "llhudtext.h"  #include "llselectmgr.h"  #include "llrendersphere.h"  #include "lltooldraganddrop.h" @@ -1098,7 +1099,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  					// alpha was flipped so that it zero encoded better  					coloru.mV[3] = 255 - coloru.mV[3];  					mText->setColor(LLColor4(coloru)); -					mText->setStringUTF8(temp_string); +					mText->setString(temp_string);  					if (mDrawable.notNull())  					{ @@ -1490,7 +1491,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  					dp->unpackBinaryDataFixed(coloru.mV, 4, "Color");  					coloru.mV[3] = 255 - coloru.mV[3];  					mText->setColor(LLColor4(coloru)); -					mText->setStringUTF8(temp_string); +					mText->setString(temp_string);  					setChanged(TEXTURE);  				} @@ -4156,7 +4157,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text)  		mText->setOnHUDAttachment(isHUDAttachment());  	}  	mText->setColor(LLColor4::white); -	mText->setStringUTF8(utf8text); +	mText->setString(utf8text);  	mText->setZCompare(FALSE);  	mText->setDoFade(FALSE);  	updateText(); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index be83fb7ef8..346f33727f 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -37,7 +37,6 @@  #include "llassetstorage.h"  #include "lldarrayptr.h" -#include "llhudtext.h"  #include "llhudicon.h"  #include "llinventory.h"  #include "llrefcount.h" @@ -60,6 +59,7 @@ class LLColor4;  class LLFrameTimer;  class LLDrawable;  class LLHost; +class LLHUDText;  class LLWorld;  class LLNameValue;  class LLNetMap; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index fc94fbafac..7e5fa2f84d 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -53,7 +53,7 @@  #include "lltooltip.h"  #include "llworld.h"  #include "llstring.h" -#include "llhudtext.h" +#include "llhudnametag.h"  #include "lldrawable.h"  #include "xform.h"  #include "llsky.h" @@ -1201,7 +1201,7 @@ void LLViewerObjectList::generatePickList(LLCamera &camera)  			}  		} -		LLHUDText::addPickable(mSelectPickList); +		LLHUDNameTag::addPickable(mSelectPickList);  		for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();  			iter != LLCharacter::sInstances.end(); ++iter) diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index a591cc1e14..8e1ce03964 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2075,10 +2075,7 @@ void LLViewerParcelMgr::deedLandToGroup()  	args["GROUP_NAME"] = group_name;  	if(mCurrentParcel->getContributeWithDeed())  	{ -		std::string first_name, last_name; -		gCacheName->getName(mCurrentParcel->getOwnerID(), first_name, last_name); -		args["FIRST_NAME"] = first_name; -		args["LAST_NAME"] = last_name; +		args["NAME"] = LLSLURL("agent", mCurrentParcel->getOwnerID(), "completename").getSLURLString();  		LLNotificationsUtil::add("DeedLandToGroupWithContribution",args, LLSD(), deedAlertCB);  	}  	else diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 004d138221..9964c67afc 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -34,7 +34,9 @@  #include "llviewerregion.h" +// linden libraries  #include "indra_constants.h" +#include "llavatarnamecache.h"		// name lookup cap url  #include "llfloaterreg.h"  #include "llmath.h"  #include "llhttpclient.h" @@ -174,7 +176,9 @@ public:  				mRegion->showReleaseNotes();  			}  		} -		 + +		mRegion->setCapabilitiesReceived(true); +  		if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())  		{  			LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); @@ -232,7 +236,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,      // LLCapabilityListener binds all the globals it expects to need at      // construction time.      mCapabilityListener(host.getString(), gMessageSystem, *this, -                        gAgent.getID(), gAgent.getSessionID()) +                        gAgent.getID(), gAgent.getSessionID()), +	mCapabilitiesReceived(false)  {  	mWidth = region_width_meters;  	mOriginGlobal = from_region_handle(handle);  @@ -1486,6 +1491,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	LLSD capabilityNames = LLSD::emptyArray();  	capabilityNames.append("AttachmentResources"); +	capabilityNames.append("AvatarPickerSearch");  	capabilityNames.append("ChatSessionRequest");  	capabilityNames.append("CopyInventoryFromNotecard");  	capabilityNames.append("DispatchRegionInfo"); @@ -1496,6 +1502,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	capabilityNames.append("ObjectMediaNavigate");  	capabilityNames.append("FetchLib");  	capabilityNames.append("FetchLibDescendents"); +	capabilityNames.append("GetDisplayNames");  	capabilityNames.append("GetTexture");  	capabilityNames.append("GroupProposalBallot");  	capabilityNames.append("HomeLocation"); @@ -1517,6 +1524,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	capabilityNames.append("SendUserReport");  	capabilityNames.append("SendUserReportWithScreenshot");  	capabilityNames.append("ServerReleaseNotes"); +	capabilityNames.append("SetDisplayName");  	capabilityNames.append("StartGroupProposal");  	capabilityNames.append("TextureStats");  	capabilityNames.append("UntrustedSimulatorMessage"); @@ -1578,6 +1586,16 @@ std::string LLViewerRegion::getCapability(const std::string& name) const  	return iter->second;  } +bool LLViewerRegion::capabilitiesReceived() const +{ +	return mCapabilitiesReceived; +} + +void LLViewerRegion::setCapabilitiesReceived(bool received) +{ +	mCapabilitiesReceived = received; +} +  void LLViewerRegion::logActiveCapabilities() const  {  	int count = 0; diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index a9e7ef771c..b0169c33c0 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -235,6 +235,11 @@ public:  	void setCapability(const std::string& name, const std::string& url);  	// implements LLCapabilityProvider      virtual std::string getCapability(const std::string& name) const; + +	// has region received its final (not seed) capability list? +	bool capabilitiesReceived() const; +	void setCapabilitiesReceived(bool received); +  	static bool isSpecialCapabilityName(const std::string &name);  	void logActiveCapabilities() const; @@ -417,6 +422,7 @@ private:  private:  	bool	mAlive;					// can become false if circuit disconnects +	bool	mCapabilitiesReceived;  	//spatial partitions for objects in this region  	std::vector<LLSpatialPartition*> mObjectPartition; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5f0fcb72f0..b480883b3a 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -120,6 +120,7 @@  #include "llglheaders.h"  #include "lltooltip.h"  #include "llhudmanager.h" +#include "llhudobject.h"  #include "llhudview.h"  #include "llimagebmp.h"  #include "llimagej2c.h" @@ -1178,12 +1179,8 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window,  S32 x,  S32 y, S32 width,  S  		//SetBKColor(hdc, RGB(255, 255, 255));  		FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255))); -		std::string name_str; -		LLAgentUI::buildName(name_str); -  		std::string temp_str; -		temp_str = llformat( "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f",		/* Flawfinder: ignore */ -				name_str.c_str(), +		temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f",		/* Flawfinder: ignore */  				LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(),  				LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0),  				LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0)); @@ -1877,7 +1874,7 @@ void LLViewerWindow::reshape(S32 width, S32 height)  		// clear font width caches  		if (display_scale_changed)  		{ -			LLHUDText::reshape(); +			LLHUDObject::reshapeAll();  		}  		sendShapeToSim(); @@ -4064,7 +4061,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei  		send_agent_pause();  		//rescale fonts  		initFonts(scale_factor); -		LLHUDText::reshape(); +		LLHUDObject::reshapeAll();  	}  	S32 output_buffer_offset_y = 0; @@ -4193,7 +4190,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei  	if (high_res)  	{  		initFonts(1.f); -		LLHUDText::reshape(); +		LLHUDObject::reshapeAll();  	}  	// Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 72aec07e67..06a0e854bc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -44,6 +44,7 @@  #include <ctype.h>  #include "llaudioengine.h" +#include "llcachename.h"  #include "noise.h"  #include "sound_ids.h" @@ -51,8 +52,10 @@  #include "llagentcamera.h"  #include "llagentwearables.h"  #include "llanimationstates.h" +#include "llavatarnamecache.h"  #include "llavatarpropertiesprocessor.h"  #include "llviewercontrol.h" +#include "llcallingcard.h"		// IDEVO for LLAvatarTracker  #include "lldrawpoolavatar.h"  #include "lldriverparam.h"  #include "lleditingmotion.h" @@ -61,6 +64,8 @@  #include "llheadrotmotion.h"  #include "llhudeffecttrail.h"  #include "llhudmanager.h" +#include "llhudnametag.h" +#include "llhudtext.h"				// for mText/mDebugText  #include "llkeyframefallmotion.h"  #include "llkeyframestandmotion.h"  #include "llkeyframewalkmotion.h" @@ -659,12 +664,14 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mAppearanceAnimating(FALSE),  	mNameString(),  	mTitle(), -	mNameAway(FALSE), -	mNameBusy(FALSE), -	mNameMute(FALSE), +	mNameAway(false), +	mNameBusy(false), +	mNameMute(false), +	mNameAppearance(false), +	mNameFriend(false), +	mNameAlpha(0.f),  	mRenderGroupTitles(sRenderGroupTitles), -	mNameAppearance(FALSE), -	mNameCloud(FALSE), +	mNameCloud(false),  	mFirstTEMessageReceived( FALSE ),  	mFirstAppearanceMessageReceived( FALSE ),  	mCulled( FALSE ), @@ -2783,8 +2790,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)  								 && gSavedSettings.getS32("AvatarNameTagMode") ));  	} -	if ( render_name ) +	if ( !render_name )  	{ +		if (mNameText) +		{ +			// ...clean up old name tag +			mNameText->markDead(); +			mNameText = NULL; +			sNumVisibleChatBubbles--; +		} +		return; +	} +  		BOOL new_name = FALSE;  		if (visible_chat != mVisibleChat)  		{ @@ -2800,7 +2817,6 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)  		// First Calculate Alpha  		// If alpha > 0, create mNameText if necessary, otherwise delete it -		{  			F32 alpha = 0.f;  			if (mAppAngle > 5.f)  			{ @@ -2821,66 +2837,62 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)  				alpha = (mAppAngle-2.f)/3.f;  			} -			if (alpha > 0.f) +	if (alpha <= 0.f)  			{ +		if (mNameText) +		{ +			mNameText->markDead(); +			mNameText = NULL; +			sNumVisibleChatBubbles--; +		} +		return; +	} +  				if (!mNameText)  				{ -					mNameText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); -					mNameText->setMass(10.f); +		mNameText = static_cast<LLHUDNameTag*>( LLHUDObject::addHUDObject( +			LLHUDObject::LL_HUD_NAME_TAG) ); +		//mNameText->setMass(10.f);  					mNameText->setSourceObject(this); -					mNameText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); +		mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP);  					mNameText->setVisibleOffScreen(TRUE);  					mNameText->setMaxLines(11);  					mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f); -					mNameText->setUseBubble(TRUE);  					sNumVisibleChatBubbles++;  					new_name = TRUE;  				} -				LLColor4 avatar_name_color = LLUIColorTable::instance().getColor( "AvatarNameColor" ); -				avatar_name_color.setAlpha(alpha); -				mNameText->setColor(avatar_name_color); +	LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last); +	mNameText->setPositionAgent(name_position); -				LLQuaternion root_rot = mRoot.getWorldRotation(); -				mNameText->setUsePixelSize(TRUE); -				LLVector3 pixel_right_vec; -				LLVector3 pixel_up_vec; -				LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec); -				LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin(); -				camera_to_av.normalize(); -				LLVector3 local_camera_at = camera_to_av * ~root_rot; -				LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis(); -				local_camera_up.normalize(); -				local_camera_up = local_camera_up * ~root_rot; +	idleUpdateNameTagText(new_name); -				local_camera_up.scaleVec(mBodySize * 0.5f); -				local_camera_at.scaleVec(mBodySize * 0.5f); +	idleUpdateNameTagAlpha(new_name, alpha); +} -				LLVector3 name_position = mRoot.getWorldPosition() +  -					(local_camera_up * root_rot) - -					(projected_vec(local_camera_at * root_rot, camera_to_av)); -				name_position += pixel_up_vec * 15.f; -				mNameText->setPositionAgent(name_position); -			} -			else if (mNameText) +void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)  			{ -				mNameText->markDead(); -				mNameText = NULL; -				sNumVisibleChatBubbles--; -			} -		} -		  		LLNameValue *title = getNVPair("Title");  		LLNameValue* firstname = getNVPair("FirstName");  		LLNameValue* lastname = getNVPair("LastName"); -		if (mNameText.notNull() && firstname && lastname) +	// Avatars must have a first and last name +	if (!firstname || !lastname) return; + +	bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY)  != mSignaledAnimations.end(); +	bool is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); +	bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); +	bool is_muted; +	if (isSelf()) +	{ +		is_muted = false; +	} +	else  		{ -			const BOOL is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY)  != mSignaledAnimations.end(); -			const BOOL is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); -			const BOOL is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); -			const BOOL is_muted = isSelf() ? FALSE : LLMuteList::getInstance()->isMuted(getID()); -			const BOOL is_cloud = getIsCloud(); +		is_muted = LLMuteList::getInstance()->isMuted(getID()); +	} +	bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); +	bool is_cloud = getIsCloud();  			if (gSavedSettings.getBOOL("DebugAvatarRezTime"))  			{ @@ -2905,105 +2917,129 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)  				}  			} -			if (mNameString.empty() || -				new_name || -				(!title && !mTitle.empty()) || -				(title && mTitle != title->getString()) || -				(is_away != mNameAway || is_busy != mNameBusy || is_muted != mNameMute) +	// Rebuild name tag if state change detected +	if (mNameString.empty() +		|| new_name +		|| (!title && !mTitle.empty()) +		|| (title && mTitle != title->getString()) +		|| is_away != mNameAway  +		|| is_busy != mNameBusy  +		|| is_muted != mNameMute  				|| is_appearance != mNameAppearance  -				|| is_cloud != mNameCloud -				) -			{ -				std::string line; -				if (!sRenderGroupTitles) -				{ -					// If all group titles are turned off, stack first name -					// on a line above last name -					line += firstname->getString(); -					line += "\n"; -				} -				else if (title && title->getString() && title->getString()[0] != '\0') +		|| is_friend != mNameFriend +		|| is_cloud != mNameCloud)  				{ -					line += title->getString(); -					LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR); -					line += "\n"; -					line += firstname->getString(); -				} -				else -				{ -					line += firstname->getString(); -				} +		LLColor4 name_tag_color = getNameTagColor(is_friend); -				line += " "; -				line += lastname->getString(); -				BOOL need_comma = FALSE; +		clearNameTag(); -				if (is_away || is_muted || is_busy) +		if (is_away || is_muted || is_busy || is_appearance)  				{ -					line += " ("; +			std::string line;  					if (is_away)  					{  						line += LLTrans::getString("AvatarAway"); -						need_comma = TRUE; +				line += ", ";  					}  					if (is_busy)  					{ -						if (need_comma) +				line += LLTrans::getString("AvatarBusy"); +				line += ", "; +			} +			if (is_muted)  						{ +				line += LLTrans::getString("AvatarMuted");  							line += ", ";  						} -						line += LLTrans::getString("AvatarBusy"); -						need_comma = TRUE; +			if (is_appearance) +			{ +				line += LLTrans::getString("AvatarEditingAppearance"); +				line += ", ";  					} -					if (is_muted) +			if (is_cloud)  					{ -						if (need_comma) +				line += LLTrans::getString("LoadingData"); +				line += ", "; +			} +			// trim last ", " +			line.resize( line.length() - 2 ); +			LLColor4 status_color = +				LLUIColorTable::getInstance()->getColor("NameTagStatus"); +			addNameTagLine(line, status_color, LLFontGL::NORMAL, +				LLFontGL::getFontSansSerifSmall()); +		} + +		if (sRenderGroupTitles +			&& title && title->getString() && title->getString()[0] != '\0')  						{ -							line += ", "; +			LLColor4 group_color = +				LLUIColorTable::getInstance()->getColor("NameTagGroup"); +			std::string title_str = title->getString(); +			LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR); +			addNameTagLine(title_str, group_color, LLFontGL::NORMAL, +				LLFontGL::getFontSansSerifSmall());  						} -						line += LLTrans::getString("AvatarMuted"); -						need_comma = TRUE; + +		static LLUICachedControl<bool> show_display_names("NameTagShowDisplayNames"); +		static LLUICachedControl<bool> show_usernames("NameTagShowUsernames"); + +		if (LLAvatarNameCache::useDisplayNames()) +		{ +			LLAvatarName av_name; +			if (!LLAvatarNameCache::get(getID(), &av_name)) +			{ +				// ...call this function back when the name arrives +				// and force a rebuild +				LLAvatarNameCache::get(getID(), +					boost::bind(&LLVOAvatar::clearNameTag, this));  					} -					line += ")"; + +			// Might be blank if name not available yet, that's OK +			if (show_display_names) +			{ +				addNameTagLine(av_name.mDisplayName, name_tag_color, LLFontGL::NORMAL, +					LLFontGL::getFontSansSerif());  				} -				if (is_cloud) +			// Suppress SLID display if display name matches exactly (ugh) +			if (show_usernames && !av_name.mIsDisplayNameDefault)  				{ -					line += "\n"; -					line += "(" + LLTrans::getString("LoadingData") + ")"; +				// *HACK: Desaturate the color +				LLColor4 username_color = name_tag_color * 0.83f; +				addNameTagLine(av_name.mUsername, username_color, LLFontGL::NORMAL, +					LLFontGL::getFontSansSerifSmall()); +			}  				} -				else if (is_appearance) +		else  				{ -					line += "\n"; -					line += LLTrans::getString("AvatarEditingAppearance"); +			const LLFontGL* font = LLFontGL::getFontSansSerif(); +			std::string full_name = +				LLCacheName::buildFullName( firstname->getString(), lastname->getString() ); +			addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font);  				} +  				mNameAway = is_away;  				mNameBusy = is_busy;  				mNameMute = is_muted;  				mNameAppearance = is_appearance; +		mNameFriend = is_friend;  				mNameCloud = is_cloud;  				mTitle = title ? title->getString() : "";  				LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR); -				mNameString = utf8str_to_wstring(line);  				new_name = TRUE;  			} -			if (visible_chat) +	if (mVisibleChat)  			{ -				mNameText->setDropShadow(TRUE);  				mNameText->setFont(LLFontGL::getFontSansSerif()); -				mNameText->setTextAlignment(LLHUDText::ALIGN_TEXT_LEFT); +		mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_LEFT);  				mNameText->setFadeDistance(CHAT_NORMAL_RADIUS * 2.f, 5.f); -				if (new_name) -				{ -					mNameText->setLabel(mNameString); -				}  				char line[MAX_STRING];		/* Flawfinder: ignore */  				line[0] = '\0';  				std::deque<LLChat>::iterator chat_iter = mChats.begin();  				mNameText->clearString(); -				LLColor4 new_chat = LLUIColorTable::instance().getColor( "AvatarNameColor" ); +		LLColor4 new_chat = LLUIColorTable::instance().getColor( "NameTagChat" );  				LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f);  				LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f);  				if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES)  @@ -3030,17 +3066,17 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)  					if (chat_fade_amt < 1.f)  					{  						F32 u = clamp_rescale(chat_fade_amt, 0.9f, 1.f, 0.f, 1.f); -						mNameText->addLine(utf8str_to_wstring(chat_iter->mText), lerp(new_chat, normal_chat, u), style); +						mNameText->addLine(chat_iter->mText, lerp(new_chat, normal_chat, u), style);  					}  					else if (chat_fade_amt < 2.f)  					{  						F32 u = clamp_rescale(chat_fade_amt, 1.9f, 2.f, 0.f, 1.f); -						mNameText->addLine(utf8str_to_wstring(chat_iter->mText), lerp(normal_chat, old_chat, u), style); +						mNameText->addLine(chat_iter->mText, lerp(normal_chat, old_chat, u), style);  					}  					else if (chat_fade_amt < 3.f)  					{  						// *NOTE: only remove lines down to minimum number -						mNameText->addLine(utf8str_to_wstring(chat_iter->mText), old_chat, style); +						mNameText->addLine(chat_iter->mText, old_chat, style);  					}  				}  				mNameText->setVisibleOffScreen(TRUE); @@ -3065,24 +3101,129 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)  			}  			else  			{ -				mNameText->setFont(LLFontGL::getFontSansSerif()); -				mNameText->setTextAlignment(LLHUDText::ALIGN_TEXT_CENTER); +		// ...not using chat bubbles, just names +		mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_CENTER);  				mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f);  				mNameText->setVisibleOffScreen(FALSE); -				if (new_name) +	} +} + +void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font) +{ +	llassert(mNameText); +	if (mVisibleChat) +	{ +		mNameText->addLabel(line); +	} +	else +	{ +		mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font); +	} +	mNameString += line; +	mNameString += '\n'; +} + +void LLVOAvatar::clearNameTag() +{ +	mNameString.clear(); +	if (mNameText)  				{  					mNameText->setLabel(""); -					mNameText->setString(mNameString); +		mNameText->setString( "" ); +	} +} + +//static +void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id) +{ +	LLViewerObject* obj = gObjectList.findObject(agent_id); +	if (!obj) return; + +	LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(obj); +	if (!avatar) return; + +	avatar->clearNameTag(); +} + +//static +void LLVOAvatar::invalidateNameTags() +{ +	std::vector<LLCharacter*>::iterator it = LLCharacter::sInstances.begin(); +	for ( ; it != LLCharacter::sInstances.end(); ++it) +	{ +		LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*it); +		if (!avatar) continue; +		if (avatar->isDead()) continue; + +		avatar->clearNameTag();  				}  			} + +// Compute name tag position during idle update +LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) +{ +	LLQuaternion root_rot = mRoot.getWorldRotation(); +	LLVector3 pixel_right_vec; +	LLVector3 pixel_up_vec; +	LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec); +	LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin(); +	camera_to_av.normalize(); +	LLVector3 local_camera_at = camera_to_av * ~root_rot; +	LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis(); +	local_camera_up.normalize(); +	local_camera_up = local_camera_up * ~root_rot; + +	local_camera_up.scaleVec(mBodySize * 0.5f); +	local_camera_at.scaleVec(mBodySize * 0.5f); + +	LLVector3 name_position = mRoot.getWorldPosition() +  +		(local_camera_up * root_rot) - +		(projected_vec(local_camera_at * root_rot, camera_to_av)); +	name_position += pixel_up_vec * 15.f; +	return name_position; +		} + +void LLVOAvatar::idleUpdateNameTagAlpha(BOOL new_name, F32 alpha) +{ +	llassert(mNameText); + +	if (new_name +		|| alpha != mNameAlpha) +	{ +		mNameText->setAlpha(alpha); +		mNameAlpha = alpha; +	} +} + +LLColor4 LLVOAvatar::getNameTagColor(bool is_friend) +{ +	static LLUICachedControl<bool> show_friends("NameTagShowFriends"); +	const char* color_name; +	if (show_friends && is_friend) +	{ +		color_name = "NameTagFriend"; +	} +	else if (LLAvatarNameCache::useDisplayNames()) +	{ +		// ...color based on whether username "matches" a computed display +		// name +		LLAvatarName av_name; +		if (LLAvatarNameCache::get(getID(), &av_name) +			&& av_name.mIsDisplayNameDefault) +		{ +			color_name = "NameTagMatch";  		} +		else +		{ +			color_name = "NameTagMismatch";  	} -	else if (mNameText) +	} +	else  	{ -		mNameText->markDead(); -		mNameText = NULL; -		sNumVisibleChatBubbles--; +		// ...not using display names +		color_name = "NameTagLegacy";  	} +	return LLUIColorTable::getInstance()->getColor( color_name );  }  //-------------------------------------------------------------------- @@ -6904,7 +7045,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  	{  		releaseComponentTextures();  	} -		 +	  	// parse visual params  	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);  	bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing @@ -6997,9 +7138,9 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  			// re-request appearance, hoping that it comes back with a shape next time  			llinfos << "Re-requesting AvatarAppearance for object: "  << getID() << llendl;  			LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); -		} -		else -		{ +	} +	else +	{  			llinfos << "That's okay, we already have a non-default shape for object: "  << getID() << llendl;  			// we don't really care.  		} @@ -7891,9 +8032,7 @@ std::string LLVOAvatar::getFullname() const  	LLNameValue* last  = getNVPair("LastName");   	if (first && last)  	{ -		name += first->getString(); -		name += " "; -		name += last->getString(); +		name = LLCacheName::buildFullName( first->getString(), last->getString() );  	}  	return name; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 2ef333a0a0..3397acceba 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -65,7 +65,7 @@ extern const LLUUID ANIM_AGENT_WALK_ADJUST;  class LLTexLayerSet;  class LLVoiceVisualizer; -class LLHUDText; +class LLHUDNameTag;  class LLHUDEffectSpiral;  class LLTexGlobalColor;  class LLVOAvatarBoneInfo; @@ -213,6 +213,15 @@ public:  	void 			idleUpdateLoadingEffect();  	void 			idleUpdateWindEffect();  	void 			idleUpdateNameTag(const LLVector3& root_pos_last); +	void			idleUpdateNameTagText(BOOL new_name); +	LLVector3		idleUpdateNameTagPosition(const LLVector3& root_pos_last); +	void			idleUpdateNameTagAlpha(BOOL new_name, F32 alpha); +	LLColor4		getNameTagColor(bool is_friend); +	void			clearNameTag(); +	static void		invalidateNameTag(const LLUUID& agent_id); +	// force all name tags to rebuild, useful when display names turned on/off +	static void		invalidateNameTags(); +	void			addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);  	void 			idleUpdateRenderCost();  	void 			idleUpdateTractorBeam();  	void 			idleUpdateBelowWater(); @@ -833,13 +842,15 @@ protected:  	static void		getAnimLabels(LLDynamicArray<std::string>* labels);  	static void		getAnimNames(LLDynamicArray<std::string>* names);	  private: -	LLWString 		mNameString; +	std::string		mNameString;		// UTF-8 title + name + status  	std::string  	mTitle; -	BOOL	  		mNameAway; -	BOOL	  		mNameBusy; -	BOOL	  		mNameMute; -	BOOL      		mNameAppearance; -	BOOL      		mNameCloud; +	bool	  		mNameAway; +	bool	  		mNameBusy; +	bool	  		mNameMute; +	bool      		mNameAppearance; +	bool			mNameFriend; +	bool			mNameCloud; +	F32				mNameAlpha;  	BOOL      		mRenderGroupTitles;  	//-------------------------------------------------------------------- @@ -847,7 +858,7 @@ private:  	//--------------------------------------------------------------------  public:  	LLFrameTimer	mChatTimer; -	LLPointer<LLHUDText> mNameText; +	LLPointer<LLHUDNameTag> mNameText;  private:  	LLFrameTimer	mTimeVisible;  	std::deque<LLChat> mChats; diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 074f9b8bba..ee843435bc 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -82,6 +82,9 @@ public:  	virtual void getChannelInfo();  	virtual BOOL isActive();  	virtual BOOL callStarted(); + +	// Session name is a UI label used for feedback about which person, +	// group, or phone number you are talking to  	const std::string& getSessionName() const { return mSessionName; }  	boost::signals2::connection setStateChangedCallback(const state_changed_signal_t::slot_type& callback) diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 4dc9edb247..25c4914c13 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -37,6 +37,8 @@  #include "llsdutil.h" +// Linden library includes +#include "llavatarnamecache.h"  #include "llvoavatarself.h"  #include "llbufferstream.h"  #include "llfile.h" @@ -52,6 +54,8 @@  #include "llviewercontrol.h"  #include "llkeyboard.h"  #include "llappviewer.h"	// for gDisconnected, gDisableVoice + +// Viewer includes  #include "llmutelist.h"  // to check for muted avatars  #include "llagent.h"  #include "llcachename.h" @@ -2806,12 +2810,16 @@ void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream)  void LLVivoxVoiceClient::checkFriend(const LLUUID& id)  { -	std::string name;  	buddyListEntry *buddy = findBuddy(id);  	// Make sure we don't add a name before it's been looked up. -	if(gCacheName->getFullName(id, name)) +	LLAvatarName av_name; +	if(LLAvatarNameCache::get(id, &av_name))  	{ +		// *NOTE: For now, we feed legacy names to Vivox because I don't know +		// if their service can support a mix of new and old clients with +		// different sorts of names. +		std::string name = av_name.getLegacyName();  		const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id);  		bool canSeeMeOnline = false; @@ -6363,16 +6371,18 @@ void LLVivoxVoiceClient::notifyFriendObservers()  void LLVivoxVoiceClient::lookupName(const LLUUID &id)  { -	BOOL is_group = FALSE; -	gCacheName->get(id, is_group, &LLVivoxVoiceClient::onAvatarNameLookup); +	LLAvatarNameCache::get(id, +		boost::bind(&LLVivoxVoiceClient::onAvatarNameCache, +			this, _1, _2));  } -//static -void LLVivoxVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id, +										   const LLAvatarName& av_name)  { -		std::string name = llformat("%s %s", first.c_str(), last.c_str()); -		LLVivoxVoiceClient::getInstance()->avatarNameResolved(id, name); -	 +	// For Vivox, we use the legacy name because I'm uncertain whether or +	// not their service can tolerate switching to Username or Display Name +	std::string legacy_name = av_name.getLegacyName(); +	avatarNameResolved(agent_id, legacy_name);	  }  void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name) diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index f858f8f74e..d382cb0a70 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -51,7 +51,7 @@ class LLVivoxProtocolParser;  #endif  #include "llvoiceclient.h" - +class LLAvatarName;  class LLVivoxVoiceAccountProvisionResponder;  class LLVivoxVoiceClientMuteListObserver;  class LLVivoxVoiceClientFriendsObserver;	 @@ -655,7 +655,7 @@ protected:  	void leaveAudioSession();  	void lookupName(const LLUUID &id); -	static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); +	void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);  	void avatarNameResolved(const LLUUID &id, const std::string &name);  	///////////////////////////// diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b578cb9f69..4f4679a436 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -70,6 +70,8 @@  #include "llfloaterreg.h"  #include "llgldbg.h"  #include "llhudmanager.h" +#include "llhudnametag.h" +#include "llhudtext.h"  #include "lllightconstants.h"  #include "llresmgr.h"  #include "llselectmgr.h" @@ -2087,6 +2089,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)  	}  	LLHUDText::shiftAll(offset); +	LLHUDNameTag::shiftAll(offset);  	display_update_camera();  } @@ -5277,7 +5280,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,  		++iter)  	{  		LLVOAvatar* av = (LLVOAvatar*) *iter; -		if (av->mNameText.notNull() && av->mNameText->lineSegmentIntersect(start, local_end, position)) +		if (av->mNameText.notNull() +			&& av->mNameText->lineSegmentIntersect(start, local_end, position))  		{  			drawable = av->mDrawable;  			local_end = position; diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index 2188c71ff9..2098ad1a39 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -118,9 +118,6 @@       name="AlertTextColor"       value="0.58 0.66 0.84 1" />      <color -     name="AvatarNameColor" -     reference="White" /> -    <color       name="AvatarListItemIconDefaultColor"       reference="White" />      <color @@ -531,6 +528,38 @@      <color       name="MultiSliderTriangleColor"       reference="Unused?" /> +  <!-- +    <color +      name="NameTagBackground" +      value="0.85 0.85 0.85 0.80" /> +      --> +    <color +      name="NameTagBackground" +      value="0 0 0 1" /> +    <color +     name="NameTagChat" +     reference="White" /> +    <color +     name="NameTagFriend" +     value="0.447 0.784 0.663 1" /> +    <color +     name="NameTagGroup" +     value="1 1 1 1" /> +    <color +     name="NameTagLegacy" +     reference="White" /> +    <color +     name="NameTagMatch" +     reference="White" /> +    <color +     name="NameTagMismatch" +     reference="White" /> +    <color +     name="NameTagSLID" +     value="1 1 1 1" /> +    <color +     name="NameTagStatus" +     value="1 1 1 1" />      <color       name="NetMapBackgroundColor"       value="0 0 0 1" /> @@ -565,6 +594,9 @@       name="NotifyTextColor"       reference="White" />      <color +     name="ObjectBubbleColor" +     reference="DkGray_66" /> +    <color       name="ObjectChatColor"       reference="EmphasisColor" />      <color diff --git a/indra/newview/skins/default/textures/Rounded_Rect.png b/indra/newview/skins/default/textures/Rounded_Rect.png Binary files differnew file mode 100644 index 0000000000..c270c28039 --- /dev/null +++ b/indra/newview/skins/default/textures/Rounded_Rect.png diff --git a/indra/newview/skins/default/textures/icons/Person_Check.png b/indra/newview/skins/default/textures/icons/Person_Check.png Binary files differnew file mode 100644 index 0000000000..f8638540d4 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Person_Check.png diff --git a/indra/newview/skins/default/textures/icons/Person_Star.png b/indra/newview/skins/default/textures/icons/Person_Star.png Binary files differnew file mode 100644 index 0000000000..ad10580ac4 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Person_Star.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 082b37d80b..f293bbd1af 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -358,6 +358,8 @@ with the same filename but different name    <texture name="Pause_Off" file_name="icons/Pause_Off.png" preload="false" />    <texture name="Pause_Over" file_name="icons/Pause_Over.png" preload="false" />    <texture name="Pause_Press" file_name="icons/Pause_Press.png" preload="false" /> +  <texture name="Person_Check" file_name="icons/Person_Check.png" preload="false" /> +  <texture name="Person_Star" file_name="icons/Person_Star.png" preload="false" />    <texture name="Play_Off" file_name="icons/Play_Off.png" preload="false" />    <texture name="Play_Over" file_name="icons/Play_Over.png" preload="false" />    <texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" /> @@ -387,6 +389,7 @@ with the same filename but different name    <texture name="Resize_Corner" file_name="windows/Resize_Corner.png" preload="true" /> +  <texture name="Rounded_Rect"	file_name="Rounded_Rect.png" preload="true" scale.left="6" scale.top="24" scale.right="58" scale.bottom="6" />    <texture name="Rounded_Square"	file_name="rounded_square.j2c" preload="true" scale.left="16" scale.top="16" scale.right="112" scale.bottom="16" />    <texture name="Row_Selection" file_name="navbar/Row_Selection.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/da/floater_windlight_options.xml b/indra/newview/skins/default/xui/da/floater_windlight_options.xml index 65f3f67a70..56f94b24e9 100644 --- a/indra/newview/skins/default/xui/da/floater_windlight_options.xml +++ b/indra/newview/skins/default/xui/da/floater_windlight_options.xml @@ -1,18 +1,18 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <floater name="WindLight floater" title="AVANCERET OPSÆTNING FOR HIMMEL">  	<text name="KeyFramePresetsText">  		Faste indstillinger:  	</text> -	<button label="Ny" label_selected="Ny" name="WLNewPreset"/> -	<button label="Gem" label_selected="Gem" name="WLSavePreset"/> -	<button label="Slet" label_selected="Slet" name="WLDeletePreset"/> -	<button label="Dags cyklus" label_selected="Dags cyklus" name="WLDayCycleMenuButton"/> +	<button label="Ny" label_selected="Ny" name="WLNewPreset" /> +	<button label="Gem" label_selected="Gem" name="WLSavePreset" /> +	<button label="Slet" label_selected="Slet" name="WLDeletePreset" /> +	<button label="Dags cyklus" label_selected="Dags cyklus" name="WLDayCycleMenuButton" />  	<tab_container name="WindLight Tabs">  		<panel label="ATMOSFÆRE" name="Atmosphere">  			<text name="BHText">  				Blå - horisont  			</text> -			<button label="?" name="WLBlueHorizonHelp"/> +			<button label="?" name="WLBlueHorizonHelp" />  			<text name="BHText2">  				R  			</text> @@ -25,19 +25,19 @@  			<text name="BHText5">  				I  			</text> -			<slider label="" name="WLBlueHorizonR"/> -			<slider label="" name="WLBlueHorizonG"/> -			<slider label="" name="WLBlueHorizonB"/> -			<slider label="" name="WLBlueHorizonI"/> +			<slider label="" name="WLBlueHorizonR" /> +			<slider label="" name="WLBlueHorizonG" /> +			<slider label="" name="WLBlueHorizonB" /> +			<slider label="" name="WLBlueHorizonI" />  			<text name="BDensText">  				Dis - horisont  			</text> -			<button label="?" name="WLHazeHorizonHelp"/> -			<slider label="" name="WLHazeHorizon"/> +			<button label="?" name="WLHazeHorizonHelp" /> +			<slider label="" name="WLHazeHorizon" />  			<text name="BDensText2">  				Blå - tæthed  			</text> -			<button label="?" name="WLBlueDensityHelp"/> +			<button label="?" name="WLBlueDensityHelp" />  			<text name="BHText6">  				R  			</text> @@ -50,36 +50,36 @@  			<text name="BHText9">  				I  			</text> -			<slider label="" name="WLBlueDensityR"/> -			<slider label="" name="WLBlueDensityG"/> -			<slider label="" name="WLBlueDensityB"/> -			<slider label="" name="WLBlueDensityI"/> +			<slider label="" name="WLBlueDensityR" /> +			<slider label="" name="WLBlueDensityG" /> +			<slider label="" name="WLBlueDensityB" /> +			<slider label="" name="WLBlueDensityI" />  			<text name="HDText">  				Dis - intensitet  			</text> -			<button label="?" name="WLHazeDensityHelp"/> -			<slider label="" name="WLHazeDensity"/> +			<button label="?" name="WLHazeDensityHelp" /> +			<slider label="" name="WLHazeDensity" />  			<text name="DensMultText">  				Densitet faktor  			</text> -			<button label="?" name="WLDensityMultHelp"/> -			<slider label="" name="WLDensityMult"/> +			<button label="?" name="WLDensityMultHelp" /> +			<slider label="" name="WLDensityMult" />  			<text name="WLDistanceMultText">  				Distance faktor  			</text> -			<button label="?" name="WLDistanceMultHelp"/> -			<slider label="" name="WLDistanceMult"/> +			<button label="?" name="WLDistanceMultHelp" /> +			<slider label="" name="WLDistanceMult" />  			<text name="MaxAltText">  				Maximum højde  			</text> -			<button label="?" name="WLMaxAltitudeHelp"/> -			<slider label="" name="WLMaxAltitude"/> +			<button label="?" name="WLMaxAltitudeHelp" /> +			<slider label="" name="WLMaxAltitude" />  		</panel>  		<panel label="LYS" name="Lighting">  			<text name="SLCText">  				Sol/Måne farve  			</text> -			<button label="?" name="WLSunlightColorHelp"/> +			<button label="?" name="WLSunlightColorHelp" />  			<text name="BHText">  				R  			</text> @@ -92,19 +92,19 @@  			<text name="BHText4">  				I  			</text> -			<slider label="" name="WLSunlightR"/> -			<slider label="" name="WLSunlightG"/> -			<slider label="" name="WLSunlightB"/> -			<slider label="" name="WLSunlightI"/> +			<slider label="" name="WLSunlightR" /> +			<slider label="" name="WLSunlightG" /> +			<slider label="" name="WLSunlightB" /> +			<slider label="" name="WLSunlightI" />  			<text name="TODText">  				Sol/Måne position  			</text> -			<button label="?" name="WLTimeOfDayHelp"/> -			<slider label="" name="WLSunAngle"/> +			<button label="?" name="WLTimeOfDayHelp" /> +			<slider label="" name="WLSunAngle" />  			<text name="WLAmbientText">  				Omgivende  			</text> -			<button label="?" name="WLAmbientHelp"/> +			<button label="?" name="WLAmbientHelp" />  			<text name="BHText5">  				R  			</text> @@ -117,37 +117,37 @@  			<text name="BHText8">  				I  			</text> -			<slider label="" name="WLAmbientR"/> -			<slider label="" name="WLAmbientG"/> -			<slider label="" name="WLAmbientB"/> -			<slider label="" name="WLAmbientI"/> +			<slider label="" name="WLAmbientR" /> +			<slider label="" name="WLAmbientG" /> +			<slider label="" name="WLAmbientB" /> +			<slider label="" name="WLAmbientI" />  			<text name="WLEastAngleText">  				Øst vinkel  			</text> -			<button label="?" name="WLEastAngleHelp"/> -			<slider label="" name="WLEastAngle"/> +			<button label="?" name="WLEastAngleHelp" /> +			<slider label="" name="WLEastAngle" />  			<text name="SunGlowText">  				Sol glød  			</text> -			<button label="?" name="WLSunGlowHelp"/> -			<slider label="Fokus " name="WLGlowB"/> -			<slider label="Størr. " name="WLGlowR"/> +			<button label="?" name="WLSunGlowHelp" /> +			<slider label="Fokus " name="WLGlowB" /> +			<slider label="Størr. " name="WLGlowR" />  			<text name="SceneGammaText">  				Lysintensitet (gamma)  			</text> -			<button label="?" name="WLSceneGammaHelp"/> -			<slider label="" name="WLGamma"/> +			<button label="?" name="WLSceneGammaHelp" /> +			<slider label="" name="WLGamma" />  			<text name="WLStarText">  				Stjerne intensitet  			</text> -			<button label="?" name="WLStarBrightnessHelp"/> -			<slider label="" name="WLStarAlpha"/> +			<button label="?" name="WLStarBrightnessHelp" /> +			<slider label="" name="WLStarAlpha" />  		</panel>  		<panel label="SKYER" name="Clouds">  			<text name="WLCloudColorText">  				Farve på skyer  			</text> -			<button label="?" name="WLCloudColorHelp"/> +			<button label="?" name="WLCloudColorHelp" />  			<text name="BHText">  				R  			</text> @@ -160,14 +160,14 @@  			<text name="BHText4">  				I  			</text> -			<slider label="" name="WLCloudColorR"/> -			<slider label="" name="WLCloudColorG"/> -			<slider label="" name="WLCloudColorB"/> -			<slider label="" name="WLCloudColorI"/> +			<slider label="" name="WLCloudColorR" /> +			<slider label="" name="WLCloudColorG" /> +			<slider label="" name="WLCloudColorB" /> +			<slider label="" name="WLCloudColorI" />  			<text name="WLCloudColorText2">  				Skyer XY/Tæthed  			</text> -			<button label="?" name="WLCloudDensityHelp"/> +			<button label="?" name="WLCloudDensityHelp" />  			<text name="BHText5">  				X  			</text> @@ -177,23 +177,23 @@  			<text name="BHText7">  				T  			</text> -			<slider label="" name="WLCloudX"/> -			<slider label="" name="WLCloudY"/> -			<slider label="" name="WLCloudDensity"/> +			<slider label="" name="WLCloudX" /> +			<slider label="" name="WLCloudY" /> +			<slider label="" name="WLCloudDensity" />  			<text name="WLCloudCoverageText">  				Skydække  			</text> -			<button label="?" name="WLCloudCoverageHelp"/> -			<slider label="" name="WLCloudCoverage"/> +			<button label="?" name="WLCloudCoverageHelp" /> +			<slider label="" name="WLCloudCoverage" />  			<text name="WLCloudScaleText">  				Skystørrelse  			</text> -			<button label="?" name="WLCloudScaleHelp"/> -			<slider label="" name="WLCloudScale"/> +			<button label="?" name="WLCloudScaleHelp" /> +			<slider label="" name="WLCloudScale" />  			<text name="WLCloudDetailText">  				Sky detaljer(XY/tæthed)  			</text> -			<button label="?" name="WLCloudDetailHelp"/> +			<button label="?" name="WLCloudDetailHelp" />  			<text name="BHText8">  				X  			</text> @@ -203,23 +203,23 @@  			<text name="BHText10">  				T  			</text> -			<slider label="" name="WLCloudDetailX"/> -			<slider label="" name="WLCloudDetailY"/> -			<slider label="" name="WLCloudDetailDensity"/> +			<slider label="" name="WLCloudDetailX" /> +			<slider label="" name="WLCloudDetailY" /> +			<slider label="" name="WLCloudDetailDensity" />  			<text name="WLCloudScrollXText">  				Sky drift X  			</text> -			<button label="?" name="WLCloudScrollXHelp"/> -			<check_box label="Lås" name="WLCloudLockX"/> -			<slider label="" name="WLCloudScrollX"/> +			<button label="?" name="WLCloudScrollXHelp" /> +			<check_box label="Lås" name="WLCloudLockX" /> +			<slider label="" name="WLCloudScrollX" />  			<text name="WLCloudScrollYText">  				Sky drift Y  			</text> -			<button label="?" name="WLCloudScrollYHelp"/> -			<check_box label="Lås" name="WLCloudLockY"/> -			<slider label="" name="WLCloudScrollY"/> -			<check_box label="Benyt simple skyer" name="DrawClassicClouds"/> -			<button label="?" name="WLClassicCloudsHelp"/> +			<button label="?" name="WLCloudScrollYHelp" /> +			<check_box label="Lås" name="WLCloudLockY" /> +			<slider label="" name="WLCloudScrollY" /> +			<check_box label="Benyt simple skyer" name="DrawClassicClouds" /> +			<button label="?" name="WLClassicCloudsHelp" />  		</panel>  	</tab_container>  	<string name="WLDefaultSkyNames"> diff --git a/indra/newview/skins/default/xui/da/panel_classified_info.xml b/indra/newview/skins/default/xui/da/panel_classified_info.xml index 28f8936457..0bb52b8fa6 100644 --- a/indra/newview/skins/default/xui/da/panel_classified_info.xml +++ b/indra/newview/skins/default/xui/da/panel_classified_info.xml @@ -40,7 +40,7 @@  				</layout_panel>  				<layout_panel name="descr_layout_panel">  					<text name="classified_desc_label" value="Beskrivelse:"/> -					<text_editor name="classified_desc" value="[description]"/> +			<text_editor name="classified_desc" value="[description]"/>  				</layout_panel>  			</layout_stack>  		</panel> diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 99bf3e6bc1..671d8391e6 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -220,7 +220,8 @@               layout="topleft"               left_pad="2"               name="OwnerText" -             width="240"> +             use_ellipses="true"  +             width="360">                  Leyla Linden              </text>               <button @@ -374,7 +375,8 @@ Leyla Linden               </text>               left_delta="-199"               name="For sale to"               top_delta="20" -             width="186"> +             use_ellipses="true"  +             width="340">                  For sale to: [BUYER]              </text>              <text @@ -410,7 +412,7 @@ Leyla Linden               </text>               right="-10"               name="Cancel Land Sale"               left_pad="5" -             top_pad="-25" +             top_pad="-15"               width="180" />              <text               type="string" @@ -541,7 +543,7 @@ Leyla Linden               </text>               layout="topleft"               left_delta="0"               name="Reclaim Land..." -             top_delta="-61" +             top_delta="-50"               width="180" />              <button               enabled="false" diff --git a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml index f59badfcb4..a11946d352 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml @@ -5,11 +5,11 @@   height="350"   layout="topleft"   min_height="200" - min_width="265" + min_width="400"   name="avatarpicker"   help_topic="avatarpicker"   title="CHOOSE RESIDENT" - width="265"> + width="500">      <floater.string       name="not_found">          '[TEXT]' not found @@ -40,7 +40,7 @@       name="ResidentChooserTabs"       tab_position="top"       top="20" -     width="265"> +     width="500">          <panel           border="none"           height="150" @@ -83,14 +83,24 @@               left_pad="5"               name="Find"               width="45" /> -            <scroll_list -             follows="all" -             height="98" -             layout="topleft" -             left="0" -             name="SearchResults" -             top="52" -             width="132" /> +          <scroll_list +            draw_heading="true"  +           follows="all" +           height="98" +           layout="topleft" +           left="0" +           name="SearchResults" +           top="52" +           width="132"> +            <columns +              label="Name" +              name="name" +              width="150" /> +            <columns +              label="Username" +              name="username" +              width="150" /> +          </scroll_list>          </panel>          <panel           border="none" @@ -128,7 +138,7 @@              </button>              <scroll_list               follows="all" -             height="100" +             height="120"               border="false"               layout="topleft"               left="0" @@ -194,7 +204,8 @@               width="28"               name="Refresh"               image_overlay="Refresh_Off" /> -            <scroll_list +          <scroll_list +             draw_heading="true"               follows="all"               height="100"               border="false" @@ -202,21 +213,30 @@               left="0"               name="NearMe"               sort_column="0" -             top="50" -             width="132" /> +             top="52" +             width="132"> +            <columns +              label="Name" +              name="name" +              width="150" /> +            <columns +              label="Username" +              name="username" +              width="150" /> +          </scroll_list>          </panel>      </tab_container>      <button -     follows="right|bottom" +     follows="left|bottom"       height="23"       label="OK"       label_selected="OK"       name="ok_btn"       top_pad="3" -     left="46" +     left="10"       width="100" />      <button -     follows="right|bottom" +     follows="left|bottom"       height="23"       label="Cancel"       label_selected="Cancel" diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml index 303c28d7c8..1f2fe62b3c 100644 --- a/indra/newview/skins/default/xui/en/floater_bumps.xml +++ b/indra/newview/skins/default/xui/en/floater_bumps.xml @@ -14,23 +14,23 @@      </floater.string>      <floater.string       name="bump"> -        [TIME]  [FIRST] [LAST] bumped you +        [TIME]  [NAME] bumped you      </floater.string>      <floater.string       name="llpushobject"> -        [TIME]  [FIRST] [LAST] pushed you with a script +        [TIME]  [NAME] pushed you with a script      </floater.string>      <floater.string       name="selected_object_collide"> -        [TIME]  [FIRST] [LAST] hit you with an object +        [TIME]  [NAME] hit you with an object      </floater.string>      <floater.string       name="scripted_object_collide"> -        [TIME]  [FIRST] [LAST] hit you with a scripted object +        [TIME]  [NAME] hit you with a scripted object      </floater.string>      <floater.string       name="physical_object_collide"> -        [TIME]  [FIRST] [LAST] hit you with a physical object +        [TIME]  [NAME] hit you with a physical object      </floater.string>      <floater.string       name="timeStr"> diff --git a/indra/newview/skins/default/xui/en/floater_buy_land.xml b/indra/newview/skins/default/xui/en/floater_buy_land.xml index c88de878f4..d5d4565ca1 100644 --- a/indra/newview/skins/default/xui/en/floater_buy_land.xml +++ b/indra/newview/skins/default/xui/en/floater_buy_land.xml @@ -569,7 +569,7 @@ sold with objects           name="US$6.00/month,billedannually" />      </combo_box>      <locate -     height="10" +     height="5"       layout="topleft" />      <icon       follows="top|left" @@ -590,7 +590,7 @@ sold with objects       left="72"       name="land_use_action"       right="438" -     top="284" +     top="279"       width="218"       wrap="true">          Increase your monthly land use fees to US$ 40/month. @@ -610,7 +610,7 @@ sold with objects  This parcel is 512 m² of land.      </text>      <locate -     height="10" +     height="5"       layout="topleft" />      <icon       follows="top|left" @@ -654,7 +654,7 @@ This parcel is 512 m² of land.       left_delta="0"       name="currency_action"       top_pad="9" -     width="90"> +     width="95">          Buy additional L$      </text>      <locate diff --git a/indra/newview/skins/default/xui/en/floater_buy_object.xml b/indra/newview/skins/default/xui/en/floater_buy_object.xml index 3d8f5d678b..db595458c0 100644 --- a/indra/newview/skins/default/xui/en/floater_buy_object.xml +++ b/indra/newview/skins/default/xui/en/floater_buy_object.xml @@ -2,7 +2,7 @@  <floater   legacy_header_height="18"   can_resize="true" - height="290" + height="310"   layout="topleft"   min_height="150"   min_width="225" @@ -84,15 +84,18 @@       length="1"       follows="left|right|bottom"       font="SansSerif" -     height="16" +     height="35"       layout="topleft"       left_delta="0" +	 line_spacing.pixels="7"       name="buy_text"       text_color="white"       top_pad="5"       use_ellipses="true" -     width="260"> -        Buy for L$[AMOUNT] from [NAME]? +     width="260" +	 word_wrap="true"> +Buy for L$[AMOUNT] from: +[NAME]?      </text>      <button       follows="right|bottom" diff --git a/indra/newview/skins/default/xui/en/floater_incoming_call.xml b/indra/newview/skins/default/xui/en/floater_incoming_call.xml index 24fff6d4ae..81194f61cf 100644 --- a/indra/newview/skins/default/xui/en/floater_incoming_call.xml +++ b/indra/newview/skins/default/xui/en/floater_incoming_call.xml @@ -8,7 +8,7 @@   layout="topleft"   name="incoming call"   help_topic="incoming_call" - title="UNKNOWN PERSON IS CALLING" + title="Incoming call"   width="410">      <floater.string       name="lifetime"> diff --git a/indra/newview/skins/default/xui/en/floater_pay.xml b/indra/newview/skins/default/xui/en/floater_pay.xml index 509cffe490..7ab565313e 100644 --- a/indra/newview/skins/default/xui/en/floater_pay.xml +++ b/indra/newview/skins/default/xui/en/floater_pay.xml @@ -7,7 +7,7 @@   name="Give Money"   help_topic="give_money"   save_rect="true" - width="225"> + width="250">     <string      name="payee_group">          Pay Group @@ -16,28 +16,7 @@      name="payee_resident">          Pay Resident     </string> -   <text -     type="string" -     length="1" -     follows="left|top" -     height="18" -     layout="topleft" -     left="12" -     name="payee_label" -     top="22" -     width="75"> -        Pay: -    </text> -   <icon -     height="16" -     width="16" -     image_name="Generic_Person" -     mouse_opaque="true" -     name="icon_person" -     tool_tip="Person" -     top_pad="0" -     left="10" -     /> +      <text       type="string"       length="1" @@ -45,17 +24,19 @@       font="SansSerifSmall"       height="16"       layout="topleft" -     left_pad="7" +     left="10"       name="payee_name" -     width="210"> -        [FIRST] [LAST] +     top="25"  +     use_ellipses="true" +     width="230"> +        Test Name That Is Extremely Long To Check Clipping      </text>      <button       height="23"       label="L$1"       label_selected="L$1"       layout="topleft" -     left="25" +     left="35"       name="fastpay 1"       top_pad="8"       width="80" /> @@ -72,7 +53,7 @@       label="L$10"       label_selected="L$10"       layout="topleft" -     left="25" +     left="35"       name="fastpay 10"       top_pad="8"       width="80" /> @@ -90,7 +71,7 @@       follows="left|top"       height="18"       layout="topleft" -     left="25" +     left="35"       name="amount text"       top_pad="8"       width="180"> @@ -102,7 +83,7 @@       height="19"       top_pad="0"       layout="topleft" -     left="120" +     left="130"       max_length="9"       name="amount"       width="80" /> @@ -112,16 +93,16 @@       label="Pay"       label_selected="Pay"       layout="topleft" -     left="10" +     left="20"       name="pay btn" -     top_pad="5" +     top_pad="15"       width="100" />      <button       height="23"       label="Cancel"       label_selected="Cancel"       layout="topleft" -     left_pad="5" +     left_pad="10"       name="cancel btn"       width="100" />  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_pay_object.xml b/indra/newview/skins/default/xui/en/floater_pay_object.xml index d09a0a0535..d8cfed7b09 100644 --- a/indra/newview/skins/default/xui/en/floater_pay_object.xml +++ b/indra/newview/skins/default/xui/en/floater_pay_object.xml @@ -2,12 +2,12 @@  <floater   legacy_header_height="18"   can_minimize="false" - height="220" + height="225"   layout="topleft"   name="Give Money"   help_topic="give_money"   save_rect="true" - width="225"> + width="250">      <string       name="payee_group">          Pay Group @@ -16,27 +16,16 @@       name="payee_resident">          Pay Resident      </string> -   <icon -     height="16" -     width="16" -     image_name="Generic_Person" -     mouse_opaque="true" -     name="icon_person" -     tool_tip="Person" -     top_pad="24" -     left="10" -     />      <text -     type="string" -     length="1"       follows="left|top"       height="16"       layout="topleft" -     left_pad="7" -     top_delta="3" +     left="10" +     top_pad="24"       name="payee_name" -     width="184"> -      [FIRST] [LAST] +     use_ellipses="true"  +     width="225"> +      Ericacita Moostopolison      </text>      <text       type="string" @@ -45,9 +34,9 @@       halign="left"       height="14"       layout="topleft" -     left="34" +     left="10"       name="object_name_label" -     top_pad="0" +     top_pad="5"       width="180">          Via object:      </text> @@ -58,7 +47,7 @@       mouse_opaque="true"       name="icon_object"       tool_tip="Objects" -     top_pad="0" +     top_pad="5"       left="10"       />      <text 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 21c0bfef48..47383c8010 100644 --- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml +++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml @@ -373,7 +373,6 @@       height="23"       layout="topleft"       left_delta="0" -     max_length="32"       name="abuser_name_edit"       top_pad="0"       width="195" /> diff --git a/indra/newview/skins/default/xui/en/floater_sell_land.xml b/indra/newview/skins/default/xui/en/floater_sell_land.xml index 4cae42bcfe..619669d28a 100644 --- a/indra/newview/skins/default/xui/en/floater_sell_land.xml +++ b/indra/newview/skins/default/xui/en/floater_sell_land.xml @@ -164,7 +164,7 @@       left_delta="0"       name="sell_to_agent"       top_pad="4" -     width="130" /> +     width="170" />      <button       height="20"       label="Select" diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index a96dbe3553..691dd79764 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -253,7 +253,7 @@       height="28"  	 control_name="EditLinkedParts"       label="Edit linked" -     layout="topleft"      +     layout="topleft"       name="checkbox edit linked parts"       top_pad="0">  		  <check_box.commit_callback @@ -770,7 +770,7 @@  	 name="General"  	 top="16"  	 width="295"> -<panel.string +	 <panel.string  	  name="text deed continued">  		Deed  	 </panel.string> @@ -862,19 +862,23 @@               height="19"               layout="topleft"               name="Creator:" +             top_pad="7"               width="90">                  Creator:              </text> +            <!-- *NOTE: Intentionally wide for long names -->              <text               type="string"               length="1"               follows="left|top"               left_pad="0" -             height="19" +             height="30"               layout="topleft"               name="Creator Name" -             width="175"> -                Esbee Linden +             top_delta="0" +             width="190" +             word_wrap="true"> +                Mrs. Esbee Linden (esbee.linden)              </text>              <text               type="string" @@ -884,19 +888,23 @@               height="19"               layout="topleft"               name="Owner:" +             top_pad="3"               width="90">                  Owner:              </text> +            <!-- *NOTE: Intentionally wide for long names -->              <text               type="string"               length="1"               follows="left|top" -             height="19" +             height="30"               layout="topleft"               name="Owner Name"               left_pad="0" -             width="175"> -                Erica Linden +             top_delta="0" +             width="190" +             word_wrap="true"> +                Mrs. Erica "Moose" Linden (erica.linden)              </text>             <text               type="string" @@ -906,7 +914,7 @@               left="10"               height="18"               name="Group:" -             top_pad="4" +             top_pad="7"               width="75">                  Group:              </text> @@ -1060,8 +1068,8 @@ even though the user gets a free copy.           bg_alpha_color="DkGray"           name="perms_build"           left="0" -         top="241" -         height="130" +         top_pad="4" +         height="105"           width="290">              <text               type="string" @@ -1132,14 +1140,16 @@ even though the user gets a free copy.               top_delta="0"               tool_tip="Next owner can give away or resell this object"               width="100" /> +<!-- *NOTE: These "B/O/G/E/N/F fields may overlap "perm_modify" above,  +     but that's OK, this is used only for debugging. -->              <text               type="string"               text_color="EmphasisColor"               length="1" -             top_pad="5" +             top="9"               follows="left|top"               layout="topleft" -             left="10" +             left="230"               name="B:"               height="10"               width="80"> @@ -1151,7 +1161,8 @@ even though the user gets a free copy.               length="1"               follows="left|top"               layout="topleft" -             left_pad="0" +             left_delta="0" +             top_pad="2"               name="O:"               height="10"               width="80"> @@ -1163,7 +1174,8 @@ even though the user gets a free copy.               length="1"               follows="left|top"               layout="topleft" -             left_pad="0" +             left_delta="0" +             top_pad="2"               name="G:"               height="10"               width="80"> @@ -1174,7 +1186,7 @@ even though the user gets a free copy.               text_color="White"               length="1"               follows="left|top" -             left="10" +             left_delta="0"               top_pad="2"               layout="topleft"               name="E:" @@ -1188,7 +1200,8 @@ even though the user gets a free copy.               length="1"               follows="left|top"               layout="topleft" -             left_pad="0" +             left_delta="0" +             top_pad="2"               name="N:"               height="10"               width="80"> @@ -1200,7 +1213,8 @@ even though the user gets a free copy.               length="1"               follows="left|top"               layout="topleft" -             left_pad="0" +             left_delta="0" +             top_pad="2"               name="F:"               height="10"               width="80"> @@ -1208,6 +1222,7 @@ even though the user gets a free copy.              </text>          </panel>        </panel> +      <!-- Object tab -->        <panel           border="false"           follows="all" @@ -2955,4 +2970,5 @@ even though the user gets a free copy.           top_pad="4"           width="125" />   </panel> +<!-- end of tabs -->  </floater> diff --git a/indra/newview/skins/default/xui/en/inspect_avatar.xml b/indra/newview/skins/default/xui/en/inspect_avatar.xml index 194ae151d2..d018ea7ce1 100644 --- a/indra/newview/skins/default/xui/en/inspect_avatar.xml +++ b/indra/newview/skins/default/xui/en/inspect_avatar.xml @@ -9,7 +9,7 @@   bg_opaque_image="Inspector_Background"   can_close="false"   can_minimize="false" - height="148" + height="164"   layout="topleft"   name="inspect_avatar"   single_instance="true" @@ -47,9 +47,20 @@       follows="top|left"       height="16"       left="8" +     name="user_slid" +     font="SansSerifSmall" +     text_color="White" +     value="James.pinden" +     width="175" +     use_ellipses="true" /> +    <text +     follows="top|left" +     height="16" +     left="8"       name="user_subtitle"       font="SansSerifSmall"       text_color="White" +     top_pad="0"        value="11 Months, 3 days old"       width="175"       use_ellipses="true" /> @@ -108,7 +119,7 @@       height="20"       label="Add Friend"       left="8" -     top="119" +     top="135"       name="add_friend_btn"       width="90" />      <button @@ -152,7 +163,7 @@       width="35" />    <panel       follows="top|left"  -    top="148"  +    top="164"       left="0"       height="60"       width="228"  diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 63ff7047b4..ccdc8266be 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2653,6 +2653,12 @@              <menu_item_call.on_click               function="Advanced.SendTestIMs" />            </menu_item_call> +          <menu_item_call +           label="Flush Names Caches" +           name="Flush Names Caches"> +            <menu_item_call.on_click +             function="Advanced.FlushNameCaches" /> +          </menu_item_call>          </menu>          <menu           create_jump_keys="true" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 95ee374e39..3b9fb42a74 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -257,7 +257,7 @@ Save all changes to clothing/body parts?     name="GrantModifyRights"     type="alertmodal">  Granting modify rights to another Resident allows them to change, delete or take ANY objects you may have in-world. Be VERY careful when handing out this permission. -Do you want to grant modify rights for [FIRST_NAME] [LAST_NAME]? +Do you want to grant modify rights for [NAME]?      <usetemplate       name="okcancelbuttons"       notext="No" @@ -280,7 +280,7 @@ Do you want to grant modify rights for the selected Residents?     icon="alertmodal.tga"     name="RevokeModifyRights"     type="alertmodal"> -Do you want to revoke modify rights for [FIRST_NAME] [LAST_NAME]? +Do you want to revoke modify rights for [NAME]?      <usetemplate       name="okcancelbuttons"       notext="No" @@ -717,7 +717,7 @@ You can not wear that item because it has not yet loaded. Please try again in a     name="MustHaveAccountToLogIn"     type="alertmodal">  Oops! Something was left blank. -You need to enter both the First and Last name of your avatar. +You need to enter the Username name of your avatar.  You need an account to enter [SECOND_LIFE]. Would you like to create one now?      <url @@ -737,7 +737,7 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now?     icon="alertmodal.tga"     name="InvalidCredentialFormat"     type="alertmodal"> -You need to enter both the First and Last name of your avatar into the Username field, then login again. +You need to enter either the Username or both the First and Last name of your avatar into the Username field, then login again.    </notification> @@ -2021,20 +2021,6 @@ You do not have permission to buy land for your active group.    <notification     icon="alertmodal.tga"     label="Add Friend" -   name="AddFriend" -   type="alertmodal"> -Friends can give permissions to track each other on the map and receive online status updates. - -Offer friendship to [NAME]? -    <usetemplate -     name="okcancelbuttons" -     notext="Cancel" -     yestext="OK"/> -  </notification> - -  <notification -   icon="alertmodal.tga" -   label="Add Friend"     name="AddFriendWithMessage"     type="alertmodal">  Friends can give permissions to track each other on the map and receive online status updates. @@ -2128,7 +2114,7 @@ Would you be my friend?     icon="alertmodal.tga"     name="RemoveFromFriends"     type="alertmodal"> -Do you want to remove [FIRST_NAME] [LAST_NAME] from your Friends List? +Do you want to remove [NAME] from your Friends List?      <usetemplate       name="okcancelbuttons"       notext="Cancel" @@ -2381,7 +2367,7 @@ Deed this [AREA] m² of land to the group '[GROUP_NAME]'?     name="DeedLandToGroupWithContribution"     type="alertmodal">  By deeding this parcel, the group will be required to have and maintain sufficient land use credits. -The deed will include a simultaneous land contribution to the group from '[FIRST_NAME] [LAST_NAME]'. +The deed will include a simultaneous land contribution to the group from '[NAME]'.  The purchase price of the land is not refunded to the owner. If a deeded parcel is sold, the sale price will be divided evenly among group members.  Deed this [AREA] m² of land to the group '[GROUP_NAME]'? @@ -3201,6 +3187,103 @@ You are no longer frozen.    <notification     icon="alertmodal.tga" +   name="SetDisplayName" +   type="alert"> +The name above your avatar's head is called a [http://wiki.secondlife.com/wiki/Setting_your_display_name display name]. You can change it periodically. + +Press reset to make it the same as your username. + +Change your display name? +    <form name="form"> +      <input name="display_name" type="text"> +[DISPLAY_NAME] +      </input> +      <button +       default="true" +       index="0" +       name="Change" +       text="Change"/> +      <button +       index="1" +       name="Reset" +       text="Reset"/> +      <button +       index="2" +       name="Cancel" +       text="Cancel"/> +    </form> +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SetDisplayNameSuccess" +   type="alert"> +Hi [DISPLAY_NAME]! + +Just like in real life, it takes a while for everyone to learn about a new name.  Please allow several days for [http://wiki.secondlife.com/wiki/Setting_your_display_name your name to update] in objects, scripts, search, etc. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SetDisplayNameFailedLockout" +   type="alert"> +Sorry, you cannot [http://wiki.secondlife.com/wiki/Setting_your_display_name change your display name] until: +[TIME] +  </notification> + +  <notification + icon="alertmodal.tga" + name="SetDisplayNameBlocked" + type="alert"> +Sorry, you cannot change your display name. If you feel this is in error, please contact support. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SetDisplayNameFailedLength" +   type="alertmodal"> +Sorry, that name is too long.  Display names can have a maximum of [LENGTH] characters. + +Please try a shorter name. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="SetDisplayNameFailedGeneric" +   type="alertmodal"> +    Sorry, we could not set your display name.  Please try again later. +  </notification> + +<!-- *NOTE: This should never happen, users should see SetDisplayNameFailedLockout above --> +  <notification +   icon="alertmodal.tga" +   name="AgentDisplayNameUpdateThresholdExceeded" +   type="alertmodal"> +Sorry, you have to wait longer before you can change your display name. + +See http://wiki.secondlife.com/wiki/Setting_your_display_name + +Please try again later. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="AgentDisplayNameSetBlocked" +   type="alertmodal"> + Sorry, we could not set your requested name because it contains a banned word. +  + Please try a different name. +  </notification> + +  <notification +   icon="notifytip.tga" +   name="DisplayNameUpdate" +   type="notifytip"> +    [OLD_NAME] ([SLID]) is now known as [NEW_NAME]. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="OfferTeleport"     type="alertmodal">  Offer a teleport to your location with the following message? @@ -4503,14 +4586,14 @@ Topic: [SUBJECT], Message: [MESSAGE]     icon="notifytip.tga"     name="FriendOnline"     type="notifytip"> -[FIRST] [LAST] is Online +[NAME] is Online    </notification>    <notification     icon="notifytip.tga"     name="FriendOffline"     type="notifytip"> -[FIRST] [LAST] is Offline +[NAME] is Offline    </notification>    <notification @@ -4666,13 +4749,6 @@ You cannot remove protected categories.    <notification     icon="notifytip.tga" -   name="OfferedCard" -   type="notifytip"> -You have offered a calling card to [FIRST] [LAST] -  </notification> - -  <notification -   icon="notifytip.tga"     name="UnableToBuyWhileDownloading"     type="notifytip">  Unable to buy while downloading object data. @@ -4826,7 +4902,15 @@ Please select at least one type of content to search (General, Moderate, or Adul    <notification     icon="notify.tga" -   name="PaymentRecived" +   name="PaymentReceived" +   persist="true" +   type="notify"> +[MESSAGE] +  </notification> + +  <notification +   icon="notify.tga" +   name="PaymentSent"     persist="true"     type="notify">  [MESSAGE] @@ -4928,7 +5012,7 @@ The objects you own on the selected parcel of land have been returned back to yo     name="OtherObjectsReturned"     persist="true"     type="notify"> -The objects on the selected parcel of land that is owned by [FIRST] [LAST] have been returned to his or her inventory. +The objects on the selected parcel of land that is owned by [NAME] have been returned to his or her inventory.    </notification>    <notification @@ -5593,7 +5677,7 @@ Grant this request?     icon="notify.tga"     name="ScriptDialog"     type="notify"> -[FIRST] [LAST]'s '[TITLE]' +[NAME]'s '[TITLE]'  [MESSAGE]      <form name="form">        <button @@ -5823,7 +5907,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block     name="AutoUnmuteByIM"     persist="true"     type="notify"> -[FIRST] [LAST] was sent an instant message and has been automatically unblocked. +[NAME] was sent an instant message and has been automatically unblocked.    </notification>    <notification @@ -5831,7 +5915,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block     name="AutoUnmuteByMoney"     persist="true"     type="notify"> -[FIRST] [LAST] was given money and has been automatically unblocked. +[NAME] was given money and has been automatically unblocked.    </notification>    <notification @@ -5839,7 +5923,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block     name="AutoUnmuteByInventory"     persist="true"     type="notify"> -[FIRST] [LAST] was offered inventory and has been automatically unblocked. +[NAME] was offered inventory and has been automatically unblocked.    </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 3416b2369d..72f41c62f4 100644 --- a/indra/newview/skins/default/xui/en/panel_activeim_row.xml +++ b/indra/newview/skins/default/xui/en/panel_activeim_row.xml @@ -71,7 +71,7 @@  		top="10"  		left_pad="10"  		height="14" -		width="255" +		width="250"  		length="1"  		follows="right|left"  		use_ellipses="true" 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 5072ec3a66..1e69ecaed8 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_profile.xml @@ -3,7 +3,7 @@   background_visible="true"   class="edit_profile_panel"    follows="all" - height="535" + height="548"   label="Profile Edit"   layout="topleft"   left="0" @@ -60,7 +60,7 @@   <scroll_container       color="DkGray2"       follows="all" -     height="494" +     height="507"       min_height="300"       layout="topleft"       left="8" @@ -74,7 +74,7 @@           follows="left|top|right"           layout="topleft"           top="0" -     height="494" +     height="507"       min_height="300"           left="0"           width="292"> @@ -83,16 +83,45 @@       follows="left|top|right"           layout="topleft"           top="0" -     height="494" +     height="507"       min_height="300"           left="0"           width="292"> +      <text +       follows="top|left" +       font="SansSerifBigBold" +       height="20" +       layout="topleft" +       left="10" +       name="user_name" +       text_color="white" +       top="4" +       value="Hamilton Hitchings" +       width="280" /> +      <text +       follows="top|left" +       height="13" +       layout="topleft" +       left="10" +       name="user_slid" +       text_color="LtGray" +       top_pad="5" +       value="(hamilton.linden)" +       width="150" /> +      <button +       follows="top|left" +       height="20" +       label="Set Name..." +       left="170" +       name="set_name" +       top_delta="-4" +       width="110" />       <panel         name="lifes_images_panel"           follows="left|top|right"           height="244"           layout="topleft" -         top="0" +         top="37"           left="0"           width="292">  	 <panel @@ -146,8 +175,8 @@         height="102"         layout="topleft"         left="123" -       top="25" -       max_length="511" +       top="62" +       max_length="512"         name="sl_description_edit"         width="157"         word_wrap="true"> @@ -202,8 +231,8 @@         height="102"         layout="topleft"         left="123" -       max_length="254" -       top="157" +       max_length="512" +       top="195"         name="fl_description_edit"         width="157"         word_wrap="true"> @@ -301,17 +330,17 @@           left="10"           name="partner_data_panel"           width="200"> -            <name_box -             follows="left|top|right" -             height="30" -             initial_value="(retrieving)" -             layout="topleft" -             left="0" -             link="true" -             name="partner_text" -             top="0" -             width="200" -             word_wrap="true" /> +          <text +           follows="left|top|right" +           height="12" +           initial_value="(retrieving)" +           layout="topleft" +           left="0" +           link="true" +           name="partner_text" +           top="0" +           use_ellipses="true" +           width="280"/>           </panel>          <text           follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_group_general.xml b/indra/newview/skins/default/xui/en/panel_group_general.xml index 2af1a84400..70b96ca5eb 100644 --- a/indra/newview/skins/default/xui/en/panel_group_general.xml +++ b/indra/newview/skins/default/xui/en/panel_group_general.xml @@ -33,7 +33,7 @@ Hover your mouse over the options for more help.       height="110"       label=""       layout="topleft" -     left="10" +     left="5"       name="insignia"       no_commit_on_selection="true"       tool_tip="Click to choose a picture" @@ -49,22 +49,20 @@ Hover your mouse over the options for more help.       type="string"       height="16"       length="1" -     left_pad="10" +     left_pad="8"       name="prepend_founded_by"       top_delta="0">        Founder:      </text> -    <name_box -     follows="left|top" +     <text +      follows="left|top"       height="16" -     initial_value="(retrieving)"       layout="topleft" -     left_delta="0" -     link="true" +     left_delta="-2"       name="founder_name"       top_pad="2"       use_ellipses="true" -     width="190" /> +     width="168" />      <text      font="SansSerifMedium"      text_color="EmphasisColor" @@ -92,13 +90,13 @@ Hover your mouse over the options for more help.      <text_editor       type="string"       follows="left|top|right" -     left="5" +     left="3"       height="80"       layout="topleft"       max_length="511"       name="charter"       top="105" -     right="-1" +     right="-4"      bg_readonly_color="DkGray2"      text_readonly_color="White"       word_wrap="true"> @@ -113,6 +111,7 @@ Hover your mouse over the options for more help.       layout="topleft"       left="0"       name="visible_members" +     short_names="false"        top_pad="2">          <name_list.columns           label="Member" diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 18a2f37ba2..19b541c53b 100644 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -85,6 +85,7 @@ clicking on their names.               right="-1"               multi_select="true"               name="member_list" +             short_names="false"                top_pad="5">                  <name_list.columns                   label="Member" diff --git a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml index 33a5e01e4c..a36f078f4f 100644 --- a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml @@ -24,25 +24,15 @@       top_pad="5"       width="114">          <layout_panel -         mouse_opaque="false" -         auto_resize="true" -         follows="top|left" -         height="0" -         layout="topleft" -         left="2" -         min_height="0" -         width="109" -         top="0" -         name="spacer" -         user_resize="false" /> -        <layout_panel           auto_resize="false"           follows="top|left|right"           height="20"           layout="topleft" +         left="2"            min_height="20"           width="109"           name="view_profile_btn_panel" +         top="0"            user_resize="false">              <button               follows="left|top|right" @@ -171,5 +161,15 @@               name="voice_ctrls_btn"               width="109" />          </layout_panel> +      <layout_panel +       mouse_opaque="false" +       auto_resize="true" +       follows="top|left" +       height="0" +       layout="topleft" +       min_height="0" +       width="109" +       name="spacer" +       user_resize="false" />      </layout_stack>  </panel> 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 34fd3352a3..021cf00d03 100644 --- a/indra/newview/skins/default/xui/en/panel_instant_message.xml +++ b/indra/newview/skins/default/xui/en/panel_instant_message.xml @@ -67,7 +67,7 @@           top="8"           use_ellipses="true"           value="Erica Vader" -         width="212" /> +         width="205" />  	 <!-- TIME STAMP -->          <text          font="SansSerifSmall" diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml index a7e87f2a1e..8d43cc816c 100644 --- a/indra/newview/skins/default/xui/en/panel_landmarks.xml +++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml @@ -3,7 +3,7 @@     name="Landmarks"     top="0"     height="400" -   layout="topleft" +   layout="topleft"      left="0"     width="313"     help_topic="panel_landmarks" @@ -88,7 +88,7 @@          </accordion_tab>      </accordion>      <panel -     background_visible="true" +       background_visible="true"       bevel_style="none"       bottom="0"       follows="left|right|bottom" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 185e458a85..48b021efcf 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -65,12 +65,13 @@ Username:  <line_editor  follows="left|bottom"  height="22" -label="Username" +label="bobsmith12 or Steller Sunshine"  left_delta="0" -max_length="31" +max_length="63"  name="username_edit" +prevalidate_callback="ascii"   select_on_focus="true" -tool_tip="[SECOND_LIFE] Username" +tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"  top_pad="0"  width="150" />  <text @@ -158,8 +159,8 @@ width="135"  <layout_panel  follows="right|bottom"  name="links" -width="200" -min_width="200" +width="205" +min_width="205"  user_resize="false"  height="80">     <text @@ -171,7 +172,7 @@ height="16"  top="12"  right="-10"  name="create_new_account_text" -  width="180"> +  width="200">         Sign up   </text>  <text @@ -183,8 +184,8 @@ height="16"  name="forgot_password_text"  top_pad="12"  right="-10" -  width="180"> -       Forgot your name or password? +  width="200"> +       Forgot your username or password?  </text>  <text  follows="right|bottom" @@ -195,7 +196,7 @@ height="16"  name="login_help"  top_pad="2"  right="-10" -    width="180"> +    width="200">         Need help logging in?   </text>  <!--  <text      follows="right|bottom" diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml index 2e49fc8d6f..49802aa3f2 100644 --- a/indra/newview/skins/default/xui/en/panel_my_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml @@ -286,7 +286,7 @@               name="partner_data_panel"               top_pad="0"               width="300"> -              <name_box +              <text                 follows="left|top"                 height="10"                 initial_value="(retrieving)" @@ -295,8 +295,8 @@                 link="true"                 name="partner_text"                 top="0" -           width="300" -               word_wrap="true" /> +               use_ellipses="true"  +           width="300" />              </panel>              <text               follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml index cf174da2f0..dde0db2513 100644 --- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml +++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml @@ -57,6 +57,7 @@      <string       name="replace_body_part"       value="Click to replace your existing shape"/> +        <button       follows="top|left" @@ -197,19 +198,19 @@ It is calculated as border_size + 2*UIResizeBarOverlap                   user_resize="false"                   visible="true"> -                    <!-- List containing items from the COF and Base outfit --> -                    <panel -                     background_visible="false" -                     class="cof_wearables" -                     filename="panel_cof_wearables.xml" +            <!-- List containing items from the COF and Base outfit --> +            <panel +             background_visible="false" +             class="cof_wearables" +             filename="panel_cof_wearables.xml"                       follows="all"                        height="129" -                     layout="topleft" -                     left="1" -                     name="cof_wearables_list" -                     top="0" -                     width="311" /> -                     +             layout="topleft" +             left="1" +             name="cof_wearables_list" +             top="0" +             width="311" /> +                      <button                       follows="left|bottom"                        height="22" @@ -228,7 +229,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap                      <combo_box                       follows="left|right|bottom"                       height="22" -                     layout="topleft" +             layout="topleft"                       left_pad="5"                       name="list_view_filter_combobox"                       top_delta="0" @@ -244,20 +245,20 @@ It is calculated as border_size + 2*UIResizeBarOverlap                       visible="false"                       width="152"/> -                    <button +            <button                       follows="bottom|right"                       height="22" -                     image_overlay="Search_Icon" +             image_overlay="Search_Icon"                       image_pressed="PushButton_Press"                       image_pressed_selected="PushButton_Selected_Press"                       image_selected="PushButton_Selected_Press" -                     is_toggle="true" -                     layout="topleft" -                     name="filter_button" +             is_toggle="true" +             layout="topleft" +             name="filter_button"                       right="-5" -                     top_delta="0" +             top_delta="0"                       visible="false" -                     width="20" /> +             width="20" />                  </layout_panel>                  <layout_panel @@ -286,13 +287,13 @@ It is calculated as border_size + 2*UIResizeBarOverlap                  </layout_panel>              </layout_stack> -        </layout_panel> +                </layout_panel> -        <layout_panel +                <layout_panel           background_visible="false"           bg_alpha_color="DkGray2" -         auto_resize="true" +                 auto_resize="true"           default_tab_group="3"           height="450"           min_height="53" @@ -312,44 +313,44 @@ It is calculated as border_size + 2*UIResizeBarOverlap               top_pad="-9"               width="313" /> -            <inventory_panel -             allow_multi_select="true" -             background_visible="false" -             border="false" -             follows="left|top|right|bottom" +                    <inventory_panel +		             allow_multi_select="true" +		             background_visible="false" +		             border="false" +		             follows="left|top|right|bottom"               height="418" -             layout="topleft" -             left="0" -             mouse_opaque="false" +		             layout="topleft" +		             left="0" +		             mouse_opaque="false"               name="folder_view"               top_pad="0"               width="313" -             visible="false"/> -            <panel -             name="filtered_wearables_panel" -             background_opaque="true" -             background_visible="false" -             layout="topleft" -             follows="left|top|right|bottom" -             border="false" +		             visible="false"/> +		            <panel +		             name="filtered_wearables_panel" +		             background_opaque="true" +		             background_visible="false" +		             layout="topleft" +		             follows="left|top|right|bottom" +		             border="false"               height="418" -             left="0" -             mouse_opaque="false" +		             left="0" +		             mouse_opaque="false"               width="310" -             top_delta="0" -             visible="true"> -                <wearable_items_list -                 color="0.107 0.107 0.107 1" +		             top_delta="0" +		             visible="true"> +		             <wearable_items_list +		              color="0.107 0.107 0.107 1"                   name="list_view" -                 allow_select="true" -                 layout="topleft" -                 follows="all" -                 multi_select="true" +		              allow_select="true" +		              layout="topleft" +		              follows="all" +		              multi_select="true"                   width="313"                   height="418" -                 left="0" -                 top="0"/> -            </panel> +		              left="0" +		              top="0"/> +		            </panel>              <button  	         follows="bottom|left"  	         height="22" @@ -360,7 +361,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap  	         top_pad="5"  	         width="130" /> -        </layout_panel> +       </layout_panel>      </layout_stack> @@ -461,15 +462,15 @@ It is calculated as border_size + 2*UIResizeBarOverlap           name="list_view_btn"           top="1"           width="31" /> -        <icon -         follows="bottom|left|right" -         height="25" +       <icon +        follows="bottom|left|right" +        height="25"           image_name="Toolbar_Middle_Off" -         layout="topleft" -         left_pad="1" +        layout="topleft" +        left_pad="1"           name="dummy_right_icon"           width="186" > -        </icon> +       </icon>          <button           follows="bottom|right"           height="25" @@ -484,7 +485,7 @@ It is calculated as border_size + 2*UIResizeBarOverlap           tool_tip="Visit the SL Marketplace. You can also select something you are wearing, then click here to see more things like it"           width="31" />      </panel> -     +      <!-- SAVE AND REVERT BUTTONS -->      <panel       follows="left|right|bottom" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 7cd0d5b5f0..1353d401c3 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -81,7 +81,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M       width="317">       	<panel           background_opaque="true" -         background_visible="true" +       background_visible="true"           bg_alpha_color="DkGray"           bg_opaque_color="DkGray"           follows="all" @@ -155,7 +155,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M          </panel>          <panel           background_opaque="true" -         background_visible="true" +       background_visible="true"           bg_alpha_color="DkGray"           bg_opaque_color="DkGray"           follows="all" @@ -280,7 +280,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M          </panel>          <panel           background_opaque="true" -         background_visible="true" +       background_visible="true"           bg_alpha_color="DkGray"           bg_opaque_color="DkGray"           follows="all" @@ -365,7 +365,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M          </panel>          <panel           background_opaque="true" -         background_visible="true" +       background_visible="true"           bg_alpha_color="DkGray"           bg_opaque_color="DkGray"           follows="all" diff --git a/indra/newview/skins/default/xui/en/panel_place_profile.xml b/indra/newview/skins/default/xui/en/panel_place_profile.xml index 35e8075896..fb6f14ae93 100644 --- a/indra/newview/skins/default/xui/en/panel_place_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_place_profile.xml @@ -316,7 +316,8 @@               name="owner_value"               top_delta="0"               value="Alex Superduperlongenamenton" -             width="205" /> +             use_ellipses="true"  +             width="200" />              <icon               follows="top|left"               height="16" 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 31d8ea27d9..7d9bd1bf2a 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -125,6 +125,7 @@ Automatic position for:       left_pad="30"       name="first_person_avatar_visible"       width="256" /> +         <check_box       control_name="ArrowKeysAlwaysMove"       follows="left|top" @@ -206,7 +207,7 @@ Automatic position for:     left="80"     name="UI Size:"     top_pad="25" -   width="160"> +   width="300">      UI size    </text>    <slider @@ -302,6 +303,7 @@ Automatic position for:       halign="center"       height="23"       image_overlay="Refresh_Off" +   layout="topleft"        tool_tip="Reset to Middle Mouse Button"       mouse_opaque="true"       name="set_voice_middlemouse_button" @@ -315,7 +317,7 @@ Automatic position for:   label="Other Devices"   left="30"   name="joystick_setup_button" - top="27" + top_pad="27"   width="155">      <button.commit_callback       function="Floater.Show" 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 a69e8d29b0..2cf4118e19 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml @@ -222,28 +222,27 @@     </text>     <radio_group       control_name="AvatarNameTagMode" -     height="20" +     height="45"       layout="topleft"       left="50"       name="Name_Tag_Preference">          <radio_item           label="Off" -         layout="topleft"           name="radio"           value="0"           width="75" />          <radio_item           label="On" -         layout="topleft" -         left_pad="12" +         left_delta="0"           name="radio2" +		 top_pad="5"           value="1"           width="75" />          <radio_item           label="Show briefly" -         layout="topleft" -         left_pad="12" +         left_delta="0"           name="radio3" +		 top_pad="5"           value="2"           width="160" />      </radio_group> @@ -253,18 +252,58 @@       height="16"       label="Show my name"       layout="topleft" -     left="50" +     left="70"       name="show_my_name_checkbox1" +	 top_pad="4"       width="300" />     <check_box +    control_name="NameTagShowFriends"  	 enabled_control="AvatarNameTagMode" -     control_name="RenderShowGroupTitleAll"       height="16" -     label="Show group titles" +    label="Highlight friends" +    left_delta="0" +    name="show_friends" +    tool_tip="Highlight the name tags of your friends" +    top_pad="2" /> +  <text +    follows="left|top" +    height="15"       layout="topleft" -     left_delta="175" +    left="250" +    name="name_tags_textbox" +    top="175" +    width="200"> +       Tags show: +   </text> +    <check_box +     control_name="NameTagShowGroupTitles" +	 enabled_control="AvatarNameTagMode" +     height="16" +     label="Group titles" +     left="265"       name="show_all_title_checkbox1" -     width="200" /> +	 tool_tip="Show group titles, like Officer or Member" +     top_pad="5" /> +  <!-- +   <check_box +     control_name="NameTagShowDisplayNames" +	 enabled_control="AvatarNameTagMode" +     height="16" +     label="Display names" +     left_delta="0" +     name="show_display_names" +	 tool_tip="Show display names, like José Sanchez" +     top_pad="5" /> +     --> +   <check_box +     control_name="NameTagShowUsernames" +	 enabled_control="AvatarNameTagMode" +     height="16" +     label="Usernames" +     left_delta="0" +     name="show_slids" +     tool_tip="Show username, like bobsmith123" +     top_pad="2" />      <text       type="string"       length="1" @@ -273,7 +312,7 @@       layout="topleft"       left="30"       name="effects_color_textbox" -     top_pad="15" +     top="290"       width="200">          My effects:      </text> @@ -285,6 +324,7 @@        layout="topleft"        left_pad="5"        name="title_afk_text" +      top_delta="0"         width="190">      Away timeout:      </text> @@ -353,8 +393,8 @@        bg_writeable_color="LtGray"        use_ellipses="false"       commit_on_focus_lost = "true" -     follows="left|top|right" -     height="60" +     follows="left|top" +     height="42"       layout="topleft"       left="50"       name="busy_response" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 2c6ceeef2e..7148aba00a 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -115,7 +115,7 @@     layout="topleft"     left="77"     name="connection_port_enabled" -   top_pad="20" +   top_pad="15"     width="256">      <check_box.commit_callback       function="Notification.Show" @@ -147,7 +147,7 @@     left="80"     mouse_opaque="false"     name="cache_size_label_l" -   top_pad="20" +   top_pad="10"     width="200">      Cache size    </text> @@ -375,4 +375,27 @@     name="web_proxy_port"     top_delta="0"     width="145" /> +  <text +       type="string" +       length="1" +       follows="left|top" +       height="10" +       layout="topleft" +       left="30" +       name="Communications:" +       top_pad="5" +       width="300"> +    Communications: +  </text> +  <check_box +control_name="UseDisplayNames" +follows="top|left" +height="15" +label="Use Display Names" +layout="topleft" +left_delta="50" +name="display_names_check" +width="237" +tool_tip="Check to use display names in chat, IM, name tags, etc." +top_pad="10"/>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index fc33836c79..3ce7ef6ce4 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -265,7 +265,7 @@               name="partner_data_panel"               top_pad="0"               width="300"> -              <name_box +              <text                 follows="left|top"                 height="10"                 initial_value="(retrieving)" @@ -274,8 +274,8 @@                 link="true"                 name="partner_text"                 top="0" -           width="300" -               word_wrap="true" /> +               use_ellipses="true" +           width="300" />              </panel>              <text               follows="left|top" 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 d9030fc0d6..9745f89e31 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_view.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_view.xml @@ -50,8 +50,19 @@       height="13"       layout="topleft"       left="45" +     name="user_slid" +     text_color="LtGray" +     value="" +     width="150" /> +    <text +     follows="top|left" +     halign="right"  +     height="13" +     layout="topleft" +     left="150"       name="status"       text_color="LtGray_50" +     top_delta="0"        value="Online"       width="150" />      <tab_container diff --git a/indra/newview/skins/default/xui/en/panel_region_debug.xml b/indra/newview/skins/default/xui/en/panel_region_debug.xml index a6b4ddd01e..15df095efa 100644 --- a/indra/newview/skins/default/xui/en/panel_region_debug.xml +++ b/indra/newview/skins/default/xui/en/panel_region_debug.xml @@ -103,7 +103,7 @@       mouse_opaque="false"       name="target_avatar_name"       top_delta="-2" -     width="180"> +     width="270">          (none)      </line_editor>      <button diff --git a/indra/newview/skins/default/xui/en/panel_region_estate.xml b/indra/newview/skins/default/xui/en/panel_region_estate.xml index 08e36d5e57..1307d807e2 100644 --- a/indra/newview/skins/default/xui/en/panel_region_estate.xml +++ b/indra/newview/skins/default/xui/en/panel_region_estate.xml @@ -72,7 +72,8 @@       left_delta="0"       name="estate_owner"       top_delta="16" -     width="150"> +     use_ellipses="true" +     width="290">          (unknown)      </text>      <view_border diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml index 49b252174c..504da8026f 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml @@ -165,7 +165,7 @@       left_pad="5"  		     name="LabelCreatorName"  		     top_delta="6" -		     width="140"> +		     width="180">        </text>        <button        follows="top|right" @@ -207,7 +207,7 @@          left_pad="5"        name="LabelOwnerName"        top_delta="6" -      width="140"> +			 width="180">        </text>  	     <button  			 follows="top|right" diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml index 843015cb8b..5da449de3d 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml @@ -167,7 +167,7 @@       left_pad="0"               name="Creator Name"  		     top_delta="0" -		     width="140"> +		     width="225">  	        Erica Linden  	     </text>  	    <text @@ -191,7 +191,7 @@  			    left_pad="0"  			    name="Owner Name"  			    top_delta="0" -			    width="140"> +			    width="225">  			    Erica Linden  	     </text>  	    	    <text diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 048de70045..7a1de925f1 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -89,6 +89,7 @@  	<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="TooltipAgentInspect">Learn more about this Resident</string>  	<string name="TooltipAgentMute">Click to mute this Resident</string>  	<string name="TooltipAgentUnmute">Click to unmute this Resident</string>  	<string name="TooltipAgentIM">Click to IM this Resident</string> @@ -3036,7 +3037,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE].      You are the only user in this session.    </string>    <string name="offline_message"> -    [FIRST] [LAST] is offline. +    [NAME] is offline.    </string>    <string name="invite_message">      Click the [BUTTON NAME] button to accept/connect to this voice chat. @@ -3122,17 +3123,20 @@ If you continue to receive this message, contact the [SUPPORT_SITE].    <string name="voice_morphing_url">http://secondlife.com/landing/voicemorphing</string>    <!-- Financial operations strings --> -  <string name="paid_you_ldollars">[NAME] paid you L$[AMOUNT]</string> +  <string name="paid_you_ldollars">[NAME] paid you L$[AMOUNT] [REASON].</string> +  <string name="paid_you_ldollars_no_reason">[NAME] paid you L$[AMOUNT].</string>    <string name="you_paid_ldollars">You paid [NAME] L$[AMOUNT] [REASON].</string>    <string name="you_paid_ldollars_no_info">You paid L$[AMOUNT].</string>    <string name="you_paid_ldollars_no_reason">You paid [NAME] L$[AMOUNT].</string>    <string name="you_paid_ldollars_no_name">You paid L$[AMOUNT] [REASON].</string> +  <string name="for item">for [ITEM]</string>    <string name="for a parcel of land">for a parcel of land</string>    <string name="for a land access pass">for a land access pass</string>    <string name="for deeding land">for deeding land</string>    <string name="to create a group">to create a group</string>    <string name="to join a group">to join a group</string>    <string name="to upload">to upload</string> +  <string name="to publish a classified ad">to publish a classified ad</string>    <string name="giving">Giving L$ [AMOUNT]</string>    <string name="uploading_costs">Uploading costs L$ [AMOUNT]</string> diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index 88013df8f5..f2ef987d66 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -1419,7 +1419,7 @@ Esta actualización no es obligatoria, pero te sugerimos instalarla para mejorar  	</notification>  	<notification name="BusyModeSet">  		Pasar al modo ocupado. -Se ocultará el chat y los mensajes instantáneos (éstos recibirán tu Respuesta en el modo ocupado). Se rehusarán todos los ofrecimientos de teleporte. Todas las ofertas de inventario irán a tu Papelera. +Se ocultará el chat y los mensajes instantáneos   (éstos recibirán tu Respuesta en el modo ocupado). Se rehusarán todos los ofrecimientos de teleporte. Todas las ofertas de inventario irán a tu Papelera.  		<usetemplate ignoretext="Cambio mi estado al modo ocupado" name="okignore" yestext="OK"/>  	</notification>  	<notification name="JoinedTooManyGroupsMember"> @@ -1886,7 +1886,7 @@ Linden Lab  		</form>  	</notification>  	<notification name="ConfirmDeleteProtectedCategory"> -		La carpeta '[FOLDERNAME]' pertenece al sistema, y borrar carpetas del sistema puede provocar inestabilidad.  ¿Estás seguro de que quieres borrarla? +		La carpeta '[FOLDERNAME]' pertenece al sistema,   y borrar carpetas del sistema puede provocar inestabilidad.  ¿Estás seguro de que quieres borrarla?  		<usetemplate ignoretext="Confirmar antes de borrar una carpeta del sistema" name="okcancelignore" notext="Cancelar" yestext="OK"/>  	</notification>  	<notification name="ConfirmEmptyTrash"> @@ -2445,7 +2445,7 @@ Esto añadirá un marcador en tu inventario para que puedas enviarle rápidament  Si permaneces en esta región serás desconectado.  	</notification>  	<notification name="RegionRestartSeconds"> -		Esta región se reiniciará en [SECONDS] segundos. +		Esta región se reiniciará en  [SECONDS] segundos.  Si permaneces en esta región serás desconectado.  	</notification>  	<notification name="LoadWebPage"> @@ -2509,7 +2509,7 @@ Si no confias en este objeto y en su creador, deberías rehusar esta petición.  	<notification name="BuyLindenDollarSuccess">  		¡Gracias por tu pago! -Tu saldo de L$ se actualizará cuando se complete el proceso. Si el proceso tarda más de 20 minutos, se cancelará tu transacción, y la cantidad se cargará en tu saldo de US$. +Tu saldo de L$ se actualizará cuando se complete el proceso. Si el proceso tarda más de 20 minutos, se cancelará tu transacción,    y la cantidad se cargará en tu saldo de US$.  Puedes revisar el estado de tu pago en el Historial de transacciones de tu [http://secondlife.com/account/ Panel de Control]  	</notification> diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml index 5cb42a0435..bad92f200c 100644 --- a/indra/newview/skins/default/xui/fr/notifications.xml +++ b/indra/newview/skins/default/xui/fr/notifications.xml @@ -178,7 +178,7 @@ Voulez-vous continuer ?  	<notification name="JoinGroupNoCost">  		Vous vous apprêtez à rejoindre le groupe [NAME].  Voulez-vous continuer ? -		<usetemplate name="okcancelbuttons" notext="Annuler" yestext="Rejoindre"/> +		<usetemplate name="okcancelbuttons" notext="Annuler" yestext="Fusionner"/>  	</notification>  	<notification name="JoinGroupCannotAfford">  		Rejoindre ce groupe coûte [COST] L$. diff --git a/indra/newview/skins/default/xui/ja/panel_group_land_money.xml b/indra/newview/skins/default/xui/ja/panel_group_land_money.xml index 4b3a7f880b..016dc97ab6 100644 --- a/indra/newview/skins/default/xui/ja/panel_group_land_money.xml +++ b/indra/newview/skins/default/xui/ja/panel_group_land_money.xml @@ -48,7 +48,7 @@  			あなたの貢献:  		</text>  		<text name="your_contribution_units"> -			m² +			平方メートル  		</text>  		<text name="your_contribution_max_value">  			(最大 [AMOUNT]) diff --git a/indra/newview/skins/default/xui/ja/panel_group_roles.xml b/indra/newview/skins/default/xui/ja/panel_group_roles.xml index 8a629be910..db6fe268c7 100644 --- a/indra/newview/skins/default/xui/ja/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/ja/panel_group_roles.xml @@ -17,7 +17,7 @@ Ctrl キーを押しながらメンバー名をクリックすると  			<name_list name="member_list">  				<name_list.columns label="メンバー" name="name"/>  				<name_list.columns label="寄付" name="donated"/> -				<name_list.columns label="ログイン" name="online"/> +				<name_list.columns label="ステータス" name="online"/>  			</name_list>  			<button label="招待" name="member_invite"/>  			<button label="追放" name="member_eject"/> @@ -44,7 +44,7 @@ Ctrl キーを押しながらメンバー名をクリックすると  			<filter_editor label="役割を選別" name="filter_input"/>  			<scroll_list name="role_list">  				<scroll_list.columns label="役割" name="name"/> -				<scroll_list.columns label="タイトル" name="title"/> +				<scroll_list.columns label="肩書き" name="title"/>  				<scroll_list.columns label="#" name="members"/>  			</scroll_list>  			<button label="新しい役割" name="role_create"/> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index f0a4a4e2a6..85256d8ab9 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -1381,10 +1381,10 @@  		Script não encontrado no servidor.  	</string>  	<string name="CompileQueueProblemDownloading"> -		Problema no download +		Problema no  download  	</string>  	<string name="CompileQueueInsufficientPermDownload"> -		Permissões insuficientes para fazer o download do script. +		Permissões insuficientes para  fazer o download do script.  	</string>  	<string name="CompileQueueInsufficientPermFor">  		Permissões insuficientes para @@ -1691,7 +1691,7 @@  		(vai atualizar depois de publicado)  	</string>  	<string name="NoPicksClassifiedsText"> -		Você não criou nenhum Destaque ou Anúncio. Clique no botão "+" para criar um Destaque ou Anúncio. +		Você não criou nenhum Destaque ou Anúncio.  Clique no botão "+" para criar um Destaque ou Anúncio.  	</string>  	<string name="NoAvatarPicksClassifiedsText">  		O usuário não tem nenhum destaque ou anúncio diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp index 7ba82fbd2c..9ec24eb515 100644 --- a/indra/newview/tests/lldateutil_test.cpp +++ b/indra/newview/tests/lldateutil_test.cpp @@ -189,4 +189,14 @@ namespace tut  			LLDateUtil::ageFromDate("12/13/2009", now),  			"3 weeks old" );  	} + +	//template<> template<> +	//void dateutil_object_t::test<6>() +	//{ +	//	set_test_name("ISO dates"); +	//	LLDate now(std::string("2010-01-04T12:00:00Z")); +	//	ensure_equals("days", +	//		LLDateUtil::ageFromDateISO("2009-12-13", now), +	//		"3 weeks old" ); +	//}  } diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg index d4f791c202..77dc940335 100644 --- a/scripts/messages/message_template.msg +++ b/scripts/messages/message_template.msg @@ -6812,6 +6812,19 @@ version 2.0  		{	SquareMetersCommitted	S32	}  		{	Description			Variable 1	}	// string  	} +	// For replies that are part of a transaction (buying something) provide +	// metadata for localization.  If TransactionType is 0, the message is +	// purely a balance update.  Added for server 1.40 and viewer 2.1.  JC +	{ +		TransactionInfo		Single +		{	TransactionType			S32			}	// lltransactiontype.h +		{	SourceID				LLUUID		} +		{	IsSourceGroup			BOOL		} +		{	DestID					LLUUID		} +		{	IsDestGroup				BOOL		} +		{	Amount					S32			} +		{	ItemDescription			Variable 1	}	// string +	}  } @@ -6838,6 +6851,17 @@ version 2.0  		{	SquareMetersCommitted	S32	}  		{	Description			Variable 1	}	// string  	} +	// See MoneyBalanceReply above. +	{ +		TransactionInfo		Single +		{	TransactionType			S32			}	// lltransactiontype.h +		{	SourceID				LLUUID		} +		{	IsSourceGroup			BOOL		} +		{	DestID					LLUUID		} +		{	IsDestGroup				BOOL		} +		{	Amount					S32			} +		{	ItemDescription			Variable 1	}	// string +	}  } @@ -8972,5 +8996,7 @@ version 2.0  		{	InvType			S8	}  		{	Name			Variable	1	}  		{	Description		Variable	1	} +  	}  } +  | 
