From 0cf9168895b1d7b69e4a0307ade6cbc607f799f2 Mon Sep 17 00:00:00 2001
From: Yuri Chebotarev <ychebotarev@productengine.com>
Date: Fri, 2 Jul 2010 15:23:05 +0300
Subject: [PATCH] EXT-5692 FIX Add callback to create widget segment with
 LLAvatarIconCtrl (or LLGroupIconCtrl)  based on url match id.

reviewed by Richard Nelson at https://codereview.productengine.com/secondlife/r/610/

--HG--
branch : product-engine
---
 indra/llui/lltextbase.cpp     |  27 ++-
 indra/llui/lltextbase.h       | 334 +++++++++++++++++-----------------
 indra/llui/lltextutil.cpp     |  34 ++++
 indra/llui/lltextutil.h       |  15 ++
 indra/llui/llurlentry.cpp     |  13 ++
 indra/llui/llurlentry.h       |   2 +
 indra/newview/llappviewer.cpp |  43 +++++
 7 files changed, 285 insertions(+), 183 deletions(-)

diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 17e41d9e24d..e2f1d44f3e9 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -40,6 +40,7 @@
 #include "llscrollcontainer.h"
 #include "llstl.h"
 #include "lltextparser.h"
+#include "lltextutil.h"
 #include "lltooltip.h"
 #include "lluictrl.h"
 #include "llurlaction.h"
@@ -1594,6 +1595,9 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
 		while ( LLUrlRegistry::instance().findUrl(text, match,
 		        boost::bind(&LLTextBase::replaceUrlLabel, this, _1, _2)) )
 		{
+			
+			LLTextUtil::processUrlMatch(&match,this);
+
 			start = match.getStart();
 			end = match.getEnd()+1;
 
@@ -1618,22 +1622,6 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
 				std::string subtext=text.substr(0,start);
 				appendAndHighlightText(subtext, part, style_params); 
 			}
-
-			// output an optional icon before the Url
-			if (! match.getIcon().empty())
-			{
-				LLUIImagePtr image = LLUI::getUIImage(match.getIcon());
-				if (image)
-				{
-					LLStyle::Params icon;
-					icon.image = image;
-					// Text will be replaced during rendering with the icon,
-					// but string cannot be empty or the segment won't be
-					// added (or drawn).
-					appendImageSegment(icon);
-				}
-			}
-
 			// output the styled Url (unless we've been asked to suppress hyperlinking)
 			if (match.isLinkDisabled())
 			{
@@ -1715,7 +1703,14 @@ void LLTextBase::appendImageSegment(const LLStyle::Params& style_params)
 	insertStringNoUndo(getLength(), utf8str_to_wstring(" "), &segments);
 }
 
