diff options
Diffstat (limited to 'indra')
37 files changed, 544 insertions, 233 deletions
| diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index de46d89d6f..3b3e644d10 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2579,6 +2579,8 @@ void LLFloaterView::pushVisibleAll(BOOL visible, const skip_list_t& skip_list)  			view->pushVisible(visible);  		}  	} + +	LLFloaterReg::blockShowFloaters(true);  }  void LLFloaterView::popVisibleAll(const skip_list_t& skip_list) @@ -2596,6 +2598,8 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)  			view->popVisible();  		}  	} + +	LLFloaterReg::blockShowFloaters(false);  }  void LLFloater::setInstanceName(const std::string& name) diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp index eb67e3a561..5de3934c8a 100644 --- a/indra/llui/llfloaterreg.cpp +++ b/indra/llui/llfloaterreg.cpp @@ -34,6 +34,7 @@  #include "llfloaterreg.h" +//#include "llagent.h"   #include "llfloater.h"  #include "llmultifloater.h"  #include "llfloaterreglistener.h" @@ -45,6 +46,7 @@ LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList;  LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;  LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;  std::map<std::string,std::string> LLFloaterReg::sGroupMap; +bool LLFloaterReg::sBlockShowFloaters = false;  static LLFloaterRegListener sFloaterRegListener; @@ -217,6 +219,8 @@ LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::str  //static  LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)   { +	if( sBlockShowFloaters ) +		return 0;//  	LLFloater* instance = getInstance(name, key);   	if (instance)   	{ diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 634a235926..8a11d5c3f2 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -75,6 +75,7 @@ private:  	static instance_map_t sInstanceMap;  	static build_map_t sBuildMap;  	static std::map<std::string,std::string> sGroupMap; +	static bool sBlockShowFloaters;  public:  	// Registration @@ -152,6 +153,8 @@ public:  	{  		return dynamic_cast<T*>(showInstance(name, key, focus));  	} + +	static void blockShowFloaters(bool value) { sBlockShowFloaters = value;}  }; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index cb5aea272d..eb2b4f7705 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -70,7 +70,7 @@ const S32   SCROLL_INCREMENT_DEL = 4;	// make space for baskspacing  const F32   AUTO_SCROLL_TIME = 0.05f;  const F32	TRIPLE_CLICK_INTERVAL = 0.3f;	// delay between double and triple click. *TODO: make this equal to the double click interval? -const std::string PASSWORD_ASTERISK( "\xE2\x97\x8F" ); // U+25CF BLACK CIRCLE +const std::string PASSWORD_ASTERISK( "\xE2\x80\xA2" ); // U+2022 BULLET  static LLDefaultChildRegistry::Register<LLLineEditor> r1("line_editor"); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 259522a932..b977e50bc1 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1024,6 +1024,16 @@ void LLTextBase::setReadOnlyColor(const LLColor4 &c)  }  //virtual +void LLTextBase::handleVisibilityChange( BOOL new_visibility ) +{ +	if(!new_visibility && mPopupMenu) +	{ +		mPopupMenu->hide(); +	} +	LLUICtrl::handleVisibilityChange(new_visibility); +} + +//virtual  void LLTextBase::setValue(const LLSD& value )  {  	setText(value.asString()); diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index b5c7fab67a..ed2f239476 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -122,6 +122,7 @@ public:  	/*virtual*/ BOOL		acceptsTextInput() const { return !mReadOnly; }  	/*virtual*/ void		setColor( const LLColor4& c );  	virtual     void 		setReadOnlyColor(const LLColor4 &c); +	virtual	    void		handleVisibilityChange( BOOL new_visibility );  	/*virtual*/ void		setValue(const LLSD& value );  	/*virtual*/ LLTextViewModel* getViewModel() const; diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 58148ad2aa..b20de914a0 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -49,7 +49,7 @@ LLUrlEntryBase::~LLUrlEntryBase()  {  } -std::string LLUrlEntryBase::getUrl(const std::string &string) +std::string LLUrlEntryBase::getUrl(const std::string &string) const  {  	return escapeUrl(string);  } @@ -89,7 +89,7 @@ std::string LLUrlEntryBase::escapeUrl(const std::string &url) const  	return LLURI::escape(url, no_escape_chars, true);  } -std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url) +std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url) const  {  	// return the label part from [http://www.example.org Label]  	const char *text = url.c_str(); @@ -105,7 +105,7 @@ std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url)  	return unescapeUrl(url.substr(start, url.size()-start-1));  } -std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) +std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) const  {  	// return the url part from [http://www.example.org Label]  	const char *text = string.c_str(); @@ -192,7 +192,7 @@ std::string LLUrlEntryHTTPLabel::getLabel(const std::string &url, const LLUrlLab  	return getLabelFromWikiLink(url);  } -std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) +std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const  {  	return getUrlFromWikiLink(string);  } @@ -217,7 +217,7 @@ std::string LLUrlEntryHTTPNoProtocol::getLabel(const std::string &url, const LLU  	return unescapeUrl(url);  } -std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) +std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const  {  	if (string.find("://") == std::string::npos)  	{ @@ -597,7 +597,7 @@ std::string LLUrlEntrySLLabel::getLabel(const std::string &url, const LLUrlLabel  	return getLabelFromWikiLink(url);  } -std::string LLUrlEntrySLLabel::getUrl(const std::string &string) +std::string LLUrlEntrySLLabel::getUrl(const std::string &string) const  {  	return getUrlFromWikiLink(string);  } @@ -648,14 +648,18 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const  //  LLUrlEntryNoLink::LLUrlEntryNoLink()  { -	mPattern = boost::regex("<nolink>[^[:space:]<]+</nolink>", +	mPattern = boost::regex("<nolink>[^<]*</nolink>",  							boost::regex::perl|boost::regex::icase);  	mDisabledLink = true;  } -std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +std::string LLUrlEntryNoLink::getUrl(const std::string &url) const  {  	// return the text between the <nolink> and </nolink> tags  	return url.substr(8, url.size()-8-9);  } +std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ +	return getUrl(url); +} diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 94455ac247..3abada0f24 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -71,7 +71,7 @@ public:  	boost::regex getPattern() const { return mPattern; }  	/// Return the url from a string that matched the regex -	virtual std::string getUrl(const std::string &string); +	virtual std::string getUrl(const std::string &string) const;  	/// Given a matched Url, return a label for the Url  	virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; } @@ -98,8 +98,8 @@ protected:  	std::string getIDStringFromUrl(const std::string &url) const;  	std::string escapeUrl(const std::string &url) const;  	std::string unescapeUrl(const std::string &url) const; -	std::string getLabelFromWikiLink(const std::string &url); -	std::string getUrlFromWikiLink(const std::string &string); +	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); @@ -135,7 +135,7 @@ class LLUrlEntryHTTPLabel : public LLUrlEntryBase  public:  	LLUrlEntryHTTPLabel();  	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); -	/*virtual*/ std::string getUrl(const std::string &string); +	/*virtual*/ std::string getUrl(const std::string &string) const;  };  /// @@ -146,7 +146,7 @@ class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase  public:  	LLUrlEntryHTTPNoProtocol();  	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); -	/*virtual*/ std::string getUrl(const std::string &string); +	/*virtual*/ std::string getUrl(const std::string &string) const;  };  /// @@ -256,7 +256,7 @@ class LLUrlEntrySLLabel : public LLUrlEntryBase  public:  	LLUrlEntrySLLabel();  	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); -	/*virtual*/ std::string getUrl(const std::string &string); +	/*virtual*/ std::string getUrl(const std::string &string) const;  };  /// @@ -279,6 +279,7 @@ class LLUrlEntryNoLink : public LLUrlEntryBase  public:  	LLUrlEntryNoLink();  	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); +	/*virtual*/ std::string getUrl(const std::string &string) const;  };  #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 55eb8950e9..722dbe41b3 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -132,7 +132,8 @@ static bool stringHasUrl(const std::string &text)  			text.find(".com") != std::string::npos ||  			text.find(".net") != std::string::npos ||  			text.find(".edu") != std::string::npos || -			text.find(".org") != std::string::npos); +			text.find(".org") != std::string::npos || +			text.find("<nolink>") != std::string::npos);  }  bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index bc97cf3df2..cbb303a059 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -52,9 +52,10 @@ namespace  namespace tut  { -	void testRegex(const std::string &testname, boost::regex regex, +	void testRegex(const std::string &testname, LLUrlEntryBase &entry,  				   const char *text, const std::string &expected)  	{ +		boost::regex regex = entry.getPattern();  		std::string url = "";  		boost::cmatch result;  		bool found = boost::regex_search(text, result, regex); @@ -62,7 +63,7 @@ namespace tut  		{  			S32 start = static_cast<U32>(result[0].first - text);  			S32 end = static_cast<U32>(result[0].second - text); -			url = std::string(text+start, end-start); +			url = entry.getUrl(std::string(text+start, end-start));  		}  		ensure_equals(testname, url, expected);  	} @@ -74,74 +75,73 @@ namespace tut  		// test LLUrlEntryHTTP - standard http Urls  		//  		LLUrlEntryHTTP url; -		boost::regex r = url.getPattern(); -		testRegex("no valid url", r, +		testRegex("no valid url", url,  				  "htp://slurl.com/",  				  ""); -		testRegex("simple http (1)", r, +		testRegex("simple http (1)", url,  				  "http://slurl.com/",  				  "http://slurl.com/"); -		testRegex("simple http (2)", r, +		testRegex("simple http (2)", url,  				  "http://slurl.com",  				  "http://slurl.com"); -		testRegex("simple http (3)", r, +		testRegex("simple http (3)", url,  				  "http://slurl.com/about.php",  				  "http://slurl.com/about.php"); -		testRegex("simple https", r, +		testRegex("simple https", url,  				  "https://slurl.com/about.php",  				  "https://slurl.com/about.php"); -		testRegex("http in text (1)", r, +		testRegex("http in text (1)", url,  				  "XX http://slurl.com/ XX",  				  "http://slurl.com/"); -		testRegex("http in text (2)", r, +		testRegex("http in text (2)", url,  				  "XX http://slurl.com/about.php XX",  				  "http://slurl.com/about.php"); -		testRegex("https in text", r, +		testRegex("https in text", url,  				  "XX https://slurl.com/about.php XX",  				  "https://slurl.com/about.php"); -		testRegex("two http urls", r, +		testRegex("two http urls", url,  				  "XX http://slurl.com/about.php http://secondlife.com/ XX",  				  "http://slurl.com/about.php"); -		testRegex("http url with port and username", r, +		testRegex("http url with port and username", url,  				  "XX http://nobody@slurl.com:80/about.php http://secondlife.com/ XX",  				  "http://nobody@slurl.com:80/about.php"); -		testRegex("http url with port, username, and query string", r, +		testRegex("http url with port, username, and query string", url,  				  "XX http://nobody@slurl.com:80/about.php?title=hi%20there http://secondlife.com/ XX",  				  "http://nobody@slurl.com:80/about.php?title=hi%20there");  		// note: terminating commas will be removed by LLUrlRegistry:findUrl() -		testRegex("http url with commas in middle and terminating", r, +		testRegex("http url with commas in middle and terminating", url,  				  "XX http://slurl.com/?title=Hi,There, XX",  				  "http://slurl.com/?title=Hi,There,");  		// note: terminating periods will be removed by LLUrlRegistry:findUrl() -		testRegex("http url with periods in middle and terminating", r, +		testRegex("http url with periods in middle and terminating", url,  				  "XX http://slurl.com/index.php. XX",  				  "http://slurl.com/index.php.");  		// DEV-19842: Closing parenthesis ")" breaks urls -		testRegex("http url with brackets (1)", r, +		testRegex("http url with brackets (1)", url,  				  "XX http://en.wikipedia.org/wiki/JIRA_(software) XX",  				  "http://en.wikipedia.org/wiki/JIRA_(software)");  		// DEV-19842: Closing parenthesis ")" breaks urls -		testRegex("http url with brackets (2)", r,  +		testRegex("http url with brackets (2)", url,   				  "XX http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg XX",  				  "http://jira.secondlife.com/secure/attachment/17990/eggy+avs+in+1.21.0+(93713)+public+nightly.jpg");  		// DEV-10353: URLs in chat log terminated incorrectly when newline in chat -		testRegex("http url with newlines", r, +		testRegex("http url with newlines", url,  				  "XX\nhttp://www.secondlife.com/\nXX",  				  "http://www.secondlife.com/");  	} @@ -153,39 +153,38 @@ namespace tut  		// test LLUrlEntryHTTPLabel - wiki-style http Urls with labels  		//  		LLUrlEntryHTTPLabel url; -		boost::regex r = url.getPattern(); -		testRegex("invalid wiki url [1]", r, +		testRegex("invalid wiki url [1]", url,  				  "[http://www.example.org]",  				  ""); -		testRegex("invalid wiki url [2]", r, +		testRegex("invalid wiki url [2]", url,  				  "[http://www.example.org",  				  ""); -		testRegex("invalid wiki url [3]", r, +		testRegex("invalid wiki url [3]", url,  				  "[http://www.example.org Label",  				  ""); -		testRegex("example.org with label (spaces)", r, +		testRegex("example.org with label (spaces)", url,  				  "[http://www.example.org  Text]", -				  "[http://www.example.org  Text]"); +				  "http://www.example.org"); -		testRegex("example.org with label (tabs)", r, +		testRegex("example.org with label (tabs)", url,  				  "[http://www.example.org\t Text]", -				  "[http://www.example.org\t Text]"); +				  "http://www.example.org"); -		testRegex("SL http URL with label", r, +		testRegex("SL http URL with label", url,  				  "[http://www.secondlife.com/ Second Life]", -				  "[http://www.secondlife.com/ Second Life]"); +				  "http://www.secondlife.com/"); -		testRegex("SL https URL with label", r, +		testRegex("SL https URL with label", url,  				  "XXX [https://www.secondlife.com/ Second Life] YYY", -				  "[https://www.secondlife.com/ Second Life]"); +				  "https://www.secondlife.com/"); -		testRegex("SL http URL with label", r, +		testRegex("SL http URL with label", url,  				  "[http://www.secondlife.com/?test=Hi%20There Second Life]", -				  "[http://www.secondlife.com/?test=Hi%20There Second Life]"); +				  "http://www.secondlife.com/?test=Hi%20There");  	}  	template<> template<> @@ -195,69 +194,68 @@ namespace tut  		// test LLUrlEntrySLURL - second life URLs  		//  		LLUrlEntrySLURL url; -		boost::regex r = url.getPattern(); -		testRegex("no valid slurl [1]", r, +		testRegex("no valid slurl [1]", url,  				  "htp://slurl.com/secondlife/Ahern/50/50/50/",  				  ""); -		testRegex("no valid slurl [2]", r, +		testRegex("no valid slurl [2]", url,  				  "http://slurl.com/secondlife/",  				  ""); -		testRegex("no valid slurl [3]", r, +		testRegex("no valid slurl [3]", url,  				  "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/",  				  ""); -		testRegex("Ahern (50,50,50) [1]", r, +		testRegex("Ahern (50,50,50) [1]", url,  				  "http://slurl.com/secondlife/Ahern/50/50/50/",  				  "http://slurl.com/secondlife/Ahern/50/50/50/"); -		testRegex("Ahern (50,50,50) [2]", r, +		testRegex("Ahern (50,50,50) [2]", url,  				  "XXX http://slurl.com/secondlife/Ahern/50/50/50/ XXX",  				  "http://slurl.com/secondlife/Ahern/50/50/50/"); -		testRegex("Ahern (50,50,50) [3]", r, +		testRegex("Ahern (50,50,50) [3]", url,  				  "XXX http://slurl.com/secondlife/Ahern/50/50/50 XXX",  				  "http://slurl.com/secondlife/Ahern/50/50/50"); -		testRegex("Ahern (50,50,50) multicase", r, +		testRegex("Ahern (50,50,50) multicase", url,  				  "XXX http://SLUrl.com/SecondLife/Ahern/50/50/50/ XXX",  				  "http://SLUrl.com/SecondLife/Ahern/50/50/50/"); -		testRegex("Ahern (50,50) [1]", r, +		testRegex("Ahern (50,50) [1]", url,  				  "XXX http://slurl.com/secondlife/Ahern/50/50/ XXX",  				  "http://slurl.com/secondlife/Ahern/50/50/"); -		testRegex("Ahern (50,50) [2]", r, +		testRegex("Ahern (50,50) [2]", url,  				  "XXX http://slurl.com/secondlife/Ahern/50/50 XXX",  				  "http://slurl.com/secondlife/Ahern/50/50"); -		testRegex("Ahern (50)", r, +		testRegex("Ahern (50)", url,  				  "XXX http://slurl.com/secondlife/Ahern/50 XXX",  				  "http://slurl.com/secondlife/Ahern/50"); -		testRegex("Ahern", r, +		testRegex("Ahern", url,  				  "XXX http://slurl.com/secondlife/Ahern/ XXX",  				  "http://slurl.com/secondlife/Ahern/"); -		testRegex("Ahern SLURL with title", r, +		testRegex("Ahern SLURL with title", url,  				  "XXX http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX",  				  "http://slurl.com/secondlife/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); -		testRegex("Ahern SLURL with msg", r, +		testRegex("Ahern SLURL with msg", url,  				  "XXX http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here. XXX",  				  "http://slurl.com/secondlife/Ahern/50/50/50/?msg=Your%20text%20here.");  		// DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat -		testRegex("SLURL with brackets", r, +		testRegex("SLURL with brackets", url,  				  "XXX http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30 XXX",  				  "http://slurl.com/secondlife/Burning%20Life%20(Hyper)/27/210/30");  		// DEV-35459: SLURLs and teleport Links not parsed properly -		testRegex("SLURL with quote", r, +		testRegex("SLURL with quote", url,  				  "XXX http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701 XXX", -				  "http://slurl.com/secondlife/A'ksha%20Oasis/41/166/701"); +				  "http://slurl.com/secondlife/A%27ksha%20Oasis/41/166/701");  	}  	template<> template<> @@ -267,25 +265,24 @@ namespace tut  		// test LLUrlEntryAgent - secondlife://app/agent Urls  		//  		LLUrlEntryAgent url; -		boost::regex r = url.getPattern(); -		testRegex("Invalid Agent Url", r, +		testRegex("Invalid Agent Url", url,  				  "secondlife:///app/agent/0e346d8b-4433-4d66-XXXX-fd37083abc4c/about",  				  ""); -		testRegex("Agent Url ", r, +		testRegex("Agent Url ", url,  				  "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about",  				  "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); -		testRegex("Agent Url in text", r, +		testRegex("Agent Url in text", url,  				  "XXX secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about XXX",  				  "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); -		testRegex("Agent Url multicase", r, +		testRegex("Agent Url multicase", url,  				  "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About XXX",  				  "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About"); -		testRegex("Agent Url alternate command", r, +		testRegex("Agent Url alternate command", url,  				  "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar",  				  "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar"); @@ -298,25 +295,24 @@ namespace tut  		// test LLUrlEntryGroup - secondlife://app/group Urls  		//  		LLUrlEntryGroup url; -		boost::regex r = url.getPattern(); -		testRegex("Invalid Group Url", r, +		testRegex("Invalid Group Url", url,  				  "secondlife:///app/group/00005ff3-4044-c79f-XXXX-fb28ae0df991/about",  				  ""); -		testRegex("Group Url ", r, +		testRegex("Group Url ", url,  				  "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about",  				  "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); -		testRegex("Group Url ", r, +		testRegex("Group Url ", url,  				  "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect",  				  "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect"); -		testRegex("Group Url in text", r, +		testRegex("Group Url in text", url,  				  "XXX secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about XXX",  				  "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about"); -		testRegex("Group Url multicase", r, +		testRegex("Group Url multicase", url,  				  "XXX secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About XXX",  				  "secondlife:///APP/Group/00005FF3-4044-c79f-9de8-fb28ae0df991/About");  	} @@ -328,45 +324,44 @@ namespace tut  		// test LLUrlEntryPlace - secondlife://<location> URLs  		//  		LLUrlEntryPlace url; -		boost::regex r = url.getPattern(); -		testRegex("no valid slurl [1]", r, +		testRegex("no valid slurl [1]", url,  				  "secondlife://Ahern/FOO/50/",  				  ""); -		testRegex("Ahern (50,50,50) [1]", r, +		testRegex("Ahern (50,50,50) [1]", url,  				  "secondlife://Ahern/50/50/50/",  				  "secondlife://Ahern/50/50/50/"); -		testRegex("Ahern (50,50,50) [2]", r, +		testRegex("Ahern (50,50,50) [2]", url,  				  "XXX secondlife://Ahern/50/50/50/ XXX",  				  "secondlife://Ahern/50/50/50/"); -		testRegex("Ahern (50,50,50) [3]", r, +		testRegex("Ahern (50,50,50) [3]", url,  				  "XXX secondlife://Ahern/50/50/50 XXX",  				  "secondlife://Ahern/50/50/50"); -		testRegex("Ahern (50,50,50) multicase", r, +		testRegex("Ahern (50,50,50) multicase", url,  				  "XXX SecondLife://Ahern/50/50/50/ XXX",  				  "SecondLife://Ahern/50/50/50/"); -		testRegex("Ahern (50,50) [1]", r, +		testRegex("Ahern (50,50) [1]", url,  				  "XXX secondlife://Ahern/50/50/ XXX",  				  "secondlife://Ahern/50/50/"); -		testRegex("Ahern (50,50) [2]", r, +		testRegex("Ahern (50,50) [2]", url,  				  "XXX secondlife://Ahern/50/50 XXX",  				  "secondlife://Ahern/50/50");  		// DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat -		testRegex("SLURL with brackets", r, +		testRegex("SLURL with brackets", url,  				  "XXX secondlife://Burning%20Life%20(Hyper)/27/210/30 XXX",  				  "secondlife://Burning%20Life%20(Hyper)/27/210/30");  		// DEV-35459: SLURLs and teleport Links not parsed properly -		testRegex("SLURL with quote", r, +		testRegex("SLURL with quote", url,  				  "XXX secondlife://A'ksha%20Oasis/41/166/701 XXX", -				  "secondlife://A'ksha%20Oasis/41/166/701"); +				  "secondlife://A%27ksha%20Oasis/41/166/701");  	}  	template<> template<> @@ -376,21 +371,20 @@ namespace tut  		// test LLUrlEntryParcel - secondlife://app/parcel Urls  		//  		LLUrlEntryParcel url; -		boost::regex r = url.getPattern(); -		testRegex("Invalid Classified Url", r, +		testRegex("Invalid Classified Url", url,  				  "secondlife:///app/parcel/0000060e-4b39-e00b-XXXX-d98b1934e3a8/about",  				  ""); -		testRegex("Classified Url ", r, +		testRegex("Classified Url ", url,  				  "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about",  				  "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); -		testRegex("Classified Url in text", r, +		testRegex("Classified Url in text", url,  				  "XXX secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about XXX",  				  "secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about"); -		testRegex("Classified Url multicase", r, +		testRegex("Classified Url multicase", url,  				  "XXX secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About XXX",  				  "secondlife:///APP/Parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/About");  	} @@ -401,73 +395,72 @@ namespace tut  		// test LLUrlEntryTeleport - secondlife://app/teleport URLs  		//  		LLUrlEntryTeleport url; -		boost::regex r = url.getPattern(); -		testRegex("no valid teleport [1]", r, +		testRegex("no valid teleport [1]", url,  				  "http://slurl.com/secondlife/Ahern/50/50/50/",  				  ""); -		testRegex("no valid teleport [2]", r, +		testRegex("no valid teleport [2]", url,  				  "secondlife:///app/teleport/",  				  ""); -		testRegex("no valid teleport [3]", r, +		testRegex("no valid teleport [3]", url,  				  "second-life:///app/teleport/Ahern/50/50/50/",  				  ""); -		testRegex("no valid teleport [3]", r, +		testRegex("no valid teleport [3]", url,  				  "hhtp://slurl.com/secondlife/Ahern/50/FOO/50/",  				  ""); -		testRegex("Ahern (50,50,50) [1]", r, +		testRegex("Ahern (50,50,50) [1]", url,  				  "secondlife:///app/teleport/Ahern/50/50/50/",  				  "secondlife:///app/teleport/Ahern/50/50/50/"); -		testRegex("Ahern (50,50,50) [2]", r, +		testRegex("Ahern (50,50,50) [2]", url,  				  "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX",  				  "secondlife:///app/teleport/Ahern/50/50/50/"); -		testRegex("Ahern (50,50,50) [3]", r, +		testRegex("Ahern (50,50,50) [3]", url,  				  "XXX secondlife:///app/teleport/Ahern/50/50/50 XXX",  				  "secondlife:///app/teleport/Ahern/50/50/50"); -		testRegex("Ahern (50,50,50) multicase", r, +		testRegex("Ahern (50,50,50) multicase", url,  				  "XXX secondlife:///app/teleport/Ahern/50/50/50/ XXX",  				  "secondlife:///app/teleport/Ahern/50/50/50/"); -		testRegex("Ahern (50,50) [1]", r, +		testRegex("Ahern (50,50) [1]", url,  				  "XXX secondlife:///app/teleport/Ahern/50/50/ XXX",  				  "secondlife:///app/teleport/Ahern/50/50/"); -		testRegex("Ahern (50,50) [2]", r, +		testRegex("Ahern (50,50) [2]", url,  				  "XXX secondlife:///app/teleport/Ahern/50/50 XXX",  				  "secondlife:///app/teleport/Ahern/50/50"); -		testRegex("Ahern (50)", r, +		testRegex("Ahern (50)", url,  				  "XXX secondlife:///app/teleport/Ahern/50 XXX",  				  "secondlife:///app/teleport/Ahern/50"); -		testRegex("Ahern", r, +		testRegex("Ahern", url,  				  "XXX secondlife:///app/teleport/Ahern/ XXX",  				  "secondlife:///app/teleport/Ahern/"); -		testRegex("Ahern teleport with title", r, +		testRegex("Ahern teleport with title", url,  				  "XXX secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE! XXX",  				  "secondlife:///app/teleport/Ahern/50/50/50/?title=YOUR%20TITLE%20HERE!"); -		testRegex("Ahern teleport with msg", r, +		testRegex("Ahern teleport with msg", url,  				  "XXX secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here. XXX",  				  "secondlife:///app/teleport/Ahern/50/50/50/?msg=Your%20text%20here.");  		// DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat -		testRegex("Teleport with brackets", r, +		testRegex("Teleport with brackets", url,  				  "XXX secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30 XXX",  				  "secondlife:///app/teleport/Burning%20Life%20(Hyper)/27/210/30");  		// DEV-35459: SLURLs and teleport Links not parsed properly -		testRegex("Teleport url with quote", r, +		testRegex("Teleport url with quote", url,  				  "XXX secondlife:///app/teleport/A'ksha%20Oasis/41/166/701 XXX", -				  "secondlife:///app/teleport/A'ksha%20Oasis/41/166/701"); +				  "secondlife:///app/teleport/A%27ksha%20Oasis/41/166/701");  	}  	template<> template<> @@ -477,33 +470,32 @@ namespace tut  		// test LLUrlEntrySL - general secondlife:// URLs  		//  		LLUrlEntrySL url; -		boost::regex r = url.getPattern(); -		testRegex("no valid slapp [1]", r, +		testRegex("no valid slapp [1]", url,  				  "http:///app/",  				  ""); -		testRegex("valid slapp [1]", r, +		testRegex("valid slapp [1]", url,  				  "secondlife:///app/",  				  "secondlife:///app/"); -		testRegex("valid slapp [2]", r, +		testRegex("valid slapp [2]", url,  				  "secondlife:///app/teleport/Ahern/50/50/50/",  				  "secondlife:///app/teleport/Ahern/50/50/50/"); -		testRegex("valid slapp [3]", r, +		testRegex("valid slapp [3]", url,  				  "secondlife:///app/foo",  				  "secondlife:///app/foo"); -		testRegex("valid slapp [4]", r, +		testRegex("valid slapp [4]", url,  				  "secondlife:///APP/foo?title=Hi%20There",  				  "secondlife:///APP/foo?title=Hi%20There"); -		testRegex("valid slapp [5]", r, +		testRegex("valid slapp [5]", url,  				  "secondlife://host/app/",  				  "secondlife://host/app/"); -		testRegex("valid slapp [6]", r, +		testRegex("valid slapp [6]", url,  				  "secondlife://host:8080/foo/bar",  				  "secondlife://host:8080/foo/bar");  	} @@ -515,35 +507,34 @@ namespace tut  		// test LLUrlEntrySLLabel - general secondlife:// URLs with labels  		//  		LLUrlEntrySLLabel url; -		boost::regex r = url.getPattern(); -		testRegex("invalid wiki url [1]", r, +		testRegex("invalid wiki url [1]", url,  				  "[secondlife:///app/]",  				  ""); -		testRegex("invalid wiki url [2]", r, +		testRegex("invalid wiki url [2]", url,  				  "[secondlife:///app/",  				  ""); -		testRegex("invalid wiki url [3]", r, +		testRegex("invalid wiki url [3]", url,  				  "[secondlife:///app/ Label",  				  ""); -		testRegex("agent slurl with label (spaces)", r, +		testRegex("agent slurl with label (spaces)", url,  				  "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about  Text]", -				  "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about  Text]"); +				  "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); -		testRegex("agent slurl with label (tabs)", r, +		testRegex("agent slurl with label (tabs)", url,  				  "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]", -				  "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about\t Text]"); +				  "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); -		testRegex("agent slurl with label", r, +		testRegex("agent slurl with label", url,  				  "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]", -				  "[secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about FirstName LastName]"); +				  "secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about"); -		testRegex("teleport slurl with label", r, +		testRegex("teleport slurl with label", url,  				  "XXX [secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern] YYY", -				  "[secondlife:///app/teleport/Ahern/50/50/50/ Teleport to Ahern]"); +				  "secondlife:///app/teleport/Ahern/50/50/50/");  	}  	template<> template<> @@ -553,70 +544,98 @@ namespace tut  		// test LLUrlEntryHTTPNoProtocol - general URLs without a protocol  		//  		LLUrlEntryHTTPNoProtocol url; -		boost::regex r = url.getPattern(); -		testRegex("naked .com URL", r, +		testRegex("naked .com URL", url,  				  "see google.com", -				  "google.com"); +				  "http://google.com"); -		testRegex("naked .org URL", r, +		testRegex("naked .org URL", url,  				  "see en.wikipedia.org for details", -				  "en.wikipedia.org"); +				  "http://en.wikipedia.org"); -		testRegex("naked .net URL", r, +		testRegex("naked .net URL", url,  				  "example.net", -				  "example.net"); +				  "http://example.net"); -		testRegex("naked .edu URL (2 instances)", r, +		testRegex("naked .edu URL (2 instances)", url,  				  "MIT web site is at web.mit.edu and also www.mit.edu", -				  "web.mit.edu"); +				  "http://web.mit.edu"); -		testRegex("don't match e-mail addresses", r, +		testRegex("don't match e-mail addresses", url,  				  "test@lindenlab.com",  				  ""); -		testRegex(".com URL with path", r, +		testRegex(".com URL with path", url,  				  "see secondlife.com/status for grid status", -				  "secondlife.com/status"); +				  "http://secondlife.com/status"); -		testRegex(".com URL with port", r, +		testRegex(".com URL with port", url,  				  "secondlife.com:80", -				  "secondlife.com:80"); +				  "http://secondlife.com:80"); -		testRegex(".com URL with port and path", r, +		testRegex(".com URL with port and path", url,  				  "see secondlife.com:80/status", -				  "secondlife.com:80/status"); +				  "http://secondlife.com:80/status"); -		testRegex("www.*.com URL with port and path", r, +		testRegex("www.*.com URL with port and path", url,  				  "see www.secondlife.com:80/status", -				  "www.secondlife.com:80/status"); +				  "http://www.secondlife.com:80/status"); -		testRegex("invalid .com URL [1]", r, +		testRegex("invalid .com URL [1]", url,  				  "..com",  				  ""); -		testRegex("invalid .com URL [2]", r, +		testRegex("invalid .com URL [2]", url,  				  "you.come",  				  ""); -		testRegex("invalid .com URL [3]", r, +		testRegex("invalid .com URL [3]", url,  				  "recommended",  				  ""); -		testRegex("invalid .edu URL", r, +		testRegex("invalid .edu URL", url,  				  "hi there scheduled maitenance has begun",  				  ""); -		testRegex("invalid .net URL", r, +		testRegex("invalid .net URL", url,  				  "foo.netty",  				  ""); -		testRegex("XML tags around URL [1]", r, +		testRegex("XML tags around URL [1]", url,  				  "<foo>secondlife.com</foo>", -				  "secondlife.com"); +				  "http://secondlife.com"); -		testRegex("XML tags around URL [2]", r, +		testRegex("XML tags around URL [2]", url,  				  "<foo>secondlife.com/status?bar=1</foo>", -				  "secondlife.com/status?bar=1"); +				  "http://secondlife.com/status?bar=1"); +	} + +	template<> template<> +	void object::test<12>() +	{ +		// +		// test LLUrlEntryNoLink - turn off hyperlinking +		// +		LLUrlEntryNoLink url; + +		testRegex("<nolink> [1]", url, +				  "<nolink>google.com</nolink>", +				  "google.com"); + +		testRegex("<nolink> [2]", url, +				  "<nolink>google.com", +				  ""); + +		testRegex("<nolink> [3]", url, +				  "google.com</nolink>", +				  ""); + +		testRegex("<nolink> [4]", url, +				  "<nolink>Hello World</nolink>", +				  "Hello World"); + +		testRegex("<nolink> [5]", url, +				  "<nolink>My Object</nolink>", +				  "My Object");  	}  } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 581c210bd5..7c22ac9e36 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -579,19 +579,26 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  				url += "?name=" + chat.mFromName;  				url += "&owner=" + args["owner_id"].asString(); -				LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); -				if (region) +				std::string slurl = args["slurl"].asString(); +				if (slurl.empty())  				{ -					S32 x, y, z; -					LLSLURL::globalPosToXYZ(LLVector3d(chat.mPosAgent), x, y, z); -					url += "&slurl=" + region->getName() + llformat("/%d/%d/%d", x, y, z); +					LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); +					if (region) +					{ +						S32 x, y, z; +						LLSLURL::globalPosToXYZ(LLVector3d(chat.mPosAgent), x, y, z); +						slurl = region->getName() + llformat("/%d/%d/%d", x, y, z); +					}  				} +				url += "&slurl=" + slurl;  				// set the link for the object name to be the objectim SLapp +				// (don't let object names with hyperlinks override our objectim Url)  				LLStyle::Params link_params(style_params);  				link_params.color.control = "HTMLLinkColor";  				link_params.link_href = url; -				mEditor->appendText(chat.mFromName + delimiter, false, link_params); +				mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>"  + delimiter, +									false, link_params);  			}  			else if ( chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() )  			{ diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index f7f7ee83af..f772aea4bd 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -258,8 +258,12 @@ BOOL	LLNearbyChatToastPanel::handleMouseDown	(S32 x, S32 y, MASK mask)  BOOL	LLNearbyChatToastPanel::handleMouseUp	(S32 x, S32 y, MASK mask)  { +	/* +	fix for request  EXT-4780 +	leaving this commented since I don't remember why ew block those messages...  	if(mSourceType != CHAT_SOURCE_AGENT)  		return LLPanel::handleMouseUp(x,y,mask); +    */  	LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false);  	S32 local_x = x - text_box->getRect().mLeft; diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index 784c2eaaf9..22eb9a51d2 100644 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -52,6 +52,7 @@ LLIMFloaterContainer::~LLIMFloaterContainer(){}  BOOL LLIMFloaterContainer::postBuild()  { +	LLIMModel::instance().mNewMsgSignal.connect(boost::bind(&LLIMFloaterContainer::onNewMessageReceived, this, _1));  	// Do not call base postBuild to not connect to mCloseSignal to not close all floaters via Close button  	// mTabContainer will be initialized in LLMultiFloater::addChild()  	return TRUE; @@ -162,6 +163,21 @@ void LLIMFloaterContainer::onCloseFloater(LLUUID id)  {  	LLAvatarPropertiesProcessor::instance().removeObserver(id, this);  	LLGroupMgr::instance().removeObserver(id, this); + +} + +void LLIMFloaterContainer::onNewMessageReceived(const LLSD& data) +{ +	LLUUID session_id = data["from_id"].asUUID(); +	LLFloater* floaterp = get_ptr_in_map(mSessions, session_id); +	LLFloater* current_floater = LLMultiFloater::getActiveFloater(); + +	if(floaterp && current_floater && floaterp != current_floater) +	{ +		if(LLMultiFloater::isFloaterFlashing(floaterp)) +			LLMultiFloater::setFloaterFlashing(floaterp, FALSE); +		LLMultiFloater::setFloaterFlashing(floaterp, TRUE); +	}  }  LLIMFloaterContainer* LLIMFloaterContainer::findInstance() diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index e4a32dbe1d..bc06f0cbd3 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -66,10 +66,12 @@ public:  	static LLIMFloaterContainer* getInstance();  private: -	typedef std::map<LLUUID,LLPanel*> avatarID_panel_map_t; +	typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t;  	avatarID_panel_map_t mSessions;  	void onCloseFloater(LLUUID avatar_id); + +	void onNewMessageReceived(const LLSD& data);  };  #endif // LL_LLIMFLOATERCONTAINER_H diff --git a/indra/newview/llinspect.cpp b/indra/newview/llinspect.cpp index c7b8db9635..c7b651f37c 100644 --- a/indra/newview/llinspect.cpp +++ b/indra/newview/llinspect.cpp @@ -34,6 +34,7 @@  #include "llcontrol.h"	// LLCachedControl  #include "llui.h"		// LLUI::sSettingsGroups +#include "llviewermenu.h"  LLInspect::LLInspect(const LLSD& key)  :	LLFloater(key), @@ -108,3 +109,26 @@ void LLInspect::onMouseLeave(S32 x, S32 y, MASK mask)  {  	mOpenTimer.unpause();  } + +bool LLInspect::childHasVisiblePopupMenu() +{ +	// Child text-box may spawn a pop-up menu, if mouse is over the menu, Inspector  +	// will hide(which is not expected). +	// This is an attempt to find out if child control has spawned a menu. + +	LLView* child_menu = gMenuHolder->getVisibleMenu(); +	if(child_menu) +	{ +		LLRect floater_rc = calcScreenRect(); +		LLRect menu_screen_rc = child_menu->calcScreenRect(); +		S32 mx, my; +		LLUI::getMousePositionScreen(&mx, &my); + +		// This works wrong if we spawn a menu near Inspector and menu overlaps Inspector. +		if(floater_rc.overlaps(menu_screen_rc) && menu_screen_rc.pointInRect(mx, my)) +		{ +			return true; +		} +	} +	return false; +} diff --git a/indra/newview/llinspect.h b/indra/newview/llinspect.h index a1cb9cd71c..f8c86618d2 100644 --- a/indra/newview/llinspect.h +++ b/indra/newview/llinspect.h @@ -56,6 +56,9 @@ public:  	/*virtual*/ void onFocusLost();  protected: + +	virtual bool childHasVisiblePopupMenu(); +  	LLFrameTimer		mCloseTimer;  	LLFrameTimer		mOpenTimer;  }; diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 3a41aebf28..b2cdc0738f 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -393,11 +393,18 @@ void LLInspectAvatar::onMouseLeave(S32 x, S32 y, MASK mask)  {  	LLMenuGL* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();  	LLMenuGL* gear_menu_self = getChild<LLMenuButton>("gear_self_btn")->getMenu(); -	if ( !(gear_menu && gear_menu->getVisible()) && -		 !(gear_menu_self && gear_menu_self->getVisible())) +	if ( gear_menu && gear_menu->getVisible() && +		 gear_menu_self && gear_menu_self->getVisible() )  	{ -		mOpenTimer.unpause(); +		return; +	} + +	if(childHasVisiblePopupMenu()) +	{ +		return;  	} + +	mOpenTimer.unpause();  }  void LLInspectAvatar::updateModeratorPanel() diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index dd313c528d..1a5795a2ae 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -575,10 +575,17 @@ void LLInspectObject::updateSecureBrowsing()  void LLInspectObject::onMouseLeave(S32 x, S32 y, MASK mask)  {  	LLMenuGL* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu(); -	if ( !(gear_menu && gear_menu->getVisible())) +	if ( gear_menu && gear_menu->getVisible() )  	{ -		mOpenTimer.unpause(); +		return; +	} + +	if(childHasVisiblePopupMenu()) +	{ +		return;  	} + +	mOpenTimer.unpause();  }  void LLInspectObject::onClickBuy() diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index 898f1cd9ac..66e4a1bf66 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -167,7 +167,8 @@ void LLInspectRemoteObject::nameCallback(const LLUUID& id, const std::string& fi  void LLInspectRemoteObject::update()  {  	// show the object name as the inspector's title -	getChild<LLUICtrl>("object_name")->setValue(mName); +	// (don't hyperlink URLs in object names) +	getChild<LLUICtrl>("object_name")->setValue("<nolink>" + mName + "</nolink>");  	// show the object's owner - click it to show profile  	std::string owner = mOwner; @@ -192,7 +193,7 @@ void LLInspectRemoteObject::update()  	std::string url;  	if (! mSLurl.empty())  	{ -		std::string url = "secondlife:///app/teleport/" + mSLurl; +		url = "secondlife:///app/teleport/" + mSLurl;  	}  	getChild<LLUICtrl>("object_slurl")->setValue(url); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e8a4899a0b..f68550d8fd 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3773,6 +3773,21 @@ void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* mode  		gInventory.updateItem(item);  		gInventory.notifyObservers();  	} +	else if("play" == action) +	{ +		if(!LLGestureManager::instance().isGestureActive(mUUID)) +		{ +			// we need to inform server about gesture activating to be consistent with LLPreviewGesture and  LLGestureComboList. +			BOOL inform_server = TRUE; +			BOOL deactivate_similar = FALSE; +			LLGestureManager::instance().setGestureLoadedCallback(mUUID, boost::bind(&LLGestureBridge::playGesture, mUUID)); +			LLGestureManager::instance().activateGestureWithAsset(mUUID, gInventory.getItem(mUUID)->getAssetUUID(), inform_server, deactivate_similar); +		} +		else +		{ +			playGesture(mUUID); +		} +	}  	else LLItemBridge::performAction(folder, model, action);  } @@ -3858,6 +3873,20 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  	hide_context_entries(menu, items, disabled_items);  } +// static +void LLGestureBridge::playGesture(const LLUUID& item_id) +{ +	if (LLGestureManager::instance().isGesturePlaying(item_id)) +	{ +		LLGestureManager::instance().stopGesture(item_id); +	} +	else +	{ +		LLGestureManager::instance().playGesture(item_id); +	} +} + +  // +=================================================+  // |        LLAnimationBridge                        |  // +=================================================+ diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index eeb8246b11..6fffec96a0 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -491,6 +491,8 @@ public:  	virtual void buildContextMenu(LLMenuGL& menu, U32 flags); +	static void playGesture(const LLUUID& item_id); +  protected:  	LLGestureBridge(LLInventoryPanel* inventory, const LLUUID& uuid)  	:	LLItemBridge(inventory, uuid) {} diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index dc187bf36c..96ce01c05f 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -138,16 +138,20 @@ void LLLogChat::saveHistory(const std::string& filename,  			    const LLUUID& from_id,  			    const std::string& line)  { -	if(!filename.size()) +	std::string tmp_filename = filename; +	LLStringUtil::trim(tmp_filename); +	if (tmp_filename.empty())  	{ -		llinfos << "Filename is Empty!" << llendl; +		std::string warn = "Chat history filename [" + filename + "] is empty!"; +		llwarning(warn, 666); +		llassert(tmp_filename.size());  		return;  	} - +	  	llofstream file (LLLogChat::makeLogFileName(filename), std::ios_base::app);  	if (!file.is_open())  	{ -		llinfos << "Couldn't open chat history log!" << llendl; +		llwarns << "Couldn't open chat history log! - " + filename << llendl;  		return;  	} diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 90482eb74d..6de47fccd2 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -62,6 +62,12 @@  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) @@ -194,6 +200,18 @@ void	LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args)  		mMessageArchive.push_back(chat);  		if(mMessageArchive.size()>200)  			mMessageArchive.erase(mMessageArchive.begin()); + +		if (gSavedPerAccountSettings.getBOOL("LogChat"))  +		{ +			if (chat.mChatType != CHAT_TYPE_WHISPER && chat.mChatType != CHAT_TYPE_SHOUT) +			{ +				LLLogChat::saveHistory("chat", chat.mFromName, chat.mFromID, chat.mText); +			} +			else +			{ +				LLLogChat::saveHistory("chat", "", chat.mFromID, chat.mFromName + " " + chat.mText); +			} +		}  	}  } @@ -262,6 +280,39 @@ void LLNearbyChat::processChatHistoryStyleUpdate(const LLSD& newvalue)  		nearby_chat->updateChatHistoryStyle();  } +void LLNearbyChat::loadHistory() +{ +	std::list<LLSD> history; +	LLLogChat::loadAllHistory("chat", history); + +	std::list<LLSD>::const_iterator it = history.begin(); +	while (it != history.end()) +	{ +		const LLSD& msg = *it; + +		std::string from = msg[IM_FROM]; +		LLUUID from_id = LLUUID::null; +		if (msg[IM_FROM_ID].isUndefined()) +		{ +			gCacheName->getUUID(from, from_id); +		} + +		LLChat chat; +		chat.mFromName = from; +		chat.mFromID = from_id; +		chat.mText = msg[IM_TEXT].asString(); +		chat.mTimeStr = msg[IM_TIME].asString(); +		addMessage(chat); + +		it++; +	} +} + +//static +LLNearbyChat* LLNearbyChat::getInstance() +{ +	return LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); +}  ////////////////////////////////////////////////////////////////////////////////  // @@ -278,3 +329,4 @@ void LLNearbyChat::onFocusLost()  	setBackgroundOpaque(false);  	LLPanel::onFocusLost();  } + diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index 5fb8ade19e..6ef2a1fee3 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -47,6 +47,8 @@ public:  	~LLNearbyChat();  	BOOL	postBuild			(); + +	/** @param archive true - to save a message to the chat history log */  	void	addMessage			(const LLChat& message,bool archive = true, const LLSD &args = LLSD());	  	void	onNearbyChatContextMenuItemClicked(const LLSD& userdata);  	bool	onNearbyChatCheckContextMenuItem(const LLSD& userdata); @@ -65,6 +67,10 @@ public:  	static void processChatHistoryStyleUpdate(const LLSD& newvalue); +	void loadHistory(); + +	static LLNearbyChat* getInstance(); +  private:  	virtual void    applySavedVariables(); diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index e2a748a1c5..b8e0892b02 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -168,6 +168,12 @@ void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_fi  			session_name = "chat";  		} +		//there still appears a log history file with weird name " .txt" +		if (" " == session_name || "{waiting}" == session_name || "{nobody}" == session_name) +		{ +			llwarning("Weird session name (" + session_name + ") for notification " + notification->getName(), 666) +		} +  		if(to_file_only)  		{  			logToIM(IM_NOTHING_SPECIAL, session_name, name, notification->getMessage(), diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 29cfbbe606..a49386cb5c 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -70,6 +70,7 @@  #include "lltoggleablemenu.h"  #include "llviewerinventory.h"  #include "llviewermenu.h" +#include "llviewermessage.h"  #include "llviewerparcelmgr.h"  #include "llviewerregion.h"  #include "llviewerwindow.h" @@ -105,22 +106,35 @@ private:  	LLPanelPlaces*		mPlaces;  }; -class LLPlacesInventoryObserver : public LLInventoryObserver +class LLPlacesInventoryObserver : public LLInventoryAddedObserver  {  public:  	LLPlacesInventoryObserver(LLPanelPlaces* places_panel) : -		LLInventoryObserver(), -		mPlaces(places_panel) +		mPlaces(places_panel), +		mTabsCreated(false)  	{}  	/*virtual*/ void changed(U32 mask)  	{ -		if (mPlaces) -			mPlaces->changedInventory(mask); +		LLInventoryAddedObserver::changed(mask); + +		if (!mTabsCreated && mPlaces) +		{ +			mPlaces->createTabs(); +			mTabsCreated = true; +		} +	} + +protected: +	/*virtual*/ void done() +	{ +		mPlaces->showAddedLandmarkInfo(mAdded); +		mAdded.clear();  	}  private:  	LLPanelPlaces*		mPlaces; +	bool				mTabsCreated;  };  class LLPlacesRemoteParcelInfoObserver : public LLRemoteParcelInfoObserver @@ -943,7 +957,7 @@ void LLPanelPlaces::changedParcelSelection()  	updateVerbs();  } -void LLPanelPlaces::changedInventory(U32 mask) +void LLPanelPlaces::createTabs()  {  	if (!(gInventory.isInventoryUsable() && LLTeleportHistory::getInstance()))  		return; @@ -979,10 +993,6 @@ void LLPanelPlaces::changedInventory(U32 mask)  	// Filter applied to show all items.  	if (mActivePanel)  		mActivePanel->onSearchEdit(mActivePanel->getFilterSubString()); - -	// we don't need to monitor inventory changes anymore, -	// so remove the observer -	gInventory.removeObserver(mInventoryObserver);  }  void LLPanelPlaces::changedGlobalPos(const LLVector3d &global_pos) @@ -991,6 +1001,33 @@ void LLPanelPlaces::changedGlobalPos(const LLVector3d &global_pos)  	updateVerbs();  } +void LLPanelPlaces::showAddedLandmarkInfo(const std::vector<LLUUID>& items) +{ +	for (std::vector<LLUUID>::const_iterator item_iter = items.begin(); +		 item_iter != items.end(); +		 ++item_iter) +	{ +		const LLUUID& item_id = (*item_iter); +		if(!highlight_offered_item(item_id)) +		{ +			continue; +		} + +		LLInventoryItem* item = gInventory.getItem(item_id); + +		if (LLAssetType::AT_LANDMARK == item->getType()) +		{ +			// Created landmark is passed to Places panel to allow its editing. +			// If the panel is closed we don't reopen it until created landmark is loaded. +			if("create_landmark" == getPlaceInfoType() && !getItem()) +			{ +				setItem(item); +			} +			break; +		} +	} +} +  void LLPanelPlaces::updateVerbs()  {  	bool is_place_info_visible; diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index 110d7a1054..78fcbbb11d 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -66,11 +66,15 @@ public:  	// Called on parcel selection change to update place information.  	void changedParcelSelection(); -	// Called on agent inventory change to find out when inventory gets usable. -	void changedInventory(U32 mask); +	// Called once on agent inventory first change to find out when inventory gets usable +	// and to create "My Landmarks" and "Teleport History" tabs. +	void createTabs();  	// Called when we receive the global 3D position of a parcel.  	void changedGlobalPos(const LLVector3d &global_pos); +	// Opens landmark info panel when agent creates or receives landmark. +	void showAddedLandmarkInfo(const std::vector<LLUUID>& items); +  	void setItem(LLInventoryItem* item);  	LLInventoryItem* getItem() { return mItem; } diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index f83f3eba96..ad47e351ee 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -583,7 +583,8 @@ void LLParticipantList::LLParticipantListMenu::moderateVoiceOtherParticipants(co  bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD& userdata)  {  	std::string item = userdata.asString(); -	if (item == "can_mute_text" || "can_block" == item || "can_share" == item || "can_im" == item) +	if (item == "can_mute_text" || "can_block" == item || "can_share" == item || "can_im" == item  +		|| "can_pay" == item || "can_add" == item)  	{  		return mUUIDs.front() != gAgentID;  	} diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index a00b6a9288..8f36c0e88a 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -487,10 +487,21 @@ void LLScreenChannel::showToastsBottom()  		toast_rect.setOriginAndSize(getRect().mLeft, bottom + toast_margin, toast_rect.getWidth() ,toast_rect.getHeight());  		(*it).toast->setRect(toast_rect); -		// don't show toasts if there is not enough space  		if(floater && floater->overlapsScreenChannel())  		{ +			if(it == mToastList.rbegin()) +			{ +				// move first toast above docked floater +				S32 shift = floater->getRect().getHeight(); +				if(floater->getDockControl()) +				{ +					shift += floater->getDockControl()->getTongueHeight(); +				} +				(*it).toast->translate(0, shift); +			} +  			LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); +			// don't show toasts if there is not enough space  			if(toast_rect.mTop > world_rect.mTop)  			{  				break; @@ -802,16 +813,6 @@ void LLScreenChannel::updateShowToastsState()  	S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");;  	LLRect this_rect = getRect(); -	// adjust channel's height -	if(floater->overlapsScreenChannel()) -	{ -		channel_bottom += floater->getRect().getHeight(); -		if(floater->getDockControl()) -		{ -			channel_bottom += floater->getDockControl()->getTongueHeight(); -		} -	} -  	if(channel_bottom != this_rect.mBottom)  	{  		setRect(LLRect(this_rect.mLeft, this_rect.mTop, this_rect.mRight, channel_bottom)); diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index 5383158cd3..7b923f4b0b 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -164,7 +164,21 @@ void LLSidepanelInventory::onWearButtonClicked()  void LLSidepanelInventory::onPlayButtonClicked()  { -	performActionOnSelection("activate"); +	const LLInventoryItem *item = getSelectedItem(); +	if (!item) +	{ +		return; +	} + +	switch(item->getInventoryType()) +	{ +	case LLInventoryType::IT_GESTURE: +		performActionOnSelection("play"); +		break; +	default: +		performActionOnSelection("activate"); +		break; +	}  }  void LLSidepanelInventory::onTeleportButtonClicked() diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6b816f8786..522adc05ce 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -67,6 +67,7 @@  #include "llmemorystream.h"  #include "llmessageconfig.h"  #include "llmoveview.h" +#include "llnearbychat.h"  #include "llnotifications.h"  #include "llnotificationsutil.h"  #include "llteleporthistory.h" @@ -904,7 +905,8 @@ bool idle_startup()  		LLFile::mkdir(gDirUtilp->getChatLogsDir());  		LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); -		//good as place as any to create user windlight directories + +		//good a place as any to create user windlight directories  		std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", ""));  		LLFile::mkdir(user_windlight_path_name.c_str());		 @@ -1284,6 +1286,14 @@ bool idle_startup()              LLAppViewer::instance()->loadNameCache();  		} +		//gCacheName is required for nearby chat history loading +		//so I just moved nearby history loading a few states further +		if (!gNoRender && gSavedPerAccountSettings.getBOOL("LogShowHistory")) +		{ +			LLNearbyChat* nearby_chat = LLNearbyChat::getInstance(); +			if (nearby_chat) nearby_chat->loadHistory(); +		} +  		// *Note: this is where gWorldMap used to be initialized.  		// register null callbacks for audio until the audio system is initialized diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b0952dd698..adbe28e9a7 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -860,28 +860,12 @@ void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& f  		 ++item_iter)  	{  		const LLUUID& item_id = (*item_iter); -		LLInventoryItem* item = gInventory.getItem(item_id); -		if(!item) +		if(!highlight_offered_item(item_id))  		{ -			LL_WARNS("Messaging") << "Unable to show inventory item: " << item_id << LL_ENDL;  			continue;  		} -		//////////////////////////////////////////////////////////////////////////////// -		// Don't highlight if it's in certain "quiet" folders which don't need UI  -		// notification (e.g. trash, cof, lost-and-found). -		if(!gAgent.getAFK()) -		{ -			const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(item_id); -			if (parent) -			{ -				const LLFolderType::EType parent_type = parent->getPreferredType(); -				if (LLViewerFolderType::lookupIsQuietType(parent_type)) -				{ -					continue; -				} -			} -		} +		LLInventoryItem* item = gInventory.getItem(item_id);  		////////////////////////////////////////////////////////////////////////////////  		// Special handling for various types. @@ -928,10 +912,11 @@ void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& f  						LLPanelPlaces *places_panel = dynamic_cast<LLPanelPlaces*>(LLSideTray::getInstance()->getPanel("panel_places"));  						if (places_panel)  						{ -							// we are creating a landmark +							// Landmark creation handling is moved to LLPanelPlaces::showAddedLandmarkInfo() +							// TODO* LLPanelPlaces dependency is going to be removed. See EXT-4347.  							if("create_landmark" == places_panel->getPlaceInfoType() && !places_panel->getItem())  							{ -								places_panel->setItem(item); +								//places_panel->setItem(item);  							}  							// we are opening a group notice attachment  							else @@ -981,6 +966,34 @@ void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& f  	}  } +bool highlight_offered_item(const LLUUID& item_id) +{ +	LLInventoryItem* item = gInventory.getItem(item_id); +	if(!item) +	{ +		LL_WARNS("Messaging") << "Unable to show inventory item: " << item_id << LL_ENDL; +		return false; +	} + +	//////////////////////////////////////////////////////////////////////////////// +	// Don't highlight if it's in certain "quiet" folders which don't need UI +	// notification (e.g. trash, cof, lost-and-found). +	if(!gAgent.getAFK()) +	{ +		const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(item_id); +		if (parent) +		{ +			const LLFolderType::EType parent_type = parent->getPreferredType(); +			if (LLViewerFolderType::lookupIsQuietType(parent_type)) +			{ +				return false; +			} +		} +	} + +	return true; +} +  void inventory_offer_mute_callback(const LLUUID& blocked_id,  								   const std::string& first_name,  								   const std::string& last_name, @@ -2189,7 +2202,10 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)  			LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());  			if(nearby_chat)  			{ -				nearby_chat->addMessage(chat); +				LLSD args; +				args["owner_id"] = from_id; +				args["slurl"] = location; +				nearby_chat->addMessage(chat, true, args);  			} diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 1415c16090..7dd629dcfd 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -203,6 +203,11 @@ void process_initiate_download(LLMessageSystem* msg, void**);  void start_new_inventory_observer();  void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& from_name); +// Returns true if item is not in certain "quiet" folder which don't need UI +// notification (e.g. trash, cof, lost-and-found) and agent is not AFK, false otherwise. +// Returns false if item is not found. +bool highlight_offered_item(const LLUUID& item_id); +  struct LLOfferInfo  {          LLOfferInfo() 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 455018f467..d09a0a0535 100644 --- a/indra/newview/skins/default/xui/en/floater_pay_object.xml +++ b/indra/newview/skins/default/xui/en/floater_pay_object.xml @@ -36,7 +36,7 @@       top_delta="3"       name="payee_name"       width="184"> -      Ericacita Moostopolison +      [FIRST] [LAST]      </text>      <text       type="string" diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index 60c9810e95..2c9402f6cb 100644 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -46,8 +46,11 @@    <ui_ctrl       height="90"      width="90" +    layout="topleft"      name="thumbnail_placeholder"      top_pad="6" +    follows="left|top" +    left="10"      />      <text       type="string" diff --git a/indra/newview/skins/default/xui/en/menu_participant_list.xml b/indra/newview/skins/default/xui/en/menu_participant_list.xml index 805ffbae66..d03a7e3d41 100644 --- a/indra/newview/skins/default/xui/en/menu_participant_list.xml +++ b/indra/newview/skins/default/xui/en/menu_participant_list.xml @@ -78,6 +78,9 @@       name="Pay">          <menu_item_call.on_click           function="Avatar.Pay" /> +        <menu_item_call.on_enable +         function="ParticipantList.EnableItem" +         parameter="can_pay" />      </menu_item_call>          <menu_item_separator           layout="topleft" /> diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index 27461571da..40b9b56903 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -306,7 +306,7 @@           name="add_friend"           tool_tip="Offer friendship to the Resident"           top="5" -         width="81" /> +         width="80" />          <button           follows="bottom|left"           height="23" @@ -316,7 +316,7 @@           tool_tip="Open instant message session"           top="5"           left_pad="3" -         width="45" /> +         width="39" />          <button           follows="bottom|left"           height="23" @@ -326,7 +326,7 @@           tool_tip="Call this Resident"           left_pad="3"           top="5" -         width="46" /> +         width="43" />          <button           enabled="false"           follows="bottom|left" @@ -337,7 +337,7 @@           tool_tip="Show the Resident on the map"           top="5"           left_pad="3" -         width="46" /> +         width="41" />          <button           follows="bottom|left"           height="23" @@ -347,8 +347,8 @@           tool_tip="Offer teleport"           left_pad="3"           top="5" -         width="78" /> -       <!-- <button +         width="69" /> +        <button           follows="bottom|right"           height="23"           label="▼" @@ -357,8 +357,8 @@           tool_tip="Pay money to or share inventory with the Resident"           right="-1"           top="5" -	 left_pad="3" -         width="23" />--> +	 	 left_pad="3" +         width="23" />          </layout_panel>        <layout_panel           follows="bottom|left" | 