+void LLTextBase::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo)
+{
+	segment_vec_t segments;
+	LLWString widget_wide_text = utf8str_to_wstring(text);
+	segments.push_back(new LLInlineViewSegment(params, getLength(), getLength() + widget_wide_text.size()));
 
+	insertStringNoUndo(getLength(), widget_wide_text, &segments);
+}
 
 void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params)
 {
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index fe8ebb1b800..920833de393 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -47,8 +47,170 @@
 #include <boost/signals2.hpp>
 
 class LLContextMenu;
-class LLTextSegment;
-class LLNormalTextSegment;
+class LLUrlMatch;
+
+///
+/// A text segment is used to specify a subsection of a text string
+/// that should be formatted differently, such as a hyperlink. It
+/// includes a start/end offset from the start of the string, a
+/// style to render with, an optional tooltip, etc.
+///
+class LLTextSegment : public LLRefCount, public LLMouseHandler
+{
+public:
+	LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){};
+	virtual ~LLTextSegment();
+
+	virtual bool				getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
+	virtual S32					getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
+	virtual S32					getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+	virtual void				updateLayout(const class LLTextBase& editor);
+	virtual F32					draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+	virtual bool				canEdit() const;
+	virtual void				unlinkFromDocument(class LLTextBase* editor);
+	virtual void				linkToDocument(class LLTextBase* editor);
+
+	virtual const LLColor4&		getColor() const;
+	//virtual void 				setColor(const LLColor4 &color);
+	virtual LLStyleConstSP		getStyle() const;
+	virtual void 				setStyle(LLStyleConstSP style);
+	virtual void				setToken( LLKeywordToken* token );
+	virtual LLKeywordToken*		getToken() const;
+	virtual void				setToolTip(const std::string& tooltip);
+	virtual void				dump() const;
+
+	// LLMouseHandler interface
+	/*virtual*/ BOOL			handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleMiddleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleMiddleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleRightMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleRightMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleDoubleClick(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleHover(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL			handleScrollWheel(S32 x, S32 y, S32 clicks);
+	/*virtual*/ BOOL			handleToolTip(S32 x, S32 y, MASK mask);
+	/*virtual*/ std::string		getName() const;
+	/*virtual*/ void			onMouseCaptureLost();
+	/*virtual*/ void			screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
+	/*virtual*/ void			localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
+	/*virtual*/ BOOL			hasMouseCapture();
+
+	S32							getStart() const 					{ return mStart; }
+	void						setStart(S32 start)					{ mStart = start; }
+	S32							getEnd() const						{ return mEnd; }
+	void						setEnd( S32 end )					{ mEnd = end; }
+
+protected:
+	S32				mStart;
+	S32				mEnd;
+};
+
+class LLNormalTextSegment : public LLTextSegment
+{
+public:
+	LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
+	LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
+	~LLNormalTextSegment();
+
+	/*virtual*/ bool				getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
+	/*virtual*/ S32					getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
+	/*virtual*/ S32					getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+	/*virtual*/ F32					draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+	/*virtual*/ bool				canEdit() const { return true; }
+	/*virtual*/ const LLColor4&		getColor() const					{ return mStyle->getColor(); }
+	/*virtual*/ LLStyleConstSP		getStyle() const					{ return mStyle; }
+	/*virtual*/ void 				setStyle(LLStyleConstSP style)	{ mStyle = style; }
+	/*virtual*/ void				setToken( LLKeywordToken* token )	{ mToken = token; }
+	/*virtual*/ LLKeywordToken*		getToken() const					{ return mToken; }
+	/*virtual*/ BOOL				getToolTip( std::string& msg ) const;
+	/*virtual*/ void				setToolTip(const std::string& tooltip);
+	/*virtual*/ void				dump() const;
+
+	/*virtual*/ BOOL				handleHover(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL				handleRightMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL				handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL				handleMouseUp(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL				handleToolTip(S32 x, S32 y, MASK mask);
+
+protected:
+	F32					drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRect rect);
+
+protected:
+	class LLTextBase&	mEditor;
+	LLStyleConstSP		mStyle;
+	S32					mFontHeight;
+	LLKeywordToken* 	mToken;
+	std::string     	mTooltip;
+	boost::signals2::connection mImageLoadedConnection;
+};
+
+class LLIndexSegment : public LLTextSegment
+{
+public:
+	LLIndexSegment(S32 pos) : LLTextSegment(pos, pos) {}
+};
+
+class LLInlineViewSegment : public LLTextSegment
+{
+public:
+	struct Params : public LLInitParam::Block<Params>
+	{
+		Mandatory<LLView*>		view;
+		Optional<bool>			force_newline;
+		Optional<S32>			left_pad,
+								right_pad,
+								bottom_pad,
+								top_pad;
+	};
+
+	LLInlineViewSegment(const Params& p, S32 start, S32 end);
+	~LLInlineViewSegment();
+	/*virtual*/ bool		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
+	/*virtual*/ S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+	/*virtual*/ void		updateLayout(const class LLTextBase& editor);
+	/*virtual*/ F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+	/*virtual*/ bool		canEdit() const { return false; }
+	/*virtual*/ void		unlinkFromDocument(class LLTextBase* editor);
+	/*virtual*/ void		linkToDocument(class LLTextBase* editor);
+
+private:
+	S32 mLeftPad;
+	S32 mRightPad;
+	S32 mTopPad;
+	S32 mBottomPad;
+	LLView* mView;
+	bool	mForceNewLine;
+};
+
+class LLLineBreakTextSegment : public LLTextSegment
+{
+public:
+
+	LLLineBreakTextSegment(LLStyleConstSP style,S32 pos);
+	LLLineBreakTextSegment(S32 pos);
+	~LLLineBreakTextSegment();
+	bool		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
+	S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+	F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+
+private:
+	S32			mFontHeight;
+};
+
+class LLImageTextSegment : public LLTextSegment
+{
+public:
+	LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor);
+	~LLImageTextSegment();
+	bool		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
+	S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+	F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+
+private:
+	class LLTextBase&	mEditor;
+	LLStyleConstSP	mStyle;
+};
 
 typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
 
@@ -196,8 +358,9 @@ class LLTextBase
 
 	const LLFontGL*			getDefaultFont() const					{ return mDefaultFont; }
 
-	void					appendLineBreakSegment(const LLStyle::Params& style_params);
-	void					appendImageSegment(const LLStyle::Params& style_params);
+	virtual void			appendLineBreakSegment(const LLStyle::Params& style_params);
+	virtual void			appendImageSegment(const LLStyle::Params& style_params);
+	virtual void			appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);
 
 public:
 	// Fired when a URL link is clicked
@@ -385,167 +548,4 @@ class LLTextBase
 
 };
 
-///
-/// A text segment is used to specify a subsection of a text string
-/// that should be formatted differently, such as a hyperlink. It
-/// includes a start/end offset from the start of the string, a
-/// style to render with, an optional tooltip, etc.
-///
-class LLTextSegment : public LLRefCount, public LLMouseHandler
-{
-public:
-	LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){};
-	virtual ~LLTextSegment();
-
-	virtual bool				getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
-	virtual S32					getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
-	virtual S32					getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
-	virtual void				updateLayout(const class LLTextBase& editor);
-	virtual F32					draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
-	virtual bool				canEdit() const;
-	virtual void				unlinkFromDocument(class LLTextBase* editor);
-	virtual void				linkToDocument(class LLTextBase* editor);
-
-	virtual const LLColor4&		getColor() const;
-	//virtual void 				setColor(const LLColor4 &color);
-	virtual LLStyleConstSP		getStyle() const;
-	virtual void 				setStyle(LLStyleConstSP style);
-	virtual void				setToken( LLKeywordToken* token );
-	virtual LLKeywordToken*		getToken() const;
-	virtual void				setToolTip(const std::string& tooltip);
-	virtual void				dump() const;
-
-	// LLMouseHandler interface
-	/*virtual*/ BOOL			handleMouseDown(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleMouseUp(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleMiddleMouseDown(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleMiddleMouseUp(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleRightMouseDown(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleRightMouseUp(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleDoubleClick(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleHover(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL			handleScrollWheel(S32 x, S32 y, S32 clicks);
-	/*virtual*/ BOOL			handleToolTip(S32 x, S32 y, MASK mask);
-	/*virtual*/ std::string		getName() const;
-	/*virtual*/ void			onMouseCaptureLost();
-	/*virtual*/ void			screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const;
-	/*virtual*/ void			localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const;
-	/*virtual*/ BOOL			hasMouseCapture();
-
-	S32							getStart() const 					{ return mStart; }
-	void						setStart(S32 start)					{ mStart = start; }
-	S32							getEnd() const						{ return mEnd; }
-	void						setEnd( S32 end )					{ mEnd = end; }
-
-protected:
-	S32				mStart;
-	S32				mEnd;
-};
-
-class LLNormalTextSegment : public LLTextSegment
-{
-public:
-	LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
-	LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
-	~LLNormalTextSegment();
-
-	/*virtual*/ bool				getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
-	/*virtual*/ S32					getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
-	/*virtual*/ S32					getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
-	/*virtual*/ F32					draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
-	/*virtual*/ bool				canEdit() const { return true; }
-	/*virtual*/ const LLColor4&		getColor() const					{ return mStyle->getColor(); }
-	/*virtual*/ LLStyleConstSP		getStyle() const					{ return mStyle; }
-	/*virtual*/ void 				setStyle(LLStyleConstSP style)	{ mStyle = style; }
-	/*virtual*/ void				setToken( LLKeywordToken* token )	{ mToken = token; }
-	/*virtual*/ LLKeywordToken*		getToken() const					{ return mToken; }
-	/*virtual*/ BOOL				getToolTip( std::string& msg ) const;
-	/*virtual*/ void				setToolTip(const std::string& tooltip);
-	/*virtual*/ void				dump() const;
-
-	/*virtual*/ BOOL				handleHover(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL				handleRightMouseDown(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL				handleMouseDown(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL				handleMouseUp(S32 x, S32 y, MASK mask);
-	/*virtual*/ BOOL				handleToolTip(S32 x, S32 y, MASK mask);
-
-protected:
-	F32					drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRect rect);
-
-protected:
-	class LLTextBase&	mEditor;
-	LLStyleConstSP		mStyle;
-	S32					mFontHeight;
-	LLKeywordToken* 	mToken;
-	std::string     	mTooltip;
-	boost::signals2::connection mImageLoadedConnection;
-};
-
-class LLIndexSegment : public LLTextSegment
-{
-public:
-	LLIndexSegment(S32 pos) : LLTextSegment(pos, pos) {}
-};
-
-class LLInlineViewSegment : public LLTextSegment
-{
-public:
-	struct Params : public LLInitParam::Block<Params>
-	{
-		Mandatory<LLView*>		view;
-		Optional<bool>			force_newline;
-		Optional<S32>			left_pad,
-								right_pad,
-								bottom_pad,
-								top_pad;
-	};
-
-	LLInlineViewSegment(const Params& p, S32 start, S32 end);
-	~LLInlineViewSegment();
-	/*virtual*/ bool		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
-	/*virtual*/ S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
-	/*virtual*/ void		updateLayout(const class LLTextBase& editor);
-	/*virtual*/ F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
-	/*virtual*/ bool		canEdit() const { return false; }
-	/*virtual*/ void		unlinkFromDocument(class LLTextBase* editor);
-	/*virtual*/ void		linkToDocument(class LLTextBase* editor);
-
-private:
-	S32 mLeftPad;
-	S32 mRightPad;
-	S32 mTopPad;
-	S32 mBottomPad;
-	LLView* mView;
-	bool	mForceNewLine;
-};
-
-class LLLineBreakTextSegment : public LLTextSegment
-{
-public:
-
-	LLLineBreakTextSegment(LLStyleConstSP style,S32 pos);
-	LLLineBreakTextSegment(S32 pos);
-	~LLLineBreakTextSegment();
-	bool		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
-	S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
-	F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
-
-private:
-	S32			mFontHeight;
-};
-
-class LLImageTextSegment : public LLTextSegment
-{
-public:
-	LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor);
-	~LLImageTextSegment();
-	bool		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
-	S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
-	F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
-
-private:
-	class LLTextBase&	mEditor;
-	LLStyleConstSP	mStyle;
-};
-
 #endif
diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp
index c5f3929fb12..56664071b79 100644
--- a/indra/llui/lltextutil.cpp
+++ b/indra/llui/lltextutil.cpp
@@ -34,7 +34,9 @@
 
 #include "lluicolor.h"
 #include "lltextbox.h"
+#include "llurlmatch.h"
 
+boost::function<bool(LLUrlMatch*,LLTextBase*)>	LLTextUtil::TextHelpers::iconCallbackCreationFunction = 0;
 
 void LLTextUtil::textboxSetHighlightedVal(LLTextBox *txtbox, const LLStyle::Params& normal_style, const std::string& text, const std::string& hl)
 {
@@ -76,4 +78,36 @@ const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str)
 	return formatted_phone_str;
 }
 
+bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base)
+{
+	if (match == 0 || text_base == 0)
+		return false;
+
+	if(match->getID() != LLUUID::null && TextHelpers::iconCallbackCreationFunction)
+	{
+		bool segment_created = TextHelpers::iconCallbackCreationFunction(match,text_base);
+		if(segment_created)
+			return true;
+	}
+
+	// output an optional icon before the Url
+	if (!match->getIcon().empty() )
+	{
+		LLUIImagePtr image = LLUI::getUIImage(match->getIcon());
+		if (image)
+		{
+			LLStyle::Params icon;
+			icon.image = image;
+			// Text will be replaced during rendering with the icon,
+			// but string cannot be empty or the segment won't be
+			// added (or drawn).
+			text_base->appendImageSegment(icon);
+
+			return true;
+		}
+	}
+	
+	return false;
+}
+
 // EOF
diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h
index 325c3c5b7c1..407880d1950 100644
--- a/indra/llui/lltextutil.h
+++ b/indra/llui/lltextutil.h
@@ -36,6 +36,8 @@
 #include "llstyle.h"
 
 class LLTextBox;
+class LLUrlMatch;
+class LLTextBase;
 
 namespace LLTextUtil
 {
@@ -67,6 +69,19 @@ namespace LLTextUtil
 	 * @return reference to string with formatted phone number
 	 */
 	const std::string& formatPhoneNumber(const std::string& phone_str);
+
+	bool processUrlMatch(LLUrlMatch* match,LLTextBase* text_base);
+
+	class TextHelpers
+	{
+
+		//we need this special callback since we need to create LLAvataIconCtrls while parsing
+		//avatar/group url but can't create LLAvataIconCtrl from LLUI
+		public:
+			static boost::function<bool(LLUrlMatch*,LLTextBase*)> iconCallbackCreationFunction;
+	};
+
+	
 }
 
 #endif // LL_LLTEXTUTIL_H
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index fd56a873459..e075699a6ec 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -326,6 +326,11 @@ void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id,
 	callObservers(id.asString(), first + " " + last);
 }
 
+LLUUID	LLUrlEntryAgent::getID(const std::string &string) const
+{
+	return LLUUID(getIDStringFromUrl(string));
+}
+
 std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
 {
 	// return a tooltip corresponding to the URL type instead of the generic one
@@ -434,6 +439,8 @@ LLUrlEntryGroup::LLUrlEntryGroup()
 	mColor = LLUIColorTable::instance().getColor("GroupLinkColor");
 }
 
+
+
 void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id,
 										  const std::string& first,
 										  const std::string& last,
@@ -443,6 +450,12 @@ void LLUrlEntryGroup::onGroupNameReceived(const LLUUID& id,
 	callObservers(id.asString(), first);
 }
 
+LLUUID	LLUrlEntryGroup::getID(const std::string &string) const
+{
+	return LLUUID(getIDStringFromUrl(string));
+}
+
+
 std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
 {
 	if (!gCacheName)
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 3c21fe8d614..7d718b67a93 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -172,6 +172,7 @@ class LLUrlEntryAgent : public LLUrlEntryBase
 	LLUrlEntryAgent();
 	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
 	/*virtual*/ std::string getTooltip(const std::string &string) const;
+	/*virtual*/ LLUUID	getID(const std::string &string) const;
 private:
 	void onAgentNameReceived(const LLUUID& id, const std::string& first,
 							 const std::string& last, BOOL is_group);
@@ -186,6 +187,7 @@ class LLUrlEntryGroup : public LLUrlEntryBase
 public:
 	LLUrlEntryGroup();
 	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+	/*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);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1ed63555b07..cc28f41fa1a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -81,6 +81,8 @@
 #include "llvoicechannel.h"
 #include "llvoavatarself.h"
 #include "llsidetray.h"
+#include "llurlmatch.h"
+#include "lltextutil.h"
 
 
 #include "llweb.h"
@@ -192,6 +194,7 @@
 #include "llviewerthrottle.h"
 #include "llparcel.h"
 #include "llavatariconctrl.h"
+#include "llgroupiconctrl.h"
 
 // Include for security api initialization
 #include "llsecapi.h"
@@ -351,6 +354,45 @@ static void ui_audio_callback(const LLUUID& uuid)
 	}
 }
 
+bool	create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base)
+{
+	if(!match || !base)
+		return false;
+
+	LLUUID match_id = match->getID();
+
+	LLIconCtrl* icon;
+
+	if(gAgent.isInGroup(match_id, TRUE))
+	{
+		LLGroupIconCtrl::Params icon_params = LLUICtrlFactory::instance().getDefaultParams<LLGroupIconCtrl>();
+		icon_params.group_id = match_id;
+		icon_params.rect = LLRect(0, 16, 16, 0);
+		icon_params.visible = true;
+		icon = LLUICtrlFactory::instance().createWidget<LLGroupIconCtrl>(icon_params);
+	}
+	else
+	{
+		LLAvatarIconCtrl::Params icon_params = LLUICtrlFactory::instance().getDefaultParams<LLAvatarIconCtrl>();
+		icon_params.avatar_id = match_id;
+		icon_params.rect = LLRect(0, 16, 16, 0);
+		icon_params.visible = true;
+		icon = LLUICtrlFactory::instance().createWidget<LLAvatarIconCtrl>(icon_params);
+	}
+
+	LLInlineViewSegment::Params params;
+	params.force_newline = false;
+	params.view = icon;
+	params.left_pad = 4;
+	params.right_pad = 4;
+	params.top_pad = 2;
+	params.bottom_pad = 2;
+
+	base->appendWidget(params," ",false);
+	
+	return true;
+}
+
 void request_initial_instant_messages()
 {
 	static BOOL requested = FALSE;
@@ -893,6 +935,7 @@ bool LLAppViewer::init()
 	}
 	
 	LLViewerMedia::initClass();
+	LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match;
 
 	//EXT-7013 - On windows for some locale (Japanese) standard 
 	//datetime formatting functions didn't support some parameters such as "weekday".
-- 
GitLab