From ada0f4fa221f2c7070fb02a2b7ff903bdde11c45 Mon Sep 17 00:00:00 2001
From: James Cook <james@lindenlab.com>
Date: Sat, 3 Oct 2009 23:40:28 +0000
Subject: [PATCH] Merge inspectors UI project, gooey-4, into viewer-2 trunk. 
 Added new tooltips to 3D avatars, 2D avatar names, and 3D objects.  Refactors
 tooltips and text boxes, line editors, and text editors.  Breaks
 LLExpandableTextBox, but a fix is coming.

Resolved conflicts in lltexteditor.cpp, llchatitemscontainerctrl.cpp, llchatmsgbox.cpp, llfloaterbuycurrency.cpp, llnearbychat.cpp, floater_buy_currency.xml, and ru/strings.xml

Merging revisions 134925-135157 of svn+ssh://svn.lindenlab.com/svn/linden/branches/gooey/gooey-4 into C:\source\viewer-2.0.0-3, respecting ancestry
---
 .../llui_libtest/llwidgetreg.cpp              |    2 +
 indra/llcommon/llpreprocessor.h               |    2 +
 indra/llcommon/llsafehandle.h                 |    1 +
 indra/llcommon/llsecondlifeurls.cpp           |    2 +-
 indra/llcommon/llstringtable.cpp              |   17 +
 indra/llcommon/llstringtable.h                |   18 +-
 indra/llcommon/llversionviewer.h              |    2 +-
 indra/llrender/llfontgl.cpp                   |    3 +-
 indra/llui/CMakeLists.txt                     |    4 +
 indra/llui/llbutton.cpp                       |    6 +-
 indra/llui/llbutton.h                         |    3 +
 indra/llui/llcheckboxctrl.cpp                 |    2 +-
 indra/llui/llcombobox.cpp                     |    6 +-
 indra/llui/llcombobox.h                       |    2 +-
 indra/llui/llconsole.cpp                      |    4 +-
 indra/llui/llconsole.h                        |    7 +-
 indra/llui/lldraghandle.cpp                   |    9 +-
 indra/llui/lldraghandle.h                     |    6 +-
 indra/llui/llfloater.cpp                      |    2 +-
 indra/llui/llfloater.h                        |    2 +-
 indra/llui/llfocusmgr.cpp                     |    2 +-
 indra/llui/lllayoutstack.cpp                  |    2 +
 indra/llui/lllayoutstack.h                    |    4 +-
 indra/llui/lllineeditor.cpp                   |   16 +-
 indra/llui/lllineeditor.h                     |    6 +-
 indra/llui/llmenubutton.cpp                   |  135 +
 indra/llui/llmenubutton.h                     |   68 +
 indra/llui/llmenugl.cpp                       |   96 +-
 indra/llui/llmenugl.h                         |   12 +-
 indra/llui/llmultisliderctrl.cpp              |    2 +-
 indra/llui/llpanel.cpp                        |    9 -
 indra/llui/llpanel.h                          |    6 +-
 indra/llui/llradiogroup.cpp                   |    2 +
 indra/llui/llradiogroup.h                     |   13 +-
 indra/llui/llscrollbar.cpp                    |   13 -
 indra/llui/llscrollbar.h                      |    3 -
 indra/llui/llscrollcontainer.cpp              |   50 +-
 indra/llui/llscrollcontainer.h                |    4 +-
 indra/llui/llscrolllistcell.cpp               |    7 +
 indra/llui/llscrolllistcell.h                 |   13 +-
 indra/llui/llscrolllistctrl.cpp               |   64 +-
 indra/llui/llscrolllistctrl.h                 |    6 +-
 indra/llui/llscrolllistitem.cpp               |    1 -
 indra/llui/llscrolllistitem.h                 |    2 -
 indra/llui/llsliderctrl.cpp                   |    2 +-
 indra/llui/llspinctrl.cpp                     |    2 +-
 indra/llui/llstatview.cpp                     |    2 +
 indra/llui/llstyle.cpp                        |    2 +-
 indra/llui/llstyle.h                          |   16 +-
 indra/llui/lltabcontainer.cpp                 |    8 +-
 indra/llui/lltabcontainer.h                   |    2 +-
 indra/llui/lltextbase.cpp                     | 2277 +++++++++++++++--
 indra/llui/lltextbase.h                       |  382 ++-
 indra/llui/lltextbox.cpp                      |  636 +----
 indra/llui/lltextbox.h                        |   95 +-
 indra/llui/lltexteditor.cpp                   | 2141 ++--------------
 indra/llui/lltexteditor.h                     |  293 +--
 indra/llui/lltextparser.cpp                   |    4 +-
 indra/llui/lltextparser.h                     |   12 +-
 indra/llui/lltoggleablemenu.cpp               |   82 +
 indra/llui/lltoggleablemenu.h                 |   65 +
 indra/llui/lltooltip.cpp                      |  334 +--
 indra/llui/lltooltip.h                        |   90 +-
 indra/llui/llui.cpp                           |   49 +-
 indra/llui/llui.h                             |    5 +-
 indra/llui/lluictrl.cpp                       |   30 +-
 indra/llui/lluictrl.h                         |   34 +-
 indra/llui/lluictrlfactory.cpp                |   14 +-
 indra/llui/llurlentry.cpp                     |   10 +-
 indra/llui/llurlentry.h                       |   20 +-
 indra/llui/llurlmatch.cpp                     |    5 +-
 indra/llui/llurlmatch.h                       |   20 +-
 indra/llui/llurlregistry.cpp                  |    8 +-
 indra/llui/llview.cpp                         |  377 ++-
 indra/llui/llview.h                           |   25 +-
 indra/llui/tests/llurlentry_test.cpp          |   13 +
 indra/llui/tests/llurlmatch_test.cpp          |   34 +-
 indra/llwindow/llmousehandler.h               |    7 +-
 indra/llwindow/llpreeditor.h                  |    2 +-
 indra/llwindow/llwindowmacosx.cpp             |   12 +-
 indra/llwindow/llwindowwin32.cpp              |    6 +-
 indra/llxml/llxmlnode.h                       |    2 +-
 indra/llxml/llxmlparser.h                     |    2 +-
 indra/llxuixml/llinitparam.h                  |   23 +-
 indra/llxuixml/lltrans.cpp                    |   65 +
 indra/llxuixml/lltrans.h                      |    6 +
 indra/newview/CMakeLists.txt                  |    9 +-
 indra/newview/app_settings/settings.xml       |   83 +-
 .../installers/windows/installer_template.nsi |    2 +-
 indra/newview/llappviewer.cpp                 |    7 +-
 indra/newview/llavataractions.cpp             |   29 +-
 indra/newview/llavataractions.h               |    6 +
 indra/newview/llavatarlistitem.cpp            |    2 +-
 indra/newview/llavatarpropertiesprocessor.cpp |  103 +-
 indra/newview/llavatarpropertiesprocessor.h   |    9 +-
 indra/newview/llchatitemscontainerctrl.cpp    |    4 +-
 indra/newview/llchatmsgbox.cpp                |  110 +-
 indra/newview/llchatmsgbox.h                  |    8 -
 indra/newview/llchiclet.cpp                   |    2 +-
 indra/newview/llcolorswatch.cpp               |    2 +-
 indra/newview/lldateutil.cpp                  |  140 +
 indra/newview/lldateutil.h                    |   49 +
 indra/newview/lldebugmessagebox.cpp           |    2 +-
 indra/newview/llexpandabletextbox.cpp         |   19 +-
 indra/newview/llexpandabletextbox.h           |   22 +-
 indra/newview/llfasttimerview.cpp             |    4 +-
 indra/newview/llfasttimerview.h               |    2 +-
 indra/newview/llfavoritesbar.cpp              |    4 +-
 indra/newview/llfloaterabout.cpp              |    9 +-
 indra/newview/llfloaterbuy.cpp                |    7 +
 indra/newview/llfloaterbuy.h                  |    1 +
 indra/newview/llfloaterbuyland.cpp            |   51 +-
 indra/newview/llfloaterchat.cpp               |   15 +-
 indra/newview/llfloaterfriends.cpp            |    4 +-
 indra/newview/llfloatergesture.cpp            |   16 +-
 indra/newview/llfloatergroups.cpp             |    4 +-
 indra/newview/llfloaterland.cpp               |   27 +-
 indra/newview/llfloaterregioninfo.cpp         |   35 +-
 indra/newview/llfloaterregioninfo.h           |   12 +-
 indra/newview/llfloaterreporter.cpp           |   32 +-
 indra/newview/llfloaterreporter.h             |    2 +
 indra/newview/llfloaterscriptdebug.cpp        |    3 +-
 indra/newview/llfloatersellland.cpp           |    5 +-
 indra/newview/llfloatertestinspectors.cpp     |    9 +-
 indra/newview/llfloatertestinspectors.h       |    1 +
 indra/newview/llfloatertools.cpp              |    2 +-
 indra/newview/llfloateruipreview.cpp          |   29 +-
 indra/newview/llfolderviewitem.cpp            |   14 +-
 indra/newview/llfolderviewitem.h              |    2 +-
 indra/newview/llgrouplist.cpp                 |   13 +-
 indra/newview/llimfloater.cpp                 |   11 +-
 indra/newview/llimpanel.cpp                   |   14 +-
 indra/newview/llinspectavatar.cpp             |  335 ++-
 indra/newview/llinspectavatar.h               |   61 +-
 indra/newview/llinspectobject.cpp             |  563 ++++
 indra/newview/llinspectobject.h               |   40 +
 indra/newview/lljoystickbutton.cpp            |   24 -
 indra/newview/lllistview.cpp                  |    2 +-
 indra/newview/lllocationinputctrl.cpp         |    4 +-
 indra/newview/lllocationinputctrl.h           |    2 +-
 indra/newview/llmenucommands.cpp              |    6 -
 indra/newview/llmenucommands.h                |    1 -
 indra/newview/llnamelistctrl.cpp              |   60 +-
 indra/newview/llnamelistctrl.h                |    7 +-
 indra/newview/llnearbychat.cpp                |   35 +-
 indra/newview/llnetmap.cpp                    |    6 +-
 indra/newview/llnetmap.h                      |    2 +-
 indra/newview/llpanelavatar.cpp               |    3 +-
 indra/newview/llpanelavatartag.cpp            |   24 +-
 indra/newview/llpanelblockedlist.h            |    1 +
 indra/newview/llpanelgroupgeneral.cpp         |    3 +
 indra/newview/llpanelgrouproles.cpp           |    1 +
 indra/newview/llpanellogin.cpp                |    4 +-
 indra/newview/llpanelpeople.cpp               |    2 +-
 indra/newview/llpanelpeople.h                 |    2 +-
 indra/newview/llpanelpermissions.cpp          |   32 -
 indra/newview/llpanelpermissions.h            |   15 +-
 indra/newview/llpanelpick.cpp                 |   20 +-
 indra/newview/llpanelprofile.cpp              |   13 +-
 indra/newview/llpreviewgesture.cpp            |    4 +-
 indra/newview/llpreviewnotecard.cpp           |    8 +-
 indra/newview/llprogressview.cpp              |    4 +-
 indra/newview/llselectmgr.cpp                 |   57 +-
 indra/newview/llselectmgr.h                   |   56 +-
 indra/newview/llslurl.cpp                     |    8 +
 indra/newview/llslurl.h                       |    3 +
 indra/newview/llstartup.cpp                   |   10 +-
 indra/newview/llstylemap.cpp                  |    7 +-
 indra/newview/lltexturectrl.cpp               |    2 +-
 indra/newview/lltoastalertpanel.cpp           |    3 +-
 indra/newview/lltoastnotifypanel.cpp          |    9 +-
 indra/newview/lltoastpanel.cpp                |    2 +-
 indra/newview/lltool.cpp                      |    2 +-
 indra/newview/lltool.h                        |    4 +-
 indra/newview/lltoolbar.cpp                   |    3 +
 indra/newview/lltooldraganddrop.cpp           |    4 +-
 indra/newview/lltooldraganddrop.h             |    2 +-
 indra/newview/lltoolpie.cpp                   |  272 +-
 indra/newview/lltoolpie.h                     |    5 +-
 indra/newview/lltoolpipette.cpp               |    4 +-
 indra/newview/lltoolpipette.h                 |    2 +-
 indra/newview/lluploaddialog.cpp              |    2 +-
 indra/newview/llviewchildren.cpp              |   11 -
 indra/newview/llviewchildren.h                |    2 -
 indra/newview/llviewerfloaterreg.cpp          |    5 +-
 indra/newview/llviewerjoystick.cpp            |    2 +-
 indra/newview/llviewerjoystick.h              |    3 +-
 indra/newview/llviewermedia.h                 |    5 +-
 indra/newview/llviewermenu.cpp                |  533 ++--
 indra/newview/llviewermenu.h                  |   34 +-
 indra/newview/llviewermessage.cpp             |   43 +-
 indra/newview/llviewerparcelmgr.h             |    3 +
 indra/newview/llviewertexteditor.cpp          |   95 +-
 indra/newview/llviewertexteditor.h            |    6 +-
 indra/newview/llviewerwindow.cpp              |   33 +-
 indra/newview/llworldmapview.cpp              |    5 +-
 indra/newview/llworldmapview.h                |    2 +-
 indra/newview/skins/default/colors.xml        |    4 +-
 .../default/textures/icons/Info_Small.png     |  Bin 0 -> 371 bytes
 .../skins/default/textures/textures.xml       |    1 +
 .../skins/default/xui/en/floater_about.xml    |    3 +-
 .../default/xui/en/floater_about_land.xml     |    3 -
 .../skins/default/xui/en/floater_buy_land.xml |    6 +-
 .../default/xui/en/floater_im_session.xml     |    2 +
 .../default/xui/en/floater_incoming_call.xml  |    2 +-
 .../skins/default/xui/en/floater_inspect.xml  |    2 +-
 .../skins/default/xui/en/floater_map.xml      |    7 -
 .../default/xui/en/floater_nearby_chat.xml    |    1 +
 .../xui/en/floater_preview_notecard.xml       |    1 +
 .../default/xui/en/floater_report_abuse.xml   |   10 +
 .../xui/en/floater_script_debug_panel.xml     |    1 +
 .../skins/default/xui/en/floater_telehub.xml  |    1 -
 .../xui/en/floater_test_inspectors.xml        |   31 +-
 .../default/xui/en/floater_test_textbox.xml   |    1 -
 .../default/xui/en/floater_test_widgets.xml   |   57 +-
 .../default/xui/en/floater_ui_preview.xml     |    2 +-
 .../skins/default/xui/en/inspect_avatar.xml   |  216 +-
 .../skins/default/xui/en/inspect_object.xml   |  162 ++
 .../xui/en/menu_inspect_avatar_gear.xml       |  114 +
 .../xui/en/menu_inspect_object_gear.xml       |  129 +
 .../skins/default/xui/en/notifications.xml    |    4 +-
 .../default/xui/en/panel_audio_device.xml     |    2 +-
 .../default/xui/en/panel_avatar_list_item.xml |    1 -
 .../default/xui/en/panel_edit_profile.xml     |    7 +-
 .../default/xui/en/panel_group_land_money.xml |    1 -
 .../skins/default/xui/en/panel_login.xml      |    2 +-
 .../skins/default/xui/en/panel_profile.xml    |    4 +
 .../skins/default/xui/en/panel_progress.xml   |    8 +-
 .../skins/default/xui/en/panel_script_ed.xml  |    2 -
 .../skins/default/xui/en/panel_side_tray.xml  |    4 -
 .../skins/default/xui/en/panel_status_bar.xml |    7 +-
 .../skins/default/xui/en/panel_world_map.xml  |    8 -
 .../newview/skins/default/xui/en/strings.xml  |   44 +-
 .../default/xui/en/widgets/line_editor.xml    |    7 +-
 .../xui/en/widgets/simple_text_editor.xml     |   10 +-
 .../skins/default/xui/en/widgets/text.xml     |   14 +-
 .../default/xui/en/widgets/text_editor.xml    |    2 +-
 .../skins/default/xui/en/widgets/textbase.xml |    4 +
 .../skins/default/xui/nl/floater_telehub.xml  |    2 +-
 indra/newview/tests/lldateutil_test.cpp       |  159 ++
 indra/test/test.cpp                           |   17 +-
 241 files changed, 6963 insertions(+), 5411 deletions(-)
 create mode 100644 indra/llui/llmenubutton.cpp
 create mode 100644 indra/llui/llmenubutton.h
 create mode 100644 indra/llui/lltoggleablemenu.cpp
 create mode 100644 indra/llui/lltoggleablemenu.h
 create mode 100644 indra/newview/lldateutil.cpp
 create mode 100644 indra/newview/lldateutil.h
 create mode 100644 indra/newview/llinspectobject.cpp
 create mode 100644 indra/newview/llinspectobject.h
 create mode 100644 indra/newview/skins/default/textures/icons/Info_Small.png
 create mode 100644 indra/newview/skins/default/xui/en/inspect_object.xml
 create mode 100644 indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
 create mode 100644 indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml
 create mode 100644 indra/newview/skins/default/xui/en/widgets/textbase.xml
 create mode 100644 indra/newview/tests/lldateutil_test.cpp

diff --git a/indra/integration_tests/llui_libtest/llwidgetreg.cpp b/indra/integration_tests/llui_libtest/llwidgetreg.cpp
index 5a97f2aefd1..316fd810c04 100644
--- a/indra/integration_tests/llui_libtest/llwidgetreg.cpp
+++ b/indra/integration_tests/llui_libtest/llwidgetreg.cpp
@@ -37,6 +37,7 @@
 #include "llcombobox.h"
 #include "llcontainerview.h"
 #include "lliconctrl.h"
+#include "llmenubutton.h"
 #include "llmenugl.h"
 #include "llmultislider.h"
 #include "llmultisliderctrl.h"
@@ -64,6 +65,7 @@ void LLWidgetReg::initClass(bool register_widgets)
 	if (register_widgets)
 	{
 		LLDefaultChildRegistry::Register<LLButton> button("button");
+		LLDefaultChildRegistry::Register<LLMenuButton> menu_button("menu_button");
 		LLDefaultChildRegistry::Register<LLCheckBoxCtrl> check_box("check_box");
 		LLDefaultChildRegistry::Register<LLComboBox> combo_box("combo_box");
 		LLDefaultChildRegistry::Register<LLFilterEditor> filter_editor("filter_editor");
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index 4401be1679b..bb598a2be1b 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -117,7 +117,9 @@ using snprintf_hack::snprintf;
 #if defined(LL_WINDOWS)
 #define BOOST_REGEX_NO_LIB 1
 #define CURL_STATICLIB 1
+#ifndef XML_STATIC
 #define XML_STATIC
+#endif
 #endif	//	LL_WINDOWS
 
 
diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h
index 1f7c682fd1b..5862f1a341b 100644
--- a/indra/llcommon/llsafehandle.h
+++ b/indra/llcommon/llsafehandle.h
@@ -77,6 +77,7 @@ class LLSafeHandle
 	Type*	operator->()						{ return nonNull(mPointer); }
 
 	Type*	get() const							{ return mPointer; }
+	void	clear()								{ assign(NULL); }
 	// we disallow these operations as they expose our null objects to direct manipulation
 	// and bypass the reference counting semantics
 	//const Type&	operator*() const			{ return *nonNull(mPointer); }
diff --git a/indra/llcommon/llsecondlifeurls.cpp b/indra/llcommon/llsecondlifeurls.cpp
index 6323d9d36ba..9e67872ffd4 100644
--- a/indra/llcommon/llsecondlifeurls.cpp
+++ b/indra/llcommon/llsecondlifeurls.cpp
@@ -34,7 +34,7 @@
 #include "llsecondlifeurls.h"
 /*
 const std::string CREATE_ACCOUNT_URL ( 
-	"http://secondlife.com/registration/");
+	"http://join.secondlife.com/");
 
 const std::string MANAGE_ACCOUNT ( 
 	"http://secondlife.com/account/");  // *TODO: NOT USED
diff --git a/indra/llcommon/llstringtable.cpp b/indra/llcommon/llstringtable.cpp
index 27f9036b8bb..2f3a994d8ff 100644
--- a/indra/llcommon/llstringtable.cpp
+++ b/indra/llcommon/llstringtable.cpp
@@ -38,6 +38,23 @@
 
 LLStringTable gStringTable(32768);
 
+LLStringTableEntry::LLStringTableEntry(const char *str)
+: mString(NULL), mCount(1)
+{
+	// Copy string
+	U32 length = (U32)strlen(str) + 1;	 /*Flawfinder: ignore*/
+	length = llmin(length, MAX_STRINGS_LENGTH);
+	mString = new char[length];
+	strncpy(mString, str, length);	 /*Flawfinder: ignore*/
+	mString[length - 1] = 0;
+}
+
+LLStringTableEntry::~LLStringTableEntry()
+{
+	delete [] mString;
+	mCount = 0;
+}
+
 LLStringTable::LLStringTable(int tablesize)
 : mUniqueEntries(0)
 {
diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h
index 4492063275e..888361b0b9a 100644
--- a/indra/llcommon/llstringtable.h
+++ b/indra/llcommon/llstringtable.h
@@ -59,21 +59,9 @@ const U32 MAX_STRINGS_LENGTH = 256;
 class LLStringTableEntry
 {
 public:
-	LLStringTableEntry(const char *str)
-		: mString(NULL), mCount(1)
-	{
-		// Copy string
-		U32 length = (U32)strlen(str) + 1;	 /*Flawfinder: ignore*/
-		length = llmin(length, MAX_STRINGS_LENGTH);
-		mString = new char[length];
-		strncpy(mString, str, length);	 /*Flawfinder: ignore*/
-		mString[length - 1] = 0;
-	}
-	~LLStringTableEntry()
-	{
-		delete [] mString;
-		mCount = 0;
-	}
+	LLStringTableEntry(const char *str);
+	~LLStringTableEntry();
+
 	void incCount()		{ mCount++; }
 	BOOL decCount()		{ return --mCount; }
 
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 45810a101d6..2c3e9c73337 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -38,6 +38,6 @@ const S32 LL_VERSION_MINOR = 0;
 const S32 LL_VERSION_PATCH = 0;
 const S32 LL_VERSION_BUILD = 0;
 
-const char * const LL_CHANNEL = "Second Life 2009";
+const char * const LL_CHANNEL = "Second Life Developer";
 
 #endif
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index d76b23248d6..8f943182b8b 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -484,7 +484,8 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
 	S32 start_of_last_word = 0;
 	BOOL in_word = FALSE;
 
-	F32 scaled_max_pixels =	(F32)llceil(max_pixels * sScaleX);
+	// avoid S32 overflow when max_pixels == S32_MAX by staying in floating point
+	F32 scaled_max_pixels =	ceil(max_pixels * sScaleX);
 
 	S32 i;
 	for (i=0; (i < max_chars); i++)
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 0a284f0088b..d9169f57f91 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -51,6 +51,7 @@ set(llui_SOURCE_FILES
     lllayoutstack.cpp
     lllineeditor.cpp
     lllocalcliprect.cpp
+    llmenubutton.cpp
     llmenugl.cpp
     llmodaldialog.cpp
     llmultifloater.cpp 
@@ -87,6 +88,7 @@ set(llui_SOURCE_FILES
     lltextparser.cpp
     lltransientfloatermgr.cpp
     lltransutil.cpp
+    lltoggleablemenu.cpp
     lltooltip.cpp
     llui.cpp
     lluicolortable.cpp
@@ -137,6 +139,7 @@ set(llui_HEADER_FILES
     lllazyvalue.h
     lllineeditor.h
     lllocalcliprect.h
+    llmenubutton.h
     llmenugl.h
     llmodaldialog.h
     llmultifloater.h 
@@ -171,6 +174,7 @@ set(llui_HEADER_FILES
     lltextbox.h
     lltexteditor.h
     lltextparser.h
+    lltoggleablemenu.h
     lltooltip.h
     lltransientfloatermgr.h
     lltransutil.h
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index b9613b502c5..219c2ee2548 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -145,7 +145,8 @@ LLButton::LLButton(const LLButton::Params& p)
 	mRightHPad(p.pad_right),
 	mHoverGlowStrength(p.hover_glow_amount),
 	mCommitOnReturn(p.commit_on_return),
-	mFadeWhenDisabled(FALSE)
+	mFadeWhenDisabled(FALSE),
+	mForcePressedState(FALSE)
 {
 	static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
 	static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>());
@@ -536,7 +537,8 @@ void LLButton::draw()
 	bool enabled = isInEnabledChain();
 
 	bool pressed = pressed_by_keyboard 
-					|| (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y));
+					|| (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y))
+					|| mForcePressedState;
 	bool selected = getToggleState();
 	
 	bool use_glow_effect = FALSE;
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 04716d605b9..73ba457d348 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -233,6 +233,8 @@ class LLButton
 	static void		toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname);
 	static void		setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname);
 	static void		showHelp(LLUICtrl* ctrl, const LLSD& sdname);
+
+	void		setForcePressedState(BOOL b) { mForcePressedState = b; }
 	
 protected:
 	const LLPointer<LLUIImage>&	getImageUnselected() const	{ return mImageUnselected; }
@@ -310,6 +312,7 @@ class LLButton
 	BOOL						mNeedsHighlight;
 	BOOL						mCommitOnReturn;
 	BOOL						mFadeWhenDisabled;
+	BOOL						mForcePressedState;
 
 	LLFrameTimer				mFlashingTimer;
 };
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 455b17ffc71..7f0f9751dbb 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -97,7 +97,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
 
 	LLTextBox::Params tbparams = p.label_text;
 	tbparams.rect(label_rect);
-	tbparams.text(local_label);
+	tbparams.initial_value(local_label);
 	if (p.font.isProvided())
 	{
 		tbparams.font(p.font);
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 0170ac0c6ac..36e309d639e 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -714,11 +714,11 @@ void LLComboBox::onItemSelected(const LLSD& data)
 	}
 }
 
-BOOL LLComboBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+BOOL LLComboBox::handleToolTip(S32 x, S32 y, MASK mask)
 {
     std::string tool_tip;
 
-	if(LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen))
+	if(LLUICtrl::handleToolTip(x, y, mask))
 	{
 		return TRUE;
 	}
@@ -731,7 +731,7 @@ BOOL LLComboBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_re
 	
 	if( !tool_tip.empty() )
 	{
-		LLToolTipMgr::instance().show(LLToolTipParams()
+		LLToolTipMgr::instance().show(LLToolTip::Params()
 			.message(tool_tip)
 			.sticky_rect(calcScreenRect()));
 	}
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 68cbfeeeeb2..6285ca5170b 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -113,7 +113,7 @@ class LLComboBox
 	// LLView interface
 	virtual void	onFocusLost();
 
-	virtual BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect);
+	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleKeyHere(KEY key, MASK mask);
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 1e8b8a5537c..285ce82d2d6 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -61,7 +61,7 @@ const F32 FADE_DURATION = 2.f;
 const S32 MIN_CONSOLE_WIDTH = 200;
  
 LLConsole::LLConsole(const LLConsole::Params& p) 
-:	LLView(p),
+:	LLUICtrl(p),
 	LLFixedBuffer(p.max_lines),
 	mLinePersistTime(p.persist_time), // seconds
 	mFont(p.font)
@@ -94,7 +94,7 @@ void LLConsole::reshape(S32 width, S32 height, BOOL called_from_parent)
 	mConsoleWidth = new_width;
 	mConsoleHeight= new_height;
 	
-	LLView::reshape(new_width, new_height, called_from_parent);
+	LLUICtrl::reshape(new_width, new_height, called_from_parent);
 	
 	for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++)
 	{
diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h
index 56e1614948b..5800a82922a 100644
--- a/indra/llui/llconsole.h
+++ b/indra/llui/llconsole.h
@@ -34,14 +34,13 @@
 #define LL_LLCONSOLE_H
 
 #include "llfixedbuffer.h"
-#include "llview.h"
+#include "lluictrl.h"
 #include "v4color.h"
 #include <deque>
 
-class LLFontGL;
 class LLSD;
 
-class LLConsole : public LLFixedBuffer, public LLView
+class LLConsole : public LLFixedBuffer, public LLUICtrl
 {
 public:
 	typedef enum e_font_size
@@ -51,7 +50,7 @@ class LLConsole : public LLFixedBuffer, public LLView
 		BIG = 1
 	} EFontSize;
 
-	struct Params : public LLInitParam::Block<Params, LLView::Params>
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
 		Optional<U32>	max_lines;
 		Optional<F32>	persist_time;
diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp
index 6e8e37ded37..8eccd709ce6 100644
--- a/indra/llui/lldraghandle.cpp
+++ b/indra/llui/lldraghandle.cpp
@@ -108,7 +108,7 @@ void LLDragHandleTop::setTitle(const std::string& title)
 		LLTextBox::Params params;
 		params.name("Drag Handle Title");
 		params.rect(getRect());
-		params.text(trimmed_title);
+		params.initial_value(trimmed_title);
 		params.font(font);
 		params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT);
 		params.font_shadow(LLFontGL::DROP_SHADOW_SOFT);
@@ -120,7 +120,7 @@ void LLDragHandleTop::setTitle(const std::string& title)
 }
 
 
-const std::string& LLDragHandleTop::getTitle() const
+std::string LLDragHandleTop::getTitle() const
 {
 	return mTitleBox == NULL ? LLStringUtil::null : mTitleBox->getText();
 }
@@ -138,7 +138,7 @@ void LLDragHandleLeft::setTitle(const std::string& )
 }
 
 
-const std::string& LLDragHandleLeft::getTitle() const
+std::string LLDragHandleLeft::getTitle() const
 {
 	return LLStringUtil::null;
 }
@@ -256,7 +256,8 @@ void LLDragHandleTop::reshapeTitleBox()
 		getRect().getWidth() - LEFT_PAD - RIGHT_PAD,
 		title_height);
 
-	mTitleBox->setRect( title_rect );
+	// calls reshape on mTitleBox
+	mTitleBox->setShape( title_rect );
 }
 
 void LLDragHandleTop::reshape(S32 width, S32 height, BOOL called_from_parent)
diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h
index 88ec1d21f81..dc5410787b5 100644
--- a/indra/llui/lldraghandle.h
+++ b/indra/llui/lldraghandle.h
@@ -74,7 +74,7 @@ class LLDragHandle : public LLView
 	void			setTitleVisible(BOOL visible);
 
 	virtual void	setTitle( const std::string& title ) = 0;
-	virtual const std::string&	getTitle() const = 0;
+	virtual std::string	getTitle() const = 0;
 
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
@@ -112,7 +112,7 @@ class LLDragHandleTop
 	friend class LLUICtrlFactory;
 public:
 	virtual void	setTitle( const std::string& title );
-	virtual const std::string& getTitle() const;
+	virtual std::string getTitle() const;
 	virtual void	draw();
 	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 
@@ -130,7 +130,7 @@ class LLDragHandleLeft
 	friend class LLUICtrlFactory;
 public:
 	virtual void	setTitle( const std::string& title );
-	virtual const std::string& getTitle() const;
+	virtual std::string getTitle() const;
 	virtual void	draw();
 	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index ff0288a32f0..564e4d748f4 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -785,7 +785,7 @@ void LLFloater::applyTitle()
 	}
 }
 
-const std::string& LLFloater::getCurrentTitle() const
+std::string LLFloater::getCurrentTitle() const
 {
 	return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
 }
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 2a31ba4e8f8..1dc5177f810 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -171,7 +171,7 @@ friend class LLMultiFloater;
 	LLMultiFloater* getHost();
 
 	void			applyTitle();
-	const std::string&	getCurrentTitle() const;
+	std::string		getCurrentTitle() const;
 	void			setTitle( const std::string& title);
 	std::string		getTitle() const;
 	void			setShortTitle( const std::string& short_title );
diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp
index 279cbaa9235..00a80478cf4 100644
--- a/indra/llui/llfocusmgr.cpp
+++ b/indra/llui/llfocusmgr.cpp
@@ -274,7 +274,7 @@ BOOL LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const
 // Returns TRUE is parent or any descedent of parent is the mouse captor.
 BOOL LLFocusMgr::childHasMouseCapture( const LLView* parent ) const
 {
-	if( mMouseCaptor && mMouseCaptor->isView() )
+	if( mMouseCaptor && dynamic_cast<LLView*>(mMouseCaptor) != NULL )
 	{
 		LLView* captor_view = (LLView*)mMouseCaptor;
 		while( captor_view )
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 2d582c05687..5eade72b61c 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -35,7 +35,9 @@
 #include "linden_common.h"
 
 #include "lllayoutstack.h"
+
 #include "lllocalcliprect.h"
+#include "llpanel.h"
 #include "llresizebar.h"
 #include "llcriticaldamp.h"
 
diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h
index 9459b9990cd..49cbe7270fe 100644
--- a/indra/llui/lllayoutstack.h
+++ b/indra/llui/lllayoutstack.h
@@ -34,7 +34,9 @@
 #ifndef LL_LLLAYOUTSTACK_H
 #define LL_LLLAYOUTSTACK_H
 
-#include "llpanel.h"
+#include "llview.h"
+
+class LLPanel;
 
 class LLLayoutStack : public LLView
 {
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index ede67ad17d3..693ea5bb452 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -107,9 +107,6 @@ LLLineEditor::Params::Params()
 	highlight_color("highlight_color"),
 	preedit_bg_color("preedit_bg_color"),
 	border(""),
-	is_unicode("is_unicode"),
-	drop_shadow_visible("drop_shadow_visible"),
-	border_drop_shadow_visible("border_drop_shadow_visible"),
 	bg_visible("bg_visible"),
 	text_pad_left("text_pad_left"),
 	text_pad_right("text_pad_right"),
@@ -544,18 +541,13 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 	{
 		return TRUE;
 	}
-	if (mSelectAllonFocusReceived
-		&& gFocusMgr.getKeyboardFocus() != this)
-	{
-		setFocus( TRUE );
-	}
-	else
+	
+	if (!mSelectAllonFocusReceived
+		|| gFocusMgr.getKeyboardFocus() == this)
 	{
 		mLastSelectionStart = -1;
 		mLastSelectionStart = -1;
 
-		setFocus( TRUE );
-
 		if (mask & MASK_SHIFT)
 		{
 			// Handle selection extension
@@ -621,6 +613,8 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 		gFocusMgr.setMouseCapture( this );
 	}
 
+	setFocus(TRUE);
+
 	// delay cursor flashing
 	mKeystrokeTimer.reset();
 	
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 339aad30fbe..48d68b9935e 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -105,10 +105,7 @@ class LLLineEditor
 		Optional<S32>					text_pad_left,
 										text_pad_right;
 
-		Ignored							is_unicode,
-										drop_shadow_visible,	
-										border_drop_shadow_visible,
-										bg_visible;
+		Ignored							bg_visible;
 		
 		Params();
 	};
@@ -280,6 +277,7 @@ class LLLineEditor
 	virtual void	getPreeditRange(S32 *position, S32 *length) const;
 	virtual BOOL	getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const;
 	virtual S32		getPreeditFontSize() const;
+	virtual LLWString getPreeditString() const { return getWText(); }
 
 protected:
 	LLUIString		mText;					// The string being edited.
diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
new file mode 100644
index 00000000000..2bb6749c833
--- /dev/null
+++ b/indra/llui/llmenubutton.cpp
@@ -0,0 +1,135 @@
+/** 
+ * @file llbutton.cpp
+ * @brief LLButton base class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llmenubutton.h"
+
+// Linden library includes
+#include "llmenugl.h"
+#include "llstring.h"
+#include "v4color.h"
+
+static LLDefaultChildRegistry::Register<LLMenuButton> r("menu_button");
+
+
+LLMenuButton::Params::Params()
+:	menu_filename("menu_filename")
+{
+}
+
+
+LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
+:	LLButton(p),
+	mMenu(NULL),
+	mMenuVisibleLastFrame(false)
+{
+	std::string menu_filename = p.menu_filename;
+
+	if (!menu_filename.empty())
+	{
+		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+		if (!mMenu)
+		{
+			llwarns << "Error loading menu_button menu" << llendl;
+		}
+	}
+}
+
+void LLMenuButton::toggleMenu()
+{
+    if(!mMenu)
+		return;
+
+	if (mMenu->getVisible() || mMenuVisibleLastFrame)
+	{
+		mMenu->setVisible(FALSE);
+	}
+	else
+	{
+	    LLRect rect = getRect();
+		//mMenu->needsArrange(); //so it recalculates the visible elements
+		LLMenuGL::showPopup(getParent(), mMenu, rect.mLeft, rect.mBottom);
+	}
+}
+
+
+BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
+{
+	if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
+	{
+		toggleMenu();
+		return TRUE;
+	}
+
+	if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
+	{
+		mMenu->setVisible(FALSE);
+		return TRUE;
+	}
+	
+	return FALSE;
+}
+
+BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	if (hasTabStop() && !getIsChrome())
+	{
+		setFocus(TRUE);
+	}
+
+	toggleMenu();
+	
+	if (getSoundFlags() & MOUSE_DOWN)
+	{
+		make_ui_sound("UISndClick");
+	}
+
+	return TRUE;
+}
+
+void LLMenuButton::draw()
+{
+	//we save this off so next frame when we try to close it by 
+	//button click, and it hides menus before we get to it, we know
+	mMenuVisibleLastFrame = mMenu && mMenu->getVisible();
+	
+	if (mMenuVisibleLastFrame)
+	{
+		setForcePressedState(TRUE);
+	}
+
+	LLButton::draw();
+
+	setForcePressedState(FALSE);
+}
+
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
new file mode 100644
index 00000000000..94b0e4355de
--- /dev/null
+++ b/indra/llui/llmenubutton.h
@@ -0,0 +1,68 @@
+/** 
+ * @file llbutton.h
+ * @brief Header for buttons
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLMENUBUTTON_H
+#define LL_LLMENUBUTTON_H
+
+#include "llbutton.h"
+
+class LLMenuGL;
+
+class LLMenuButton
+: public LLButton
+{
+public:
+	struct Params 
+	:	public LLInitParam::Block<Params, LLButton::Params>
+	{
+		// filename for it's toggleable menu
+		Optional<std::string>	menu_filename;
+	
+		Params();
+	};	
+	
+	void toggleMenu();
+	/*virtual*/ void draw();
+	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
+
+protected:
+	friend class LLUICtrlFactory;
+	LLMenuButton(const Params&);
+
+private:
+	LLMenuGL*	mMenu;
+	bool mMenuVisibleLastFrame;
+};
+
+
+#endif  // LL_LLMENUBUTTON_H
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index f2d147ac392..14bee0465c2 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -781,6 +781,10 @@ LLMenuItemCallGL::LLMenuItemCallGL(const LLMenuItemCallGL::Params& p)
 
 void LLMenuItemCallGL::initFromParams(const Params& p)
 {
+	if (p.on_visible.isProvided())
+	{
+		initVisibleCallback(p.on_visible, mVisibleSignal);
+	}
 	if (p.on_enable.isProvided())
 	{
 		initEnableCallback(p.on_enable, mEnableSignal);
@@ -823,9 +827,19 @@ void LLMenuItemCallGL::updateEnabled( void )
 	}
 }
 
+void LLMenuItemCallGL::updateVisible( void )
+{
+	if (mVisibleSignal.num_slots() > 0)
+	{
+		bool visible = mVisibleSignal(this, LLSD());
+		setVisible(visible);
+	}
+}
+
 void LLMenuItemCallGL::buildDrawLabel( void )
 {
 	updateEnabled();
+	updateVisible();
 	LLMenuItemGL::buildDrawLabel();
 }
 
@@ -1224,23 +1238,7 @@ void LLMenuItemBranchGL::openMenu()
 			rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS);
 		}
 		branch->setRect( rect );
-		S32 x = 0;
-		S32 y = 0;
-		branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() ); 
-		S32 delta_x = 0;
-		S32 delta_y = 0;
-		if( y < menu_region_rect.mBottom )
-		{
-			delta_y = menu_region_rect.mBottom - y;
-		}
-
-		S32 menu_region_width = menu_region_rect.getWidth();
-		if( x - menu_region_rect.mLeft > menu_region_width - rect.getWidth() )
-		{
-			// move sub-menu over to left side
-			delta_x = llmax(-x, (-1 * (rect.getWidth() + getRect().getWidth())));
-		}
-		branch->translate( delta_x, delta_y );
+		branch->translateIntoRectWithExclusion( menu_region_rect, getMenu()->getRect(), FALSE );
 		branch->setVisible( TRUE );
 		branch->getParent()->sendChildToFront(branch);
 
@@ -1935,6 +1933,9 @@ void LLMenuGL::arrange( void )
 			item_list_t::iterator item_iter;
 			for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
 			{
+				// do first so LLMenuGLItemCall can call on_visible to determine if visible
+				(*item_iter)->buildDrawLabel();
+
 				if ((*item_iter)->getVisible())
 				{
 					if (!getTornOff() 
@@ -1976,6 +1977,9 @@ void LLMenuGL::arrange( void )
 
 			for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
 			{
+				// do first so LLMenuGLItemCall can call on_visible to determine if visible
+				(*item_iter)->buildDrawLabel();
+		
 				if ((*item_iter)->getVisible())
 				{
 					if (!getTornOff() 
@@ -2162,7 +2166,7 @@ void LLMenuGL::arrange( void )
 
 		item_list_t::iterator item_iter;
 		for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
-		{
+		{		
 			if ((*item_iter)->getVisible())
 			{
 				if (mScrollable)
@@ -2193,7 +2197,6 @@ void LLMenuGL::arrange( void )
 					}
 				}
 				(*item_iter)->setRect( rect );
-				(*item_iter)->buildDrawLabel();
 			}
 		}
 	}
@@ -2936,11 +2939,27 @@ void hide_top_view( LLView* view )
 // static
 void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
 {
+	const S32 CURSOR_HEIGHT = 22;		// Approximate "normal" cursor size
+	const S32 CURSOR_WIDTH = 12;
+
 	// Save click point for detecting cursor moves before mouse-up.
 	// Must be in local coords to compare with mouseUp events.
 	// If the mouse doesn't move, the menu will stay open ala the Mac.
 	// See also LLContextMenu::show()
 	S32 mouse_x, mouse_y;
+
+	// Resetting scrolling position
+	if (menu->isScrollable())
+	{
+		menu->mFirstVisibleItem = NULL;
+	}
+
+	menu->setVisible( TRUE );
+
+	// Fix menu rect if needed.
+	menu->needsArrange();
+	menu->arrangeAndClear();
+
 	LLUI::getMousePositionLocal(menu->getParent(), &mouse_x, &mouse_y);
 	LLMenuHolderGL::sContextMenuSpawnPos.set(mouse_x,mouse_y);
 
@@ -2948,7 +2967,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
 
 	const S32 HPAD = 2;
 	LLRect rect = menu->getRect();
-	//LLView* cur_view = spawning_view;
 	S32 left = x + HPAD;
 	S32 top = y;
 	spawning_view->localPointToOtherView(left, top, &left, &top, menu->getParent());
@@ -2956,37 +2974,19 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
 							rect.getWidth(), rect.getHeight() );
 	menu->setRect( rect );
 
-	// Resetting scrolling position
-	if (menu->isScrollable())
-	{
-		menu->mFirstVisibleItem = NULL;
-		menu->needsArrange();
-	}
-	menu->arrangeAndClear(); // Fix menu rect if needed.
-	rect = menu->getRect();
 
 	// Adjust context menu to fit onscreen
-	S32 bottom;
-	left = rect.mLeft;
-	bottom = rect.mBottom;
-	S32 delta_x = 0;
-	S32 delta_y = 0;
-	if( bottom < menu_region_rect.mBottom )
-	{
-		// At this point, we need to move the context menu to the
-		// other side of the mouse.
-		delta_y = (rect.getHeight() + 2 * HPAD);
-	}
-
-	if( left > menu_region_rect.mRight - rect.getWidth() )
-	{
-		// At this point, we need to move the context menu to the
-		// other side of the mouse.
-		delta_x = -(rect.getWidth() + 2 * HPAD);
-	}
-	menu->translate( delta_x, delta_y );
-	menu->setVisible( TRUE );
+	LLRect mouse_rect;
+	const S32 MOUSE_CURSOR_PADDING = 5;
+	mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, 
+		mouse_y + MOUSE_CURSOR_PADDING, 
+		CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, 
+		CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2);
+	menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect, FALSE );
 	menu->getParent()->sendChildToFront(menu);
+
+
+
 }
 
 ///============================================================================
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 8309fedf7f4..48887ec3520 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -268,15 +268,18 @@ class LLMenuItemCallGL : public LLMenuItemGL
 	{
 		Optional<EnableCallbackParam > on_enable;
 		Optional<CommitCallbackParam > on_click;
+		Optional<VisibleCallbackParam > on_visible;
 		Params()
 			: on_enable("on_enable"),
-			  on_click("on_click")
+			  on_click("on_click"),
+			  on_visible("on_visible")
 		{}
 	};
 protected:
 	LLMenuItemCallGL(const Params&);
 	friend class LLUICtrlFactory;
 	void updateEnabled( void );
+	void updateVisible( void );
 
 public:
 	void initFromParams(const Params& p);
@@ -300,10 +303,15 @@ class LLMenuItemCallGL : public LLMenuItemGL
 	{
 		return mEnableSignal.connect(cb);
 	}
-
+	
+	boost::signals2::connection setVisibleCallback( const visible_signal_t::slot_type& cb )
+	{
+		return mVisibleSignal.connect(cb);
+	}
 	
 private:
 	enable_signal_t mEnableSignal;
+	visible_signal_t mVisibleSignal;
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index 0fbb7ced54f..a9f462173dd 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -98,7 +98,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
 		LLTextBox::Params params;
 		params.name("MultiSliderCtrl Label");
 		params.rect(label_rect);
-		params.text(p.label);
+		params.initial_value(p.label());
 		params.font(p.font);
 		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
 		addChild(mLabelBox);
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index b9bbb4db22f..1695aee2b87 100644
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -819,15 +819,6 @@ void LLPanel::childSetPrevalidate(const std::string& id, BOOL (*func)(const LLWS
 	}
 }
 
-void LLPanel::childSetWrappedText(const std::string& id, const std::string& text, bool visible)
-{
-	LLTextBox* child = findChild<LLTextBox>(id);
-	if (child)
-	{
-		child->setVisible(visible);
-		child->setWrappedText(text);
-	}
-}
 
 void LLPanel::childSetAction(const std::string& id, boost::function<void(void*)> function, void* value)
 {
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index 8b23ea7030b..0594762333a 100644
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -209,9 +209,6 @@ class LLPanel : public LLUICtrl
 	void childShowTab(const std::string& id, const std::string& tabname, bool visible = true);
 	LLPanel *childGetVisibleTab(const std::string& id) const;
 
-	// LLTextBox
-	void childSetWrappedText(const std::string& id, const std::string& text, bool visible = true);
-
 	// LLTextBox/LLTextEditor/LLLineEditor
 	void childSetText(const std::string& id, const LLStringExplicit& text) { childSetValue(id, LLSD(text)); }
 
@@ -243,7 +240,8 @@ class LLPanel : public LLUICtrl
 	LLCallbackMap::map_t mFactoryMap;
 	CommitCallbackRegistry::ScopedRegistrar mCommitCallbackRegistrar;
 	EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar;
-	
+	VisibleCallbackRegistry::ScopedRegistrar mVisibleCallbackRegistrar;
+
 	commit_signal_t mVisibleSignal;		// Called when visibility changes, passes new visibility as LLSD()
 
 	std::string		mHelpTopic;         // the name of this panel's help topic to display in the Help Viewer
diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp
index d1ea5843eb3..f9f0307d17c 100644
--- a/indra/llui/llradiogroup.cpp
+++ b/indra/llui/llradiogroup.cpp
@@ -55,6 +55,8 @@ LLRadioGroup::Params::Params()
 	name = "radio_group";
 	mouse_opaque = true;
 	follows.flags = FOLLOWS_LEFT | FOLLOWS_TOP;
+	// radio items are not tabbable until they are selected
+	tab_stop = false;
 }
 
 LLRadioGroup::LLRadioGroup(const LLRadioGroup::Params& p)
diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h
index 914548b6aa2..1e9b5115f82 100644
--- a/indra/llui/llradiogroup.h
+++ b/indra/llui/llradiogroup.h
@@ -47,18 +47,7 @@ class LLRadioCtrl : public LLCheckBoxCtrl
 {
 public:
 	struct Params : public LLInitParam::Block<Params, LLCheckBoxCtrl::Params>
-	{
-		Ignored		length;
-		Ignored		type;
-
-		Params() 
-		:	length("length"),
-			type("type")
-		{
-			// radio items are not tabbable until they are selected
-			tab_stop = false;
-		}
-	};
+	{};
 
 	/*virtual*/ ~LLRadioCtrl();
 	/*virtual*/ void setValue(const LLSD& value);
diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp
index ed150ac50ca..7db34a0608d 100644
--- a/indra/llui/llscrollbar.cpp
+++ b/indra/llui/llscrollbar.cpp
@@ -88,8 +88,6 @@ LLScrollbar::LLScrollbar(const Params & p)
 		mCurGlowStrength(0.f),
 		mTrackColor( p.track_color() ),
 		mThumbColor ( p.thumb_color() ),
-		mOnScrollEndCallback( NULL ),
-		mOnScrollEndData( NULL ),
 		mThumbImageV(p.thumb_image_vertical),
 		mThumbImageH(p.thumb_image_horizontal),
 		mTrackImageV(p.track_image_vertical),
@@ -243,11 +241,6 @@ void LLScrollbar::updateThumbRect()
 		mThumbRect.mRight = thumb_start + thumb_length;
 		mThumbRect.mBottom = 0;
 	}
-	
-	if (mOnScrollEndCallback && mOnScrollEndData && (mDocPos == getDocPosMax()))
-	{
-		mOnScrollEndCallback(mOnScrollEndData);
-	}
 }
 
 BOOL LLScrollbar::handleMouseDown(S32 x, S32 y, MASK mask)
@@ -568,12 +561,6 @@ void LLScrollbar::draw()
 		}
 	}
 
-	BOOL was_scrolled_to_bottom = (getDocPos() == getDocPosMax());
-	if (mOnScrollEndCallback && was_scrolled_to_bottom)
-	{
-		mOnScrollEndCallback(mOnScrollEndData);
-	}
-
 	// Draw children
 	LLView::draw();
 } // end draw
diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h
index 7e88b16561c..e4c5712fb7d 100644
--- a/indra/llui/llscrollbar.h
+++ b/indra/llui/llscrollbar.h
@@ -164,9 +164,6 @@ class LLScrollbar
 	LLUIImagePtr		mTrackImageH;
 
 	S32					mThickness;
-
-	void			(*mOnScrollEndCallback)(void*);
-	void			*mOnScrollEndData;
 };
 
 
diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp
index cd5926fb6b2..5597d494fec 100644
--- a/indra/llui/llscrollcontainer.cpp
+++ b/indra/llui/llscrollcontainer.cpp
@@ -76,6 +76,7 @@ LLScrollContainer::Params::Params()
 :	is_opaque("opaque"),
 	bg_color("color"),
 	border_visible("border_visible"),
+	hide_scrollbar("hide_scrollbar"),
 	min_auto_scroll_rate("min_auto_scroll_rate", 100),
 	max_auto_scroll_rate("max_auto_scroll_rate", 1000),
 	reserve_scroll_corner("reserve_scroll_corner", false)
@@ -93,6 +94,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
 	mAutoScrollRate( 0.f ),
 	mBackgroundColor(p.bg_color()),
 	mIsOpaque(p.is_opaque),
+	mHideScrollbar(p.hide_scrollbar),
 	mReserveScrollCorner(p.reserve_scroll_corner),
 	mMinAutoScrollRate(p.min_auto_scroll_rate),
 	mMaxAutoScrollRate(p.max_auto_scroll_rate),
@@ -349,28 +351,33 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height
 	S32 doc_width = doc_rect.getWidth();
 	S32 doc_height = doc_rect.getHeight();
 
-	*visible_width = getRect().getWidth() - 2 * mBorder->getBorderWidth();
-	*visible_height = getRect().getHeight() - 2 * mBorder->getBorderWidth();
+	S32 border_width = (mBorder->getVisible() ? 2 * mBorder->getBorderWidth() : 0);
+	*visible_width = getRect().getWidth() - border_width;
+	*visible_height = getRect().getHeight() - border_width;
 	
 	*show_v_scrollbar = FALSE;
-	if( *visible_height < doc_height )
-	{
-		*show_v_scrollbar = TRUE;
-		*visible_width -= scrollbar_size;
-	}
-
 	*show_h_scrollbar = FALSE;
-	if( *visible_width < doc_width )
-	{
-		*show_h_scrollbar = TRUE;
-		*visible_height -= scrollbar_size;
 
-		// Must retest now that visible_height has changed
-		if( !*show_v_scrollbar && (*visible_height < doc_height) )
+	if (!mHideScrollbar)
+	{
+		if( *visible_height < doc_height )
 		{
 			*show_v_scrollbar = TRUE;
 			*visible_width -= scrollbar_size;
 		}
+
+		if( *visible_width < doc_width )
+		{
+			*show_h_scrollbar = TRUE;
+			*visible_height -= scrollbar_size;
+
+			// Must retest now that visible_height has changed
+			if( !*show_v_scrollbar && (*visible_height < doc_height) )
+			{
+				*show_v_scrollbar = TRUE;
+				*visible_width -= scrollbar_size;
+			}
+		}
 	}
 }
 	
@@ -457,19 +464,6 @@ void LLScrollContainer::draw()
 			sDepth--;
 		}
 	}
-
-	if (sDebugRects)
-	{
-		drawDebugRect();
-	}
-
-	//// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview)
-	//std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);
-	//if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights))
-	//{
-	//	drawDebugRect();
-	//}
-
 } // end draw
 
 bool LLScrollContainer::addChild(LLView* view, S32 tab_group)
@@ -598,7 +592,7 @@ LLRect LLScrollContainer::getContentWindowRect() const
 	BOOL show_h_scrollbar = FALSE;
 	BOOL show_v_scrollbar = FALSE;
 	calcVisibleSize( &visible_width, &visible_height, &show_h_scrollbar, &show_v_scrollbar );
-	S32 border_width = mBorder->getBorderWidth();
+	S32 border_width = mBorder->getVisible() ? mBorder->getBorderWidth() : 0;
 	scroller_view_rect.setOriginAndSize(border_width, 
 										show_h_scrollbar ? mScrollbar[HORIZONTAL]->getRect().mTop : border_width, 
 										visible_width, 
diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h
index 8385bca02fb..ac8ffe52583 100644
--- a/indra/llui/llscrollcontainer.h
+++ b/indra/llui/llscrollcontainer.h
@@ -68,7 +68,8 @@ class LLScrollContainer : public LLUICtrl
 	{
 		Optional<bool>		is_opaque,
 							reserve_scroll_corner,
-							border_visible;
+							border_visible,
+							hide_scrollbar;
 		Optional<F32>		min_auto_scroll_rate,
 							max_auto_scroll_rate;
 		Optional<LLUIColor>	bg_color;
@@ -139,6 +140,7 @@ class LLScrollContainer : public LLUICtrl
 	F32			mAutoScrollRate;
 	F32			mMinAutoScrollRate;
 	F32			mMaxAutoScrollRate;
+	bool		mHideScrollbar;
 };
 
 
diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp
index e28da91305d..a7c268758ad 100644
--- a/indra/llui/llscrolllistcell.cpp
+++ b/indra/llui/llscrolllistcell.cpp
@@ -204,6 +204,13 @@ BOOL LLScrollListText::isText() const
 	return TRUE;
 }
 
+BOOL LLScrollListText::needsToolTip() const
+{
+	// show tooltips for truncated text
+	return mFont->getWidth(mText.getString()) > getWidth();
+}
+
+
 //virtual 
 BOOL LLScrollListText::getVisible() const
 {
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 9d3fa65f648..758623f1212 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -94,16 +94,18 @@ class LLScrollListCell
 
 	LLScrollListCell(const LLScrollListCell::Params&);
 	virtual ~LLScrollListCell() {};
-	virtual void			draw(const LLColor4& color, const LLColor4& highlight_color) const = 0;		// truncate to given width, if possible
+
+	virtual void			draw(const LLColor4& color, const LLColor4& highlight_color) const {};		// truncate to given width, if possible
 	virtual S32				getWidth() const {return mWidth;}
 	virtual S32				getContentWidth() const { return 0; }
-	virtual S32				getHeight() const = 0;
+	virtual S32				getHeight() const { return 0; }
 	virtual const LLSD		getValue() const;
 	virtual void			setValue(const LLSD& value) { }
 	virtual BOOL			getVisible() const { return TRUE; }
 	virtual void			setWidth(S32 width) { mWidth = width; }
 	virtual void			highlightText(S32 offset, S32 num_chars) {}
-	virtual BOOL			isText() const = 0;
+	virtual BOOL			isText() const { return FALSE; }
+	virtual BOOL			needsToolTip() const { return FALSE; }
 	virtual void			setColor(const LLColor4&) {}
 	virtual void			onCommit() {};
 
@@ -120,8 +122,6 @@ class LLScrollListSpacer : public LLScrollListCell
 	LLScrollListSpacer(const LLScrollListCell::Params& p) : LLScrollListCell(p) {}
 	/*virtual*/ ~LLScrollListSpacer() {};
 	/*virtual*/ void			draw(const LLColor4& color, const LLColor4& highlight_color) const {}
-	/*virtual*/ S32				getHeight() const { return 0; }
-	/*virtual*/ BOOL			isText() const { return FALSE; }
 };
 
 /*
@@ -143,6 +143,7 @@ class LLScrollListText : public LLScrollListCell
 
 	/*virtual*/ void	setColor(const LLColor4&);
 	/*virtual*/ BOOL	isText() const;
+	/*virtual*/ BOOL	needsToolTip() const;
 
 	void			setText(const LLStringExplicit& text);
 	void			setFontStyle(const U8 font_style);
@@ -175,7 +176,6 @@ class LLScrollListIcon : public LLScrollListCell
 	/*virtual*/ S32		getHeight() const;
 	/*virtual*/ const LLSD		getValue() const;
 	/*virtual*/ void	setColor(const LLColor4&);
-	/*virtual*/ BOOL	isText()const { return FALSE; }
 	/*virtual*/ void	setValue(const LLSD& value);
 
 private:
@@ -202,7 +202,6 @@ class LLScrollListCheck : public LLScrollListCell
 	/*virtual*/ void	setEnabled(BOOL enable);
 
 	LLCheckBoxCtrl*	getCheckBox()				{ return mCheckBox; }
-	/*virtual*/ BOOL	isText() const				{ return FALSE; }
 
 private:
 	LLCheckBoxCtrl* mCheckBox;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 54e42bf6422..af05686c707 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -218,7 +218,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)
 	sbparams.orientation(LLScrollbar::VERTICAL);
 	sbparams.doc_size(getItemCount());
 	sbparams.doc_pos(mScrollLines);
-	sbparams.page_size( mPageLines ? mPageLines : getItemCount() );
+	sbparams.page_size( getLinesPerPage() );
 	sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2));
 	sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
 	sbparams.visible(false);
@@ -475,10 +475,7 @@ void LLScrollListCtrl::updateLayout()
 	getChildView("comment_text")->setShape(mItemListRect);
 
 	// how many lines of content in a single "page"
-	S32 page_lines =  mLineHeight? mItemListRect.getHeight() / mLineHeight : getItemCount();
-	//if mPageLines is NOT provided display all item
-	if(mPageLines)
-		page_lines = mPageLines;
+	S32 page_lines =  getLinesPerPage();
 
 	BOOL scrollbar_visible = mLineHeight * getItemCount() > mItemListRect.getHeight();
 	if (scrollbar_visible)
@@ -1386,7 +1383,7 @@ void LLScrollListCtrl::drawItems()
 	S32 y = mItemListRect.mTop - mLineHeight;
 
 	// allow for partial line at bottom
-	S32 num_page_lines = (mPageLines)? mPageLines : getItemCount() + 1;
+	S32 num_page_lines = getLinesPerPage();
 
 	LLRect item_rect;
 
@@ -1529,7 +1526,19 @@ BOOL LLScrollListCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return handled;
 }
 
-BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+// *NOTE: Requires a valid row_index and column_index
+LLRect LLScrollListCtrl::getCellRect(S32 row_index, S32 column_index)
+{
+	LLRect cell_rect;
+	S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft;
+	S32 rect_bottom = getRowOffsetFromIndex(row_index);
+	LLScrollListColumn* columnp = getColumn(column_index);
+	cell_rect.setOriginAndSize(rect_left, rect_bottom,
+		rect_left + columnp->getWidth(), mLineHeight);
+	return cell_rect;
+}
+
+BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	S32 column_index = getColumnIndexFromOffset(x);
 	LLScrollListColumn* columnp = getColumn(column_index);
@@ -1543,20 +1552,23 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sti
 	{
 		LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
 		if (!hit_cell) return FALSE;
-		//S32 cell_required_width = hit_cell->getContentWidth();
 		if (hit_cell 
-			&& hit_cell->isText())
+			&& hit_cell->isText()
+			&& hit_cell->needsToolTip())
 		{
-			S32 rect_left = getColumnOffsetFromIndex(column_index) + mItemListRect.mLeft;
-			S32 rect_bottom = getRowOffsetFromIndex(getItemIndex(hit_item));
-			LLRect cell_rect;
-			cell_rect.setOriginAndSize(rect_left, rect_bottom, rect_left + columnp->getWidth(), mLineHeight);
+			S32 row_index = getItemIndex(hit_item);
+			LLRect cell_rect = getCellRect(row_index, column_index);
 			// Convert rect local to screen coordinates
 			LLRect sticky_rect;
 			localRectToScreen(cell_rect, &sticky_rect);
-			LLToolTipMgr::instance().show(LLToolTipParams()
-				.message(hit_cell->getValue().asString())
-				.sticky_rect(sticky_rect));		
+
+			// display tooltip exactly over original cell, in same font
+			LLToolTipMgr::instance().show(LLToolTip::Params()
+										.message(hit_cell->getValue().asString())
+										.font(LLFontGL::getFontSansSerifSmall())
+										.pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 4))
+										.delay_time(0.2f)
+										.sticky_rect(sticky_rect));		
 		}
 		handled = TRUE;
 	}
@@ -1565,7 +1577,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sti
 	LLScrollColumnHeader* headerp = columnp->mHeader;
 	if (headerp && !handled)
 	{
-		handled = headerp->handleToolTip(x, y, msg, sticky_rect_screen);
+		handled = headerp->handleToolTip(x, y, mask);
 	}
 
 	return handled;
@@ -1877,7 +1889,7 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
 		mLineHeight );
 
 	// allow for partial line at bottom
-	S32 num_page_lines = (mPageLines)? mPageLines : getItemCount() + 1;
+	S32 num_page_lines = getLinesPerPage();
 
 	S32 line = 0;
 	item_list::iterator iter;
@@ -2336,6 +2348,20 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
 	}
 }
 
+S32	LLScrollListCtrl::getLinesPerPage()
+{
+	//if mPageLines is NOT provided display all item
+	if(mPageLines)
+	{
+		return mPageLines;
+	}
+	else
+	{
+		return mLineHeight ? mItemListRect.getHeight() / mLineHeight : getItemCount();
+	}
+}
+
+
 // Called by scrollbar
 void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar )
 {
@@ -2442,7 +2468,7 @@ void LLScrollListCtrl::scrollToShowSelected()
 	}
 
 	S32 lowest = mScrollLines;
-	S32 page_lines = (mPageLines)? mPageLines : getItemCount();
+	S32 page_lines = getLinesPerPage();
 	S32 highest = mScrollLines + page_lines;
 
 	if (index < lowest)
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 83b2f71037a..78bc60db6ed 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -288,7 +288,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	/*virtual*/ BOOL	handleKeyHere(KEY key, MASK mask);
 	/*virtual*/ BOOL	handleUnicodeCharHere(llwchar uni_char);
 	/*virtual*/ BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks);
-	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect);
+	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, MASK mask);
 	/*virtual*/ void	setEnabled(BOOL enabled);
 	/*virtual*/ void	setFocus( BOOL b );
 	/*virtual*/ void	onFocusReceived();
@@ -307,6 +307,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 
 	LLRect			getItemListRect() { return mItemListRect; }
 
+	/// Returns rect, in local coords, of a given row/column
+	LLRect			getCellRect(S32 row_index, S32 column_index);
+
 	// Used "internally" by the scroll bar.
 	void			onScrollChange( S32 new_pos, LLScrollbar* src );
 
@@ -390,6 +393,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	void			deselectItem(LLScrollListItem* itemp);
 	void			commitIfChanged();
 	BOOL			setSort(S32 column, BOOL ascending);
+	S32				getLinesPerPage();
 
 	static void		showNameDetails(std::string id, bool is_group);
 	static void		copyNameToClipboard(std::string id, bool is_group);
diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp
index 2ac6925c78f..2c5e0d24cda 100644
--- a/indra/llui/llscrolllistitem.cpp
+++ b/indra/llui/llscrolllistitem.cpp
@@ -36,7 +36,6 @@
 #include "llscrolllistitem.h"
 
 #include "llrect.h"
-#include "llresmgr.h"		// LLFONT_SANSSERIF_SMALL
 #include "llui.h"
 
 
diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h
index c2b7effbc7d..0ec7fbcc2c6 100644
--- a/indra/llui/llscrolllistitem.h
+++ b/indra/llui/llscrolllistitem.h
@@ -34,10 +34,8 @@
 #ifndef LLSCROLLLISTITEM_H
 #define LLSCROLLLISTITEM_H
 
-#include "llfontgl.h"		// LLFontGL::HAlign
 #include "llpointer.h"		// LLPointer<>
 #include "llsd.h"
-#include "lluistring.h"
 #include "v4color.h"
 #include "llinitparam.h"
 #include "llscrolllistcell.h"
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index fb71b607258..3ecf6290828 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -83,7 +83,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)
 		LLTextBox::Params params(p.slider_label);
 		params.rect.setIfNotProvided(label_rect);
 		params.font.setIfNotProvided(p.font);
-		params.text(p.label);
+		params.initial_value(p.label());
 		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
 		addChild(mLabelBox);
 	}
diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp
index 83d71006aac..bedf16a397d 100644
--- a/indra/llui/llspinctrl.cpp
+++ b/indra/llui/llspinctrl.cpp
@@ -90,7 +90,7 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
 		LLTextBox::Params params;
 		params.name("SpinCtrl Label");
 		params.rect(label_rect);
-		params.text(p.label);
+		params.initial_value(p.label());
 		if (p.font.isProvided())
 		{
 			params.font(p.font);
diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp
index 4ba01eb4410..9580c76e2a2 100644
--- a/indra/llui/llstatview.cpp
+++ b/indra/llui/llstatview.cpp
@@ -67,5 +67,7 @@ LLStatView::~LLStatView()
 
 static StatViewRegistry::Register<LLStatBar> r1("stat_bar");
 static StatViewRegistry::Register<LLStatView> r2("stat_view");
+// stat_view can be a child of panels/etc.
+static LLDefaultChildRegistry::Register<LLStatView> r3("stat_view");
 
 
diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp
index c16ac080144..fd3f88d1f61 100644
--- a/indra/llui/llstyle.cpp
+++ b/indra/llui/llstyle.cpp
@@ -40,7 +40,7 @@
 
 LLStyle::Params::Params()
 :	visible("visible", true),
-	drop_shadow("drop_shadow", false),
+	drop_shadow("drop_shadow", LLFontGL::NO_SHADOW),
 	color("color", LLColor4::black),
 	font("font", LLFontGL::getFontMonospace()),
 	image("image"),
diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h
index 5e8883afd7f..c7699641366 100644
--- a/indra/llui/llstyle.h
+++ b/indra/llui/llstyle.h
@@ -44,12 +44,12 @@ class LLStyle : public LLRefCount
 public:
 	struct Params : public LLInitParam::Block<Params>
 	{
-		Optional<bool>				visible,
-									drop_shadow;
-		Optional<LLUIColor>			color;
-		Optional<const LLFontGL*>	font;
-		Optional<LLUIImage*>		image;
-		Optional<std::string>		link_href;
+		Optional<bool>					visible;
+		Optional<LLFontGL::ShadowType>	drop_shadow;
+		Optional<LLUIColor>				color;
+		Optional<const LLFontGL*>		font;
+		Optional<LLUIImage*>			image;
+		Optional<std::string>			link_href;
 		Params();
 	};
 	LLStyle(const Params& p = Params());
@@ -60,6 +60,8 @@ class LLStyle : public LLRefCount
 	BOOL isVisible() const;
 	void setVisible(BOOL is_visible);
 
+	LLFontGL::ShadowType getShadowType() { return mDropShadow; }
+
 	void setFont(const LLFontGL* font);
 	const LLFontGL* getFont() const;
 
@@ -94,7 +96,7 @@ class LLStyle : public LLRefCount
 	BOOL        mItalic;
 	BOOL        mBold;
 	BOOL        mUnderline;
-	BOOL		mDropShadow;
+	LLFontGL::ShadowType		mDropShadow;
 
 protected:
 	~LLStyle() { }
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index b6eed3ef185..b1067ad6f31 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -596,10 +596,10 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
 }
 
 // virtual
-BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect& sticky_rect )
+BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask)
 {
 	static LLUICachedControl<S32> tabcntrv_pad ("UITabCntrvPad", 0);
-	BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect );
+	BOOL handled = LLPanel::handleToolTip( x, y, mask);
 	if (!handled && getTabCount() > 0) 
 	{
 		LLTabTuple* firsttuple = getTab(0);
@@ -629,7 +629,7 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect& stic
 				tuple->mButton->setVisible( TRUE );
 				S32 local_x = x - tuple->mButton->getRect().mLeft;
 				S32 local_y = y - tuple->mButton->getRect().mBottom;
-				handled = tuple->mButton->handleToolTip( local_x, local_y, msg, sticky_rect );
+				handled = tuple->mButton->handleToolTip( local_x, local_y, mask);
 				if( handled )
 				{
 					break;
@@ -906,7 +906,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
 		LLTextBox::Params params;
 		params.name(trimmed_label);
 		params.rect(btn_rect);
-		params.text(trimmed_label);
+		params.initial_value(trimmed_label);
 		params.font(font);
 		textbox = LLUICtrlFactory::create<LLTextBox> (params);
 		
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 89a0346896d..7bbecc1abc7 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -99,7 +99,7 @@ class LLTabContainer : public LLPanel
 	/*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask );
 	/*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask );
 	/*virtual*/ BOOL handleMouseUp( S32 x, S32 y, MASK mask );
-	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect );
+	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
 	/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
 	/*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,	BOOL drop,
 									   EDragAndDropType type, void* cargo_data,
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 0fd6a141876..6c048aa908d 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -34,23 +34,2009 @@
 #include "linden_common.h"
 
 #include "lltextbase.h"
-#include "llstl.h"
-#include "llview.h"
-#include "llwindow.h"
+
+#include "lllocalcliprect.h"
 #include "llmenugl.h"
+#include "llscrollcontainer.h"
+#include "llstl.h"
+#include "lltextparser.h"
 #include "lltooltip.h"
 #include "lluictrl.h"
 #include "llurlaction.h"
 #include "llurlregistry.h"
+#include "llview.h"
+#include "llwindow.h"
+#include <boost/bind.hpp>
+
+const F32	CURSOR_FLASH_DELAY = 1.0f;  // in seconds
+const S32	CURSOR_THICKNESS = 2;
+
+LLTextBase::line_info::line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num) 
+:	mDocIndexStart(index_start), 
+	mDocIndexEnd(index_end),
+	mRect(rect),
+	mLineNum(line_num)
+{}
+
+bool LLTextBase::compare_segment_end::operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const
+{
+	return a->getEnd() < b->getEnd();
+}
+
+
+// helper functors
+struct LLTextBase::compare_bottom
+{
+	bool operator()(const S32& a, const LLTextBase::line_info& b) const
+	{
+		return a > b.mRect.mBottom; // bottom of a is higher than bottom of b
+	}
+
+	bool operator()(const LLTextBase::line_info& a, const S32& b) const
+	{
+		return a.mRect.mBottom > b; // bottom of a is higher than bottom of b
+	}
+
+	bool operator()(const LLTextBase::line_info& a, const LLTextBase::line_info& b) const
+	{
+		return a.mRect.mBottom > b.mRect.mBottom; // bottom of a is higher than bottom of b
+	}
+
+};
+
+// helper functors
+struct LLTextBase::compare_top
+{
+	bool operator()(const S32& a, const LLTextBase::line_info& b) const
+	{
+		return a > b.mRect.mTop; // top of a is higher than top of b
+	}
+
+	bool operator()(const LLTextBase::line_info& a, const S32& b) const
+	{
+		return a.mRect.mTop > b; // top of a is higher than top of b
+	}
+
+	bool operator()(const LLTextBase::line_info& a, const LLTextBase::line_info& b) const
+	{
+		return a.mRect.mTop > b.mRect.mTop; // top of a is higher than top of b
+	}
+};
+
+struct LLTextBase::line_end_compare
+{
+	bool operator()(const S32& pos, const LLTextBase::line_info& info) const
+	{
+		return (pos < info.mDocIndexEnd);
+	}
+
+	bool operator()(const LLTextBase::line_info& info, const S32& pos) const
+	{
+		return (info.mDocIndexEnd < pos);
+	}
+
+	bool operator()(const LLTextBase::line_info& a, const LLTextBase::line_info& b) const
+	{
+		return (a.mDocIndexEnd < b.mDocIndexEnd);
+	}
+
+};
+
+//////////////////////////////////////////////////////////////////////////
+//
+// LLTextBase::DocumentPanel
+//
+
+
+LLTextBase::DocumentPanel::DocumentPanel(const Params& p)
+: LLPanel(p)
+{}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// LLTextBase
+//
+
+// register LLTextBase::Params under name "textbase"
+static LLWidgetNameRegistry::StaticRegistrar sRegisterTextBaseParams(&typeid(LLTextBase::Params), "textbase");
+
+LLTextBase::LineSpacingParams::LineSpacingParams()
+:	multiple("multiple", 1.f),
+	pixels("pixels", 0)
+{
+}
+
+
+LLTextBase::Params::Params()
+:	cursor_color("cursor_color"),
+	text_color("text_color"),
+	text_readonly_color("text_readonly_color"),
+	bg_visible("bg_visible", false),
+	border_visible("border_visible", false),
+	bg_readonly_color("bg_readonly_color"),
+	bg_writeable_color("bg_writeable_color"),
+	bg_focus_color("bg_focus_color"),
+	hide_scrollbar("hide_scrollbar"),
+	clip_to_rect("clip_to_rect", true),
+	track_end("track_end", false),
+	read_only("read_only", false),
+	v_pad("v_pad", 0),
+	h_pad("h_pad", 0),
+	line_spacing("line_spacing"),
+	max_text_length("max_length", 255),
+	font_shadow("font_shadow"),
+	wrap("wrap"),
+	use_ellipses("use_ellipses", false),
+	allow_html("allow_html", false),
+	parse_highlights("parse_highlights", false)
+{
+	addSynonym(track_end, "track_bottom");
+	addSynonym(wrap, "word_wrap");
+}
+
+
+LLTextBase::LLTextBase(const LLTextBase::Params &p) 
+:	LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),
+	mURLClickSignal(),
+	mMaxTextByteLength( p.max_text_length ),
+	mDefaultFont(p.font),
+	mFontShadow(p.font_shadow),
+	mPopupMenu(NULL),
+	mReadOnly(p.read_only),
+	mCursorColor(p.cursor_color),
+	mFgColor(p.text_color),
+	mBorderVisible( p.border_visible ),
+	mReadOnlyFgColor(p.text_readonly_color),
+	mWriteableBgColor(p.bg_writeable_color),
+	mReadOnlyBgColor(p.bg_readonly_color),
+	mFocusBgColor(p.bg_focus_color),
+	mReflowNeeded(FALSE),
+	mCursorPos( 0 ),
+	mScrollNeeded(FALSE),
+	mDesiredXPixel(-1),
+	mHPad(p.h_pad),
+	mVPad(p.v_pad),
+	mHAlign(p.font_halign),
+	mLineSpacingMult(p.line_spacing.multiple),
+	mLineSpacingPixels(p.line_spacing.pixels),
+	mTrackEnd( p.track_end ),
+	mScrollIndex(-1),
+	mSelectionStart( 0 ),
+	mSelectionEnd( 0 ),
+	mIsSelecting( FALSE ),
+	mClip(p.clip_to_rect),
+	mWordWrap(p.wrap),
+	mUseEllipses( p.use_ellipses ),
+	mParseHTML(p.allow_html),
+	mParseHighlights(p.parse_highlights)
+{
+	LLScrollContainer::Params scroll_params;
+	scroll_params.name = "text scroller";
+	scroll_params.rect = getLocalRect();
+	scroll_params.follows.flags = FOLLOWS_ALL;
+	scroll_params.is_opaque = false;
+	scroll_params.mouse_opaque = false;
+	scroll_params.min_auto_scroll_rate = 200;
+	scroll_params.max_auto_scroll_rate = 800;
+	scroll_params.hide_scrollbar = p.hide_scrollbar;
+	scroll_params.border_visible = p.border_visible;
+	mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_params);
+	addChild(mScroller);
+
+	LLPanel::Params panel_params;
+	panel_params.name = "text_contents";
+	panel_params.rect =  LLRect(0, 500, 500, 0);
+	panel_params.background_visible = p.bg_visible;
+	panel_params.background_opaque = true;
+	panel_params.mouse_opaque = false;
+
+	mDocumentPanel = LLUICtrlFactory::create<DocumentPanel>(panel_params);
+	mScroller->addChild(mDocumentPanel);
+
+	createDefaultSegment();
+
+	updateTextRect();
+}
+
+LLTextBase::~LLTextBase()
+{
+	delete mPopupMenu;
+	clearSegments();
+}
+
+void LLTextBase::initFromParams(const LLTextBase::Params& p)
+{
+	LLUICtrl::initFromParams(p);
+	resetDirty();		// Update saved text state
+	updateSegments();
+
+	// HACK: work around enabled == readonly design bug -- RN
+	// setEnabled will modify our read only status, so do this after
+	// LLTextBase::initFromParams
+	if (p.read_only.isProvided())
+	{
+		mReadOnly = p.read_only;
+	}
+
+	// HACK:  text editors always need to be enabled so that we can scroll
+	LLView::setEnabled(true);
+}
+
+bool LLTextBase::truncate()
+{
+	BOOL did_truncate = FALSE;
+
+	// First rough check - if we're less than 1/4th the size, we're OK
+	if (getLength() >= S32(mMaxTextByteLength / 4))
+	{	
+		// Have to check actual byte size
+        LLWString text(getWText());
+		S32 utf8_byte_size = wstring_utf8_length(text);
+		if ( utf8_byte_size > mMaxTextByteLength )
+		{
+			// Truncate safely in UTF-8
+			std::string temp_utf8_text = wstring_to_utf8str(text);
+			temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength );
+			getViewModel()->setDisplay(utf8str_to_wstring( temp_utf8_text ));
+			did_truncate = TRUE;
+		}
+	}
+
+	return did_truncate;
+}
+
+LLStyle::Params LLTextBase::getDefaultStyle()
+{
+	LLColor4 text_color = ( mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get() );
+	return LLStyle::Params().color(text_color).font(mDefaultFont).drop_shadow(mFontShadow);
+}
+
+void LLTextBase::onValueChange(S32 start, S32 end)
+{
+}
+
+
+// Draws the black box behind the selected text
+void LLTextBase::drawSelectionBackground()
+{
+	// Draw selection even if we don't have keyboard focus for search/replace
+	if( hasSelection() && !mLineInfoList.empty())
+	{
+		LLWString text = getWText();
+		std::vector<LLRect> selection_rects;
+
+		S32 selection_left		= llmin( mSelectionStart, mSelectionEnd );
+		S32 selection_right		= llmax( mSelectionStart, mSelectionEnd );
+		LLRect selection_rect = mTextRect;
+
+		// Skip through the lines we aren't drawing.
+		LLRect content_display_rect = mScroller->getVisibleContentRect();
+
+		// binary search for line that starts before top of visible buffer
+		line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
+		line_list_t::const_iterator end_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
+
+		bool done = false;
+
+		// Find the coordinates of the selected area
+		for (;line_iter != end_iter && !done; ++line_iter)
+		{
+			// is selection visible on this line?
+			if (line_iter->mDocIndexEnd > selection_left && line_iter->mDocIndexStart < selection_right)
+			{
+				segment_set_t::iterator segment_iter;
+				S32 segment_offset;
+				getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset);
+				
+				LLRect selection_rect;
+				selection_rect.mLeft = line_iter->mRect.mLeft;
+				selection_rect.mRight = line_iter->mRect.mLeft;
+				selection_rect.mBottom = line_iter->mRect.mBottom;
+				selection_rect.mTop = line_iter->mRect.mTop;
+					
+				for(;segment_iter != mSegments.end(); ++segment_iter, segment_offset = 0)
+				{
+					LLTextSegmentPtr segmentp = *segment_iter;
+
+					S32 segment_line_start = segmentp->getStart() + segment_offset;
+					S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
+
+					// if selection after beginning of segment
+					if(selection_left >= segment_line_start)
+					{
+						S32 num_chars = llmin(selection_left, segment_line_end) - segment_line_start;
+						selection_rect.mLeft += segmentp->getWidth(segment_offset, num_chars);
+					}
+
+					// if selection spans end of current segment...
+					if (selection_right > segment_line_end)
+					{
+						// extend selection slightly beyond end of line
+						// to indicate selection of newline character (use "n" character to determine width)
+						selection_rect.mRight += segmentp->getWidth(segment_offset, segment_line_end - segment_line_start);
+					}
+					// else if selection ends on current segment...
+					else
+					{
+						S32 num_chars = selection_right - segment_line_start;
+						selection_rect.mRight += segmentp->getWidth(segment_offset, num_chars);
+
+						break;
+					}
+				}
+				selection_rects.push_back(selection_rect);
+			}
+		}
+		
+		// Draw the selection box (we're using a box instead of reversing the colors on the selected text).
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+		const LLColor4& color = mReadOnly ? mReadOnlyBgColor.get() : mWriteableBgColor.get();
+		F32 alpha = hasFocus() ? 0.7f : 0.3f;
+		alpha *= getDrawContext().mAlpha;
+		gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
+
+		for (std::vector<LLRect>::iterator rect_it = selection_rects.begin();
+			rect_it != selection_rects.end();
+			++rect_it)
+		{
+			LLRect selection_rect = *rect_it;
+			selection_rect.translate(mTextRect.mLeft - content_display_rect.mLeft, mTextRect.mBottom - content_display_rect.mBottom);
+			gl_rect_2d(selection_rect);
+		}
+	}
+}
+
+void LLTextBase::drawCursor()
+{
+	F32 alpha = getDrawContext().mAlpha;
+
+	if( hasFocus()
+		&& gFocusMgr.getAppHasFocus()
+		&& !mReadOnly)
+	{
+		LLWString wtext = getWText();
+		const llwchar* text = wtext.c_str();
+
+		LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos);
+		cursor_rect.translate(-1, 0);
+		segment_set_t::iterator seg_it = getSegIterContaining(mCursorPos);
+
+		// take style from last segment
+		LLTextSegmentPtr segmentp;
+
+		if (seg_it != mSegments.end())
+		{
+			segmentp = *seg_it;
+		}
+		else
+		{
+			//segmentp = mSegments.back();
+			return;
+		}
+
+		// Draw the cursor
+		// (Flash the cursor every half second starting a fixed time after the last keystroke)
+		F32 elapsed = mCursorBlinkTimer.getElapsedTimeF32();
+		if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) )
+		{
+
+			if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
+			{
+				S32 width = llmax(CURSOR_THICKNESS, segmentp->getWidth(mCursorPos - segmentp->getStart(), 1));
+				cursor_rect.mRight = cursor_rect.mLeft + width;
+			}
+			else
+			{
+				cursor_rect.mRight = cursor_rect.mLeft + CURSOR_THICKNESS;
+			}
+			
+			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+			LLColor4 cursor_color = mCursorColor.get() % alpha;
+			gGL.color4fv( cursor_color.mV );
+			
+			gl_rect_2d(cursor_rect);
+
+			if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n')
+			{
+				LLColor4 text_color;
+				const LLFontGL* fontp;
+				if (segmentp)
+				{
+					text_color = segmentp->getColor();
+					fontp = segmentp->getStyle()->getFont();
+				}
+				else if (mReadOnly)
+				{
+					text_color = mReadOnlyFgColor.get();
+					fontp = mDefaultFont;
+				}
+				else
+				{
+					text_color = mFgColor.get();
+					fontp = mDefaultFont;
+				}
+				fontp->render(text, mCursorPos, cursor_rect.mLeft, cursor_rect.mTop, 
+					LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
+					LLFontGL::LEFT, LLFontGL::TOP,
+					LLFontGL::NORMAL,
+					LLFontGL::NO_SHADOW,
+					1);
+			}
+
+			// Make sure the IME is in the right place
+			LLRect screen_pos = calcScreenRect();
+			LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_rect.mLeft), screen_pos.mBottom + llfloor(cursor_rect.mTop) );
+
+			ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]);
+			ime_pos.mY = (S32) (ime_pos.mY * LLUI::sGLScaleFactor.mV[VY]);
+			getWindow()->setLanguageTextInput( ime_pos );
+		}
+	}
+}
+
+void LLTextBase::drawText()
+{
+	LLWString text = getWText();
+	const S32 text_len = getLength();
+	if( text_len <= 0 )
+	{
+		return;
+	}
+	S32 selection_left = -1;
+	S32 selection_right = -1;
+	// Draw selection even if we don't have keyboard focus for search/replace
+	if( hasSelection())
+	{
+		selection_left = llmin( mSelectionStart, mSelectionEnd );
+		selection_right = llmax( mSelectionStart, mSelectionEnd );
+	}
+
+	LLRect scrolled_view_rect = mScroller->getVisibleContentRect();
+	LLRect content_rect = mScroller->getContentWindowRect();
+	std::pair<S32, S32> line_range = getVisibleLines();
+	S32 first_line = line_range.first;
+	S32 last_line = line_range.second;
+	if (first_line >= last_line)
+	{
+		return;
+	}
+	
+	S32 line_start = getLineStart(first_line);
+	// find first text segment that spans top of visible portion of text buffer
+	segment_set_t::iterator seg_iter = getSegIterContaining(line_start);
+	if (seg_iter == mSegments.end()) 
+	{
+		return;
+	}
+
+	LLTextSegmentPtr cur_segment = *seg_iter;
+
+	for (S32 cur_line = first_line; cur_line < last_line; cur_line++)
+	{
+		line_info& line = mLineInfoList[cur_line];
+
+		if ((line.mRect.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom) 
+		{
+			break;
+		}
+
+		S32 next_start = -1;
+		S32 line_end = text_len;
+
+		if ((cur_line + 1) < getLineCount())
+		{
+			next_start = getLineStart(cur_line + 1);
+			line_end = next_start;
+		}
+		if ( text[line_end-1] == '\n' )
+		{
+			--line_end;
+		}
+
+		LLRect text_rect(line.mRect.mLeft + mTextRect.mLeft - scrolled_view_rect.mLeft,
+						line.mRect.mTop - scrolled_view_rect.mBottom + mTextRect.mBottom,
+						mDocumentPanel->getRect().getWidth() - scrolled_view_rect.mLeft,
+						line.mRect.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom);
+
+		// draw a single line of text
+		S32 seg_start = line_start;
+		while( seg_start < line_end )
+		{
+			while( cur_segment->getEnd() <= seg_start )
+			{
+				seg_iter++;
+				if (seg_iter == mSegments.end())
+				{
+					llwarns << "Ran off the segmentation end!" << llendl;
+
+					return;
+				}
+				cur_segment = *seg_iter;
+			}
+			
+			S32 clipped_end	=	llmin( line_end, cur_segment->getEnd() )  - cur_segment->getStart();
+			text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect));
+
+			seg_start = clipped_end + cur_segment->getStart();
+		}
+
+		line_start = next_start;
+	}
+}
+
+///////////////////////////////////////////////////////////////////
+// Returns change in number of characters in mWText
+
+S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::segment_vec_t* segments )
+{
+	LLWString text(getWText());
+	S32 old_len = text.length();		// length() returns character length
+	S32 insert_len = wstr.length();
+
+	pos = getEditableIndex(pos, true);
+
+	segment_set_t::iterator seg_iter = getSegIterContaining(pos);
+
+	LLTextSegmentPtr default_segment;
+
+	LLTextSegmentPtr segmentp;
+	if (seg_iter != mSegments.end())
+	{
+		segmentp = *seg_iter;
+	}
+	else
+	{
+		//segmentp = mSegments.back();
+		return pos;
+	}
+
+	if (segmentp->canEdit())
+	{
+		segmentp->setEnd(segmentp->getEnd() + insert_len);
+		if (seg_iter != mSegments.end())
+		{
+			++seg_iter;
+		}
+	}
+	else
+	{
+		// create default editable segment to hold new text
+		default_segment = new LLNormalTextSegment( new LLStyle(getDefaultStyle()), pos, pos + insert_len, *this);
+	}
+
+	// shift remaining segments to right
+	for(;seg_iter != mSegments.end(); ++seg_iter)
+	{
+		LLTextSegmentPtr segmentp = *seg_iter;
+		segmentp->setStart(segmentp->getStart() + insert_len);
+		segmentp->setEnd(segmentp->getEnd() + insert_len);
+	}
+
+	// insert new segments
+	if (segments)
+	{
+		if (default_segment.notNull())
+		{
+			// potentially overwritten by segments passed in
+			insertSegment(default_segment);
+		}
+		for (segment_vec_t::iterator seg_iter = segments->begin();
+			seg_iter != segments->end();
+			++seg_iter)
+		{
+			LLTextSegment* segmentp = *seg_iter;
+			insertSegment(segmentp);
+		}
+	}
+
+	text.insert(pos, wstr);
+    getViewModel()->setDisplay(text);
+
+	if ( truncate() )
+	{
+		// The user's not getting everything he's hoping for
+		make_ui_sound("UISndBadKeystroke");
+		insert_len = getLength() - old_len;
+	}
+
+	onValueChange(pos, pos + insert_len);
+
+	return insert_len;
+}
+
+S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
+{
+    LLWString text(getWText());
+	segment_set_t::iterator seg_iter = getSegIterContaining(pos);
+	while(seg_iter != mSegments.end())
+	{
+		LLTextSegmentPtr segmentp = *seg_iter;
+		S32 end = pos + length;
+		if (segmentp->getStart() < pos)
+		{
+			// deleting from middle of segment
+			if (segmentp->getEnd() > end)
+			{
+				segmentp->setEnd(segmentp->getEnd() - length);
+			}
+			// truncating segment
+			else
+			{
+				segmentp->setEnd(pos);
+			}
+		}
+		else if (segmentp->getStart() < end)
+		{
+			// deleting entire segment
+			if (segmentp->getEnd() <= end)
+			{
+				// remove segment
+				segmentp->unlinkFromDocument(this);
+				segment_set_t::iterator seg_to_erase(seg_iter++);
+				mSegments.erase(seg_to_erase);
+				continue;
+			}
+			// deleting head of segment
+			else
+			{
+				segmentp->setStart(pos);
+				segmentp->setEnd(segmentp->getEnd() - length);
+			}
+		}
+		else
+		{
+			// shifting segments backward to fill deleted portion
+			segmentp->setStart(segmentp->getStart() - length);
+			segmentp->setEnd(segmentp->getEnd() - length);
+		}
+		++seg_iter;
+	}
+
+	text.erase(pos, length);
+    getViewModel()->setDisplay(text);
+
+	// recreate default segment in case we erased everything
+	createDefaultSegment();
+
+	onValueChange(pos, pos);
+
+	return -length;	// This will be wrong if someone calls removeStringNoUndo with an excessive length
+}
+
+S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc)
+{
+	if (pos > (S32)getLength())
+	{
+		return 0;
+	}
+    LLWString text(getWText());
+	text[pos] = wc;
+    getViewModel()->setDisplay(text);
+
+	onValueChange(pos, pos + 1);
+
+	return 1;
+}
+
+
+void LLTextBase::createDefaultSegment()
+{
+	// ensures that there is always at least one segment
+	if (mSegments.empty())
+	{
+		LLTextSegmentPtr default_segment = new LLNormalTextSegment( new LLStyle(getDefaultStyle()), 0, getLength() + 1, *this);
+		mSegments.insert(default_segment);
+		default_segment->linkToDocument(this);
+	}
+}
+
+void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert)
+{
+	if (segment_to_insert.isNull()) 
+	{
+		return;
+	}
+
+	segment_set_t::iterator cur_seg_iter = getSegIterContaining(segment_to_insert->getStart());
+
+	if (cur_seg_iter == mSegments.end())
+	{
+		mSegments.insert(segment_to_insert);
+		segment_to_insert->linkToDocument(this);
+	}
+	else
+	{
+		LLTextSegmentPtr cur_segmentp = *cur_seg_iter;
+		if (cur_segmentp->getStart() < segment_to_insert->getStart())
+		{
+			S32 old_segment_end = cur_segmentp->getEnd();
+			// split old at start point for new segment
+			cur_segmentp->setEnd(segment_to_insert->getStart());
+			// advance to next segment
+			++cur_seg_iter;
+			// insert remainder of old segment
+			LLTextSegmentPtr remainder_segment = new LLNormalTextSegment( cur_segmentp->getStyle(), segment_to_insert->getStart(), old_segment_end, *this);
+			cur_seg_iter = mSegments.insert(cur_seg_iter, remainder_segment);
+			remainder_segment->linkToDocument(this);
+			// insert new segment before remainder of old segment
+			cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert);
+
+			segment_to_insert->linkToDocument(this);
+			// move to "remanider" segment and start truncation there
+			++cur_seg_iter;
+		}
+		else
+		{
+			cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert);
+			++cur_seg_iter;
+			segment_to_insert->linkToDocument(this);
+		}
+
+		// now delete/truncate remaining segments as necessary
+		while(cur_seg_iter != mSegments.end())
+		{
+			cur_segmentp = *cur_seg_iter;
+			if (cur_segmentp->getEnd() <= segment_to_insert->getEnd())
+			{
+				cur_segmentp->unlinkFromDocument(this);
+				segment_set_t::iterator seg_to_erase(cur_seg_iter++);
+				mSegments.erase(seg_to_erase);
+			}
+			else
+			{
+				cur_segmentp->setStart(segment_to_insert->getEnd());
+				break;
+			}
+		}
+	}
+}
+
+BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleMouseDown(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleMouseDown(x, y, mask);
+}
+
+BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleMouseUp(x, y, mask))
+	{
+		// Did we just click on a link?
+		if (cur_segment->getStyle()
+			&& cur_segment->getStyle()->isLink())
+		{
+			// *TODO: send URL here?
+			mURLClickSignal(this, LLSD() );
+		}
+		return TRUE;
+	}
+
+	return LLUICtrl::handleMouseUp(x, y, mask);
+}
+
+BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleMiddleMouseDown(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleMiddleMouseDown(x, y, mask);
+}
+
+BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleMiddleMouseUp(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleMiddleMouseUp(x, y, mask);
+}
+
+BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleRightMouseDown(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleRightMouseDown(x, y, mask);
+}
+
+BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleRightMouseUp(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleRightMouseUp(x, y, mask);
+}
+
+BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleDoubleClick(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleDoubleClick(x, y, mask);
+}
+
+BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleHover(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleHover(x, y, mask);
+}
+
+BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleScrollWheel(x, y, clicks))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleScrollWheel(x, y, clicks);
+}
+
+BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
+{
+	LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
+	if (cur_segment && cur_segment->handleToolTip(x, y, mask))
+	{
+		return TRUE;
+	}
+
+	return LLUICtrl::handleToolTip(x, y, mask);
+}
+
+
+void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	LLUICtrl::reshape( width, height, called_from_parent );
+
+	// do this first after reshape, because other things depend on
+	// up-to-date mTextRect
+	updateTextRect();
+	
+	needsReflow();
+}
+
+void LLTextBase::draw()
+{
+	// reflow if needed, on demand
+	reflow();
+
+	// then update scroll position, as cursor may have moved
+	updateScrollFromCursor();
+
+	LLColor4 bg_color = mReadOnly 
+						? mReadOnlyBgColor.get()
+						: hasFocus() 
+							? mFocusBgColor.get() 
+							: mWriteableBgColor.get();
+
+	mDocumentPanel->setBackgroundColor(bg_color);
+
+	LLUICtrl::draw();
+	{
+		LLLocalClipRect clip(mTextRect, mClip);
+		drawSelectionBackground();
+		drawText();
+		drawCursor();
+	}
+}
+
+//virtual
+void LLTextBase::clear()
+{
+	getViewModel()->setDisplay(LLWStringUtil::null);
+	clearSegments();
+}
+
+//virtual
+void LLTextBase::setColor( const LLColor4& c )
+{
+	mFgColor = c;
+}
+
+//virtual
+void LLTextBase::setValue(const LLSD& value )
+{
+	setText(value.asString());
+}
+
+//virtual
+void LLTextBase::deselect()
+{
+	mSelectionStart = 0;
+	mSelectionEnd = 0;
+	mIsSelecting = FALSE;
+}
+
+
+// Sets the scrollbar from the cursor position
+void LLTextBase::updateScrollFromCursor()
+{
+	// Update scroll position even in read-only mode (when there's no cursor displayed)
+	// because startOfDoc()/endOfDoc() modify cursor position. See EXT-736.
+
+	if (!mScrollNeeded)
+	{
+		return;
+	}
+	mScrollNeeded = FALSE; 
+
+	// scroll so that the cursor is at the top of the page
+	LLRect scroller_doc_window = mScroller->getVisibleContentRect();
+	LLRect cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos);
+	cursor_rect_doc.translate(scroller_doc_window.mLeft, scroller_doc_window.mBottom);
+	mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5));
+}
+
+S32 LLTextBase::getLeftOffset(S32 width)
+{
+	switch (mHAlign)
+	{
+	case LLFontGL::LEFT:
+		return 0;
+	case LLFontGL::HCENTER:
+		return (mTextRect.getWidth() - width) / 2;
+	case LLFontGL::RIGHT:
+		return mTextRect.getWidth() - width;
+	default:
+		return 0;
+	}
+}
+
+
+static LLFastTimer::DeclareTimer FTM_TEXT_REFLOW ("Text Reflow");
+void LLTextBase::reflow(S32 start_index)
+{
+	if (!mReflowNeeded) return;
+
+	LLFastTimer ft(FTM_TEXT_REFLOW);
+
+	updateSegments();
+
+	while(mReflowNeeded)
+	{
+		mReflowNeeded = FALSE;
+
+		bool scrolled_to_bottom = mScroller->isAtBottom();
+
+		LLRect old_cursor_rect = getLocalRectFromDocIndex(mCursorPos);
+		bool follow_selection = mTextRect.overlaps(old_cursor_rect); // cursor is visible
+		S32 first_line = getFirstVisibleLine();
+
+		// if scroll anchor not on first line, update it to first character of first line
+		if (!mLineInfoList.empty()
+			&&	(mScrollIndex <  mLineInfoList[first_line].mDocIndexStart
+				||	mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd))
+		{
+			mScrollIndex = mLineInfoList[first_line].mDocIndexStart;
+		}
+		LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
+
+		S32 cur_top = 0;
+
+		if (getLength())
+		{
+			segment_set_t::iterator seg_iter = mSegments.begin();
+			S32 seg_offset = 0;
+			S32 line_start_index = 0;
+			const S32 text_width = mTextRect.getWidth();  // optionally reserve room for margin
+			S32 remaining_pixels = text_width;
+			LLWString text(getWText());
+			S32 line_count = 0;
+
+			// find and erase line info structs starting at start_index and going to end of document
+			if (!mLineInfoList.empty())
+			{
+				// find first element whose end comes after start_index
+				line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare());
+				line_start_index = iter->mDocIndexStart;
+				line_count = iter->mLineNum;
+				getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset);
+				mLineInfoList.erase(iter, mLineInfoList.end());
+			}
+
+			S32 line_height = 0;
+
+			while(seg_iter != mSegments.end())
+			{
+				LLTextSegmentPtr segment = *seg_iter;
+
+				// track maximum height of any segment on this line
+				line_height = llmax(line_height, segment->getMaxHeight());
+				S32 cur_index = segment->getStart() + seg_offset;
+				// find run of text from this segment that we can display on one line
+				S32 end_index = cur_index;
+				while(end_index < segment->getEnd() && text[end_index] != '\n')
+				{
+					++end_index;
+				}
+
+				// ask segment how many character fit in remaining space
+				S32 max_characters = end_index - cur_index;
+				S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, remaining_pixels) : S32_MAX,
+															seg_offset, 
+															cur_index - line_start_index, 
+															max_characters);
+				
+
+				S32 segment_width = segment->getWidth(seg_offset, character_count);
+				remaining_pixels -= segment_width;
+				S32 text_left = getLeftOffset(text_width - remaining_pixels);
+
+				seg_offset += character_count;
+
+				S32 last_segment_char_on_line = segment->getStart() + seg_offset;
+
+				// if we didn't finish the current segment...
+				if (last_segment_char_on_line < segment->getEnd())
+				{
+					// set up index for next line
+					// ...skip newline, we don't want to draw
+					S32 next_line_count = line_count;
+					if (text[last_segment_char_on_line] == '\n')
+					{
+						seg_offset++;
+						last_segment_char_on_line++;
+						next_line_count++;
+					}
+
+					// add line info and keep going
+					mLineInfoList.push_back(line_info(
+												line_start_index, 
+												last_segment_char_on_line, 
+												LLRect(text_left, 
+														cur_top, 
+														text_left + (text_width - remaining_pixels),
+														cur_top - line_height), 
+												line_count));
+
+					line_start_index = segment->getStart() + seg_offset;
+					cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels;
+					remaining_pixels = text_width;
+					line_height = 0;
+					line_count = next_line_count;
+				}
+				// ...just consumed last segment..
+				else if (++segment_set_t::iterator(seg_iter) == mSegments.end())
+				{
+					mLineInfoList.push_back(line_info(
+												line_start_index, 
+												last_segment_char_on_line, 
+												LLRect(text_left, 
+														cur_top, 
+														text_left + (text_width - remaining_pixels),
+														cur_top - line_height), 
+												line_count));
+					cur_top -= llround((F32)line_height * mLineSpacingMult) + mLineSpacingPixels;
+					break;
+				}
+				// finished a segment and there are segments remaining on this line
+				else
+				{
+					// subtract pixels used and increment segment
+					++seg_iter;
+					seg_offset = 0;
+				}
+			}
+		}
+
+		if (mLineInfoList.empty()) 
+		{
+			mContentsRect = LLRect(0, mVPad, mHPad, 0);
+		}
+		else
+		{
+
+			mContentsRect = mLineInfoList.begin()->mRect;
+			for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin();
+				line_iter != mLineInfoList.end();
+				++line_iter)
+			{
+				mContentsRect.unionWith(line_iter->mRect);
+			}
+
+			mContentsRect.mRight += mHPad;
+			mContentsRect.mTop += mVPad;
+			// get around rounding errors when clipping text against rectangle
+			mContentsRect.stretch(1);
+		}
+
+		// change mDocumentPanel document size to accomodate reflowed text
+		LLRect document_rect;
+		document_rect.setOriginAndSize(1, 1, 
+									mScroller->getContentWindowRect().getWidth(), 
+									llmax(mScroller->getContentWindowRect().getHeight(), mContentsRect.getHeight()));
+		mDocumentPanel->setShape(document_rect);
+
+		// after making document big enough to hold all the text, move the text to fit in the document
+		if (!mLineInfoList.empty())
+		{
+			S32 delta_pos = mDocumentPanel->getRect().getHeight() - mLineInfoList.begin()->mRect.mTop - mVPad;
+			// move line segments to fit new document rect
+			for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it)
+			{
+				it->mRect.translate(0, delta_pos);
+			}
+			mContentsRect.translate(0, delta_pos);
+		}
+
+		// calculate visible region for diplaying text
+		updateTextRect();
+
+		for (segment_set_t::iterator segment_it = mSegments.begin();
+			segment_it != mSegments.end();
+			++segment_it)
+		{
+			LLTextSegmentPtr segmentp = *segment_it;
+			segmentp->updateLayout(*this);
+
+		}
+
+		// apply scroll constraints after reflowing text
+		if (!hasMouseCapture())
+		{
+			LLRect visible_content_rect = mScroller->getVisibleContentRect();
+			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 = getLocalRectFromDocIndex(mCursorPos);
+				new_cursor_rect_doc.translate(visible_content_rect.mLeft, visible_content_rect.mBottom);
+				mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect);
+				//llassert_always(getLocalRectFromDocIndex(mCursorPos).mBottom == old_cursor_rect.mBottom);
+			}
+			else
+			{
+				// keep first line of text visible
+				LLRect new_first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
+				new_first_char_rect.translate(visible_content_rect.mLeft, visible_content_rect.mBottom);
+				mScroller->scrollToShowRect(new_first_char_rect, first_char_rect);
+				//llassert_always(getLocalRectFromDocIndex(mScrollIndex).mBottom == first_char_rect.mBottom);
+			}
+		}
+	}
+
+
+	// reset desired x cursor position
+	updateCursorXPos();
+}
+
+LLRect LLTextBase::getContentsRect()
+{
+	reflow();
+	return mContentsRect;
+}
+
+
+void LLTextBase::clearSegments()
+{
+	mSegments.clear();
+	createDefaultSegment();
+}
+
+S32 LLTextBase::getLineStart( S32 line ) const
+{
+	S32 num_lines = getLineCount();
+	if (num_lines == 0)
+    {
+		return 0;
+    }
+
+	line = llclamp(line, 0, num_lines-1);
+	return mLineInfoList[line].mDocIndexStart;
+}
+
+
+S32 LLTextBase::getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap) const
+{
+	if (mLineInfoList.empty())
+	{
+		return 0;
+	}
+	else
+	{
+		line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_index, line_end_compare());
+		if (include_wordwrap)
+		{
+			return iter - mLineInfoList.begin();
+		}
+		else
+		{
+			if (iter == mLineInfoList.end())
+			{
+				return mLineInfoList.back().mLineNum;
+			}
+			else
+			{
+				return iter->mLineNum;
+			}
+		}
+	}
+}
+
+// Given an offset into text (pos), find the corresponding line (from the start of the doc) and an offset into the line.
+S32 LLTextBase::getLineOffsetFromDocIndex( S32 startpos, bool include_wordwrap) const
+{
+	if (mLineInfoList.empty())
+	{
+		return startpos;
+	}
+	else
+	{
+		line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), startpos, line_end_compare());
+		return startpos - iter->mDocIndexStart;
+	}
+}
+
+S32	LLTextBase::getFirstVisibleLine() const
+{
+	LLRect visible_region = mScroller->getVisibleContentRect();
+
+	// binary search for line that starts before top of visible buffer
+	line_list_t::const_iterator iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
+
+	return iter - mLineInfoList.begin();
+}
+
+std::pair<S32, S32>	LLTextBase::getVisibleLines() const
+{
+	LLRect visible_region = mScroller->getVisibleContentRect();
+
+	// binary search for line that starts before top of visible buffer and starts before end of visible buffer
+	line_list_t::const_iterator first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
+	line_list_t::const_iterator last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top());
+
+	return std::pair<S32, S32>(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin());
+}
+
+
+
+LLTextViewModel* LLTextBase::getViewModel() const
+{
+	return (LLTextViewModel*)mViewModel.get();
+}
+
+void LLTextBase::addDocumentChild(LLView* view) 
+{ 
+	mDocumentPanel->addChild(view); 
+}
+
+void LLTextBase::removeDocumentChild(LLView* view) 
+{ 
+	mDocumentPanel->removeChild(view); 
+}
+
+
+static LLFastTimer::DeclareTimer FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments");
+void LLTextBase::updateSegments()
+{
+	LLFastTimer ft(FTM_UPDATE_TEXT_SEGMENTS);
+	createDefaultSegment();
+}
+
+void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const
+{
+	*seg_iter = getSegIterContaining(startpos);
+	if (*seg_iter == mSegments.end())
+	{
+		*offsetp = 0;
+	}
+	else
+	{
+		*offsetp = startpos - (**seg_iter)->getStart();
+	}
+}
+
+void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp )
+{
+	*seg_iter = getSegIterContaining(startpos);
+	if (*seg_iter == mSegments.end())
+	{
+		*offsetp = 0;
+	}
+	else
+	{
+		*offsetp = startpos - (**seg_iter)->getStart();
+	}
+}
+
+LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)
+{
+	segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index));
+	return it;
+}
+
+LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 index) const
+{
+	LLTextBase::segment_set_t::const_iterator it =  mSegments.upper_bound(new LLIndexSegment(index));
+	return it;
+}
+
+// Finds the text segment (if any) at the give local screen position
+LLTextSegmentPtr LLTextBase::getSegmentAtLocalPos( S32 x, S32 y )
+{
+	// Find the cursor position at the requested local screen position
+	S32 offset = getDocIndexFromLocalCoord( x, y, FALSE );
+	segment_set_t::iterator seg_iter = getSegIterContaining(offset);
+	if (seg_iter != mSegments.end())
+	{
+		return *seg_iter;
+	}
+	else
+	{
+		return LLTextSegmentPtr();
+	}
+}
+
+void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
+{
+	// work out the XUI menu file to use for this url
+	LLUrlMatch match;
+	std::string url = in_url;
+	if (! LLUrlRegistry::instance().findUrl(url, match))
+	{
+		return;
+	}
+	
+	std::string xui_file = match.getMenuName();
+	if (xui_file.empty())
+	{
+		return;
+	}
+
+	// set up the callbacks for all of the potential menu items, N.B. we
+	// don't use const ref strings in callbacks in case url goes out of scope
+	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+	registrar.add("Url.Open", boost::bind(&LLUrlAction::openURL, url));
+	registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url));
+	registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url));
+	registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url));
+	registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));
+	registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
+	registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));
+
+	// create and return the context menu from the XUI file
+	delete mPopupMenu;
+	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer,
+																		 LLMenuHolderGL::child_registry_t::instance());	
+	if (mPopupMenu)
+	{
+		mPopupMenu->show(x, y);
+		LLMenuGL::showPopup(this, mPopupMenu, x, y);
+	}
+}
+
+void LLTextBase::setText(const LLStringExplicit &utf8str)
+{
+	// clear out the existing text and segments
+	clear();
+
+	truncate();
+
+	createDefaultSegment();
+
+	startOfDoc();
+	deselect();
+
+	// append the new text (supports Url linking)
+	std::string text(utf8str);
+	LLStringUtil::removeCRLF(text);
+
+	appendText(text, false);
+
+	needsReflow();
+
+	//resetDirty();
+	onValueChange(0, getLength());
+}
+
+//virtual
+std::string LLTextBase::getText() const
+{
+	return getViewModel()->getValue().asString();
+}
+
+void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
+{
+	LLStyle::Params style_params(input_params);
+	style_params.fillFrom(getDefaultStyle());
+
+	if (!style_params.font.isProvided())
+	{
+		style_params.font = mDefaultFont;
+	}
+	if (!style_params.drop_shadow.isProvided())
+	{
+		style_params.drop_shadow = mFontShadow;
+	}
+
+	S32 part = (S32)LLTextParser::WHOLE;
+	if(mParseHTML)
+	{
+		S32 start=0,end=0;
+		LLUrlMatch match;
+		std::string text = new_text;
+		while ( LLUrlRegistry::instance().findUrl(text, match,
+		        boost::bind(&LLTextBase::replaceUrlLabel, this, _1, _2)) )
+		{
+			start = match.getStart();
+			end = match.getEnd()+1;
+
+			LLStyle::Params link_params = style_params;
+			link_params.color = match.getColor();
+			// apply font name from requested style_params
+			std::string font_name = LLFontGL::nameFromFont(style_params.font());
+			link_params.font.name.setIfNotProvided(font_name);
+			link_params.font.style = "UNDERLINE";
+			link_params.link_href = match.getUrl();
+
+			// output the text before the Url
+			if (start > 0)
+			{
+				if (part == (S32)LLTextParser::WHOLE ||
+					part == (S32)LLTextParser::START)
+				{
+					part = (S32)LLTextParser::START;
+				}
+				else
+				{
+					part = (S32)LLTextParser::MIDDLE;
+				}
+				std::string subtext=text.substr(0,start);
+				appendAndHighlightText(subtext, prepend_newline, part, style_params); 
+				prepend_newline = false;
+			}
+
+			// 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;
+					// HACK: fix spacing of images and remove the fixed char spacing
+					appendAndHighlightText("   ", prepend_newline, part, icon);
+					prepend_newline = false;
+				}
+			}
+			// output the styled Url
+			appendAndHighlightText(match.getLabel(), prepend_newline, part, link_params);
+			prepend_newline = false;
+
+			// set the tooltip for the Url label
+			if (! match.getTooltip().empty())
+			{
+				segment_set_t::iterator it = getSegIterContaining(getLength()-1);
+				if (it != mSegments.end())
+				{
+					LLTextSegmentPtr segment = *it;
+					segment->setToolTip(match.getTooltip());
+				}
+			}
+
+			// move on to the rest of the text after the Url
+			if (end < (S32)text.length()) 
+			{
+				text = text.substr(end,text.length() - end);
+				end=0;
+				part=(S32)LLTextParser::END;
+			}
+			else
+			{
+				break;
+			}
+		}
+		if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END;
+		if (end < (S32)text.length()) appendAndHighlightText(text, prepend_newline, part, style_params);		
+	}
+	else
+	{
+		appendAndHighlightText(new_text, prepend_newline, part, style_params);
+	}
+}
+
+void LLTextBase::appendAndHighlightText(const std::string &new_text, bool prepend_newline, S32 highlight_part, const LLStyle::Params& stylep)
+{
+	if (new_text.empty()) return;
+
+	// Save old state
+	S32 selection_start = mSelectionStart;
+	S32 selection_end = mSelectionEnd;
+	BOOL was_selecting = mIsSelecting;
+	S32 cursor_pos = mCursorPos;
+	S32 old_length = getLength();
+	BOOL cursor_was_at_end = (mCursorPos == old_length);
+
+	deselect();
+
+	setCursorPos(old_length);
+
+	LLTextParser* highlight = LLTextParser::getInstance();
+	
+	if (mParseHighlights && highlight)
+	{
+		LLStyle::Params highlight_params = stylep;
+
+		LLSD pieces = highlight->parsePartialLineHighlights(new_text, highlight_params.color(), (LLTextParser::EHighlightPosition)highlight_part);
+		for (S32 i = 0; i < pieces.size(); i++)
+		{
+			LLSD color_llsd = pieces[i]["color"];
+			LLColor4 lcolor;
+			lcolor.setValue(color_llsd);
+			highlight_params.color = lcolor;
+
+			LLWString wide_text;
+			if (prepend_newline && (i == 0 || pieces.size() <= 1 )) 
+			{
+				wide_text = utf8str_to_wstring(std::string("\n") + pieces[i]["text"].asString());
+			}
+			else
+			{
+				wide_text = utf8str_to_wstring(pieces[i]["text"].asString());
+			}
+			S32 cur_length = getLength();
+			LLTextSegmentPtr segmentp = new LLNormalTextSegment(new LLStyle(highlight_params), cur_length, cur_length + wide_text.size(), *this);
+			segment_vec_t segments;
+			segments.push_back(segmentp);
+			insertStringNoUndo(cur_length, wide_text, &segments);
+		}
+	}
+	else
+	{
+		LLWString wide_text;
+
+		// Add carriage return if not first line
+		if (getLength() != 0
+			&& prepend_newline)
+		{
+			wide_text = utf8str_to_wstring(std::string("\n") + new_text);
+		}
+		else
+		{
+			wide_text = utf8str_to_wstring(new_text);
+		}
+
+		segment_vec_t segments;
+		S32 segment_start = old_length;
+		S32 segment_end = old_length + wide_text.size();
+		segments.push_back(new LLNormalTextSegment(new LLStyle(stylep), segment_start, segment_end, *this ));
+
+		insertStringNoUndo(getLength(), wide_text, &segments);
+	}
+
+	needsReflow();
+	
+	// Set the cursor and scroll position
+	if( selection_start != selection_end )
+	{
+		mSelectionStart = selection_start;
+		mSelectionEnd = selection_end;
+
+		mIsSelecting = was_selecting;
+		setCursorPos(cursor_pos);
+	}
+	else if( cursor_was_at_end )
+	{
+		setCursorPos(getLength());
+	}
+	else
+	{
+		setCursorPos(cursor_pos);
+	}
+
+	//if( !allow_undo )
+	//{
+	//	blockUndo();
+	//}
+}
+
+
+void LLTextBase::replaceUrlLabel(const std::string &url,
+								   const std::string &label)
+{
+	// get the full (wide) text for the editor so we can change it
+	LLWString text = getWText();
+	LLWString wlabel = utf8str_to_wstring(label);
+	bool modified = false;
+	S32 seg_start = 0;
+
+	// iterate through each segment looking for ones styled as links
+	segment_set_t::iterator it;
+	for (it = mSegments.begin(); it != mSegments.end(); ++it)
+	{
+		LLTextSegment *seg = *it;
+		const LLStyleSP style = seg->getStyle();
+
+		// update segment start/end length in case we replaced text earlier
+		S32 seg_length = seg->getEnd() - seg->getStart();
+		seg->setStart(seg_start);
+		seg->setEnd(seg_start + seg_length);
+
+		// if we find a link with our Url, then replace the label
+		if (style->isLink() && style->getLinkHREF() == url)
+		{
+			S32 start = seg->getStart();
+			S32 end = seg->getEnd();
+			text = text.substr(0, start) + wlabel + text.substr(end, text.size() - end + 1);
+			seg->setEnd(start + wlabel.size());
+			modified = true;
+		}
+
+		// work out the character offset for the next segment
+		seg_start = seg->getEnd();
+	}
+
+	// update the editor with the new (wide) text string
+	if (modified)
+	{
+		getViewModel()->setDisplay(text);
+		deselect();
+		setCursorPos(mCursorPos);
+		needsReflow();
+	}
+}
+
+
+void LLTextBase::setWText(const LLWString& text)
+{
+	setText(wstring_to_utf8str(text));
+}
+
+LLWString LLTextBase::getWText() const
+{
+    return getViewModel()->getDisplay();
+}
+
+// If round is true, if the position is on the right half of a character, the cursor
+// will be put to its right.  If round is false, the cursor will always be put to the
+// character's left.
+
+S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const
+{
+	// Figure out which line we're nearest to.
+	LLRect visible_region = mScroller->getVisibleContentRect();
+
+	// binary search for line that starts before local_y
+	line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mTextRect.mBottom + visible_region.mBottom, compare_bottom());
+
+	if (line_iter == mLineInfoList.end())
+	{
+		return getLength(); // past the end
+	}
+	
+	S32 pos = getLength();
+	S32 start_x = mTextRect.mLeft + line_iter->mRect.mLeft;
+
+	segment_set_t::iterator line_seg_iter;
+	S32 line_seg_offset;
+	for(getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
+		line_seg_iter != mSegments.end(); 
+		++line_seg_iter, line_seg_offset = 0)
+	{
+		const LLTextSegmentPtr segmentp = *line_seg_iter;
+
+		S32 segment_line_start = segmentp->getStart() + line_seg_offset;
+		S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd - 1) - segment_line_start;
+		S32 text_width = segmentp->getWidth(line_seg_offset, segment_line_length);
+		if (local_x < start_x + text_width						// cursor to left of right edge of text
+			|| segmentp->getEnd() >= line_iter->mDocIndexEnd - 1)	// or this segment wraps to next line
+		{
+			// Figure out which character we're nearest to.
+			S32 offset;
+			if (!segmentp->canEdit())
+			{
+				S32 segment_width = segmentp->getWidth(0, segmentp->getEnd() - segmentp->getStart());
+				if (round && local_x - start_x > segment_width / 2)
+				{
+					offset = segment_line_length;
+				}
+				else
+				{
+					offset = 0;
+				}
+			}
+			else
+			{
+				offset = segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round);
+			}
+			pos = segment_line_start + offset;
+			break;
+		}
+		start_x += text_width;
+	}
+
+	return pos;
+}
 
-#include <boost/bind.hpp>
+LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
+{
+	LLRect local_rect;
+	if (mLineInfoList.empty()) 
+	{ 
+		local_rect = mTextRect;
+		local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight());
+		return local_rect;
+	}
 
-// global state for all text fields
-LLUIColor LLTextBase::mLinkColor = LLColor4::blue;
+	// clamp pos to valid values
+	pos = llclamp(pos, 0, mLineInfoList.back().mDocIndexEnd - 1);
 
-bool LLTextBase::compare_segment_end::operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const
+
+	// find line that contains cursor
+	line_list_t::const_iterator line_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), pos, line_end_compare());
+
+	LLRect scrolled_view_rect = mScroller->getVisibleContentRect();
+	local_rect.mLeft = mTextRect.mLeft - scrolled_view_rect.mLeft + line_iter->mRect.mLeft; 
+	local_rect.mBottom = mTextRect.mBottom + (line_iter->mRect.mBottom - scrolled_view_rect.mBottom);
+	local_rect.mTop = mTextRect.mBottom + (line_iter->mRect.mTop - scrolled_view_rect.mBottom);
+
+	segment_set_t::iterator line_seg_iter;
+	S32 line_seg_offset;
+	segment_set_t::iterator cursor_seg_iter;
+	S32 cursor_seg_offset;
+	getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
+	getSegmentAndOffset(pos, &cursor_seg_iter, &cursor_seg_offset);
+
+	while(line_seg_iter != mSegments.end())
+	{
+		const LLTextSegmentPtr segmentp = *line_seg_iter;
+
+		if (line_seg_iter == cursor_seg_iter)
+		{
+			// cursor advanced to right based on difference in offset of cursor to start of line
+			local_rect.mLeft += segmentp->getWidth(line_seg_offset, cursor_seg_offset - line_seg_offset);
+
+			break;
+		}
+		else
+		{
+			// add remainder of current text segment to cursor position
+			local_rect.mLeft += segmentp->getWidth(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset);
+			// offset will be 0 for all segments after the first
+			line_seg_offset = 0;
+			// go to next text segment on this line
+			++line_seg_iter;
+		}
+	}
+
+	local_rect.mRight = local_rect.mLeft; 
+
+	return local_rect;
+}
+
+void LLTextBase::updateCursorXPos()
 {
-	return a->getEnd() < b->getEnd();
+	// reset desired x cursor position
+	mDesiredXPixel = getLocalRectFromDocIndex(mCursorPos).mLeft;
+}
+
+
+void LLTextBase::startOfLine()
+{
+	S32 offset = getLineOffsetFromDocIndex(mCursorPos);
+	setCursorPos(mCursorPos - offset);
+}
+
+void LLTextBase::endOfLine()
+{
+	S32 line = getLineNumFromDocIndex(mCursorPos);
+	S32 num_lines = getLineCount();
+	if (line + 1 >= num_lines)
+	{
+		setCursorPos(getLength());
+	}
+	else
+	{
+		setCursorPos( getLineStart(line + 1) - 1 );
+	}
+}
+
+void LLTextBase::startOfDoc()
+{
+	setCursorPos(0);
+}
+
+void LLTextBase::endOfDoc()
+{
+	setCursorPos(getLength());
+}
+
+void LLTextBase::changePage( S32 delta )
+{
+	const S32 PIXEL_OVERLAP_ON_PAGE_CHANGE = 10;
+	if (delta == 0) return;
+
+	LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos);
+
+	if( delta == -1 )
+	{
+		mScroller->pageUp(PIXEL_OVERLAP_ON_PAGE_CHANGE);
+	}
+	else
+	if( delta == 1 )
+	{
+		mScroller->pageDown(PIXEL_OVERLAP_ON_PAGE_CHANGE);
+	}
+
+	if (getLocalRectFromDocIndex(mCursorPos) == cursor_rect)
+	{
+		// cursor didn't change apparent position, so move to top or bottom of document, respectively
+		if (delta < 0)
+		{
+			startOfDoc();
+		}
+		else
+		{
+			endOfDoc();
+		}
+	}
+	else
+	{
+		setCursorAtLocalPos(cursor_rect.getCenterX(), cursor_rect.getCenterY(), true, false);
+	}
+}
+
+// Picks a new cursor position based on the screen size of text being drawn.
+void LLTextBase::setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset )
+{
+	setCursorPos(getDocIndexFromLocalCoord(local_x, local_y, round), keep_cursor_offset);
+}
+
+
+void LLTextBase::changeLine( S32 delta )
+{
+	S32 line = getLineNumFromDocIndex(mCursorPos);
+
+	S32 new_line = line;
+	if( (delta < 0) && (line > 0 ) )
+	{
+		new_line = line - 1;
+	}
+	else if( (delta > 0) && (line < (getLineCount() - 1)) )
+	{
+		new_line = line + 1;
+	}
+
+	LLRect visible_region = mScroller->getVisibleContentRect();
+
+	S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, mLineInfoList[new_line].mRect.mBottom + mTextRect.mBottom - visible_region.mBottom, TRUE);
+	setCursorPos(new_cursor_pos, true);
+}
+
+
+bool LLTextBase::setCursor(S32 row, S32 column)
+{
+	if (0 <= row && row < (S32)mLineInfoList.size())
+	{
+		S32 doc_pos = mLineInfoList[row].mDocIndexStart;
+		column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1);
+		doc_pos += column;
+		updateCursorXPos();
+
+		return setCursorPos(doc_pos);
+	}
+	return false;
+}
+
+
+bool LLTextBase::setCursorPos(S32 cursor_pos, bool keep_cursor_offset)
+{
+	S32 new_cursor_pos = cursor_pos;
+	if (new_cursor_pos != mCursorPos)
+	{
+		new_cursor_pos = getEditableIndex(new_cursor_pos, new_cursor_pos >= mCursorPos);
+	}
+
+	mCursorPos = llclamp(new_cursor_pos, 0, (S32)getLength());
+	needsScroll();
+	if (!keep_cursor_offset)
+		updateCursorXPos();
+	// did we get requested position?
+	return new_cursor_pos == cursor_pos;
+}
+
+// constraint cursor to editable segments of document
+S32 LLTextBase::getEditableIndex(S32 index, bool increasing_direction)
+{
+	segment_set_t::iterator segment_iter;
+	S32 offset;
+	getSegmentAndOffset(index, &segment_iter, &offset);
+	if (segment_iter == mSegments.end())
+	{
+		return 0;
+	}
+
+	LLTextSegmentPtr segmentp = *segment_iter;
+
+	if (segmentp->canEdit()) 
+	{
+		return segmentp->getStart() + offset;			
+	}
+	else if (segmentp->getStart() < index && index < segmentp->getEnd())
+	{
+		// bias towards document end
+		if (increasing_direction)
+		{
+			return segmentp->getEnd();
+		}
+		// bias towards document start
+		else
+		{
+			return segmentp->getStart();
+		}
+	}
+	else
+	{
+		return index;
+	}
+}
+
+void LLTextBase::updateTextRect()
+{
+	LLRect old_text_rect = mTextRect;
+	mTextRect = mScroller->getContentWindowRect();
+	//FIXME: replace border with image?
+	if (mBorderVisible)
+	{
+		mTextRect.stretch(-1);
+	}
+	mTextRect.mLeft += mHPad;
+	mTextRect.mTop -= mVPad;
+	if (mTextRect != old_text_rect)
+	{
+		needsReflow();
+	}
+}
+
+
+void LLTextBase::startSelection()
+{
+	if( !mIsSelecting )
+	{
+		mIsSelecting = TRUE;
+		mSelectionStart = mCursorPos;
+		mSelectionEnd = mCursorPos;
+	}
+}
+
+void LLTextBase::endSelection()
+{
+	if( mIsSelecting )
+	{
+		mIsSelecting = FALSE;
+		mSelectionEnd = mCursorPos;
+	}
 }
 
 //
@@ -69,17 +2055,29 @@ S32	LLTextSegment::getMaxHeight() const { return 0; }
 bool LLTextSegment::canEdit() const { return false; }
 void LLTextSegment::unlinkFromDocument(LLTextBase*) {}
 void LLTextSegment::linkToDocument(LLTextBase*) {}
-void LLTextSegment::setHasMouseHover(bool hover) {}
 const LLColor4& LLTextSegment::getColor() const { return LLColor4::white; }
 void LLTextSegment::setColor(const LLColor4 &color) {}
 const LLStyleSP LLTextSegment::getStyle() const {static LLStyleSP sp(new LLStyle()); return sp; }
 void LLTextSegment::setStyle(const LLStyleSP &style) {}
 void LLTextSegment::setToken( LLKeywordToken* token ) {}
 LLKeywordToken*	LLTextSegment::getToken() const { return NULL; }
-BOOL LLTextSegment::getToolTip( std::string& msg ) const { return FALSE; }
 void LLTextSegment::setToolTip( const std::string &msg ) {}
 void LLTextSegment::dump() const {}
-
+BOOL LLTextSegment::handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleMiddleMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleRightMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleHover(S32 x, S32 y, MASK mask) { return FALSE; }
+BOOL LLTextSegment::handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }
+BOOL LLTextSegment::handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; }
+std::string	LLTextSegment::getName() const { return ""; }
+void LLTextSegment::onMouseCaptureLost() {}
+void LLTextSegment::screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const {}
+void LLTextSegment::localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const {}
+BOOL LLTextSegment::hasMouseCapture() { return FALSE; }
 
 //
 // LLNormalTextSegment
@@ -89,7 +2087,6 @@ LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32
 :	LLTextSegment(start, end),
 	mStyle( style ),
 	mToken(NULL),
-	mHasMouseHover(false),
 	mEditor(editor)
 {
 	mMaxHeight = llceil(mStyle->getFont()->getLineHeight());
@@ -98,7 +2095,6 @@ LLNormalTextSegment::LLNormalTextSegment( const LLStyleSP& style, S32 start, S32
 LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) 
 :	LLTextSegment(start, end),
 	mToken(NULL),
-	mHasMouseHover(false),
 	mEditor(editor)
 {
 	mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color));
@@ -115,21 +2111,25 @@ F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selec
 			LLUIImagePtr image = mStyle->getImage();
 			S32 style_image_height = image->getHeight();
 			S32 style_image_width = image->getWidth();
-			image->draw(draw_rect.mLeft, draw_rect.mTop-style_image_height, 
+			// Center the image vertically
+			S32 image_bottom = draw_rect.getCenterY() - (style_image_height/2);
+			image->draw(draw_rect.mLeft, image_bottom, 
 				style_image_width, style_image_height);
 		}
 
-		return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect.mLeft, draw_rect.mBottom);
+		return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect);
 	}
 	return draw_rect.mLeft;
 }
 
 // Draws a single text segment, reversing the color for selection if needed.
-F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, F32 x, F32 y)
+F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRect rect)
 {
+	F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha;
+
 	const LLWString &text = mEditor.getWText();
 
-	F32 right_x = x;
+	F32 right_x = rect.mLeft;
 	if (!mStyle->isVisible())
 	{
 		return right_x;
@@ -137,7 +2137,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
 
 	const LLFontGL* font = mStyle->getFont();
 
-	LLColor4 color = mStyle->getColor();
+	LLColor4 color = mStyle->getColor() % alpha;
 
 	font = mStyle->getFont();
 
@@ -147,9 +2147,9 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
 		S32 start = seg_start;
 		S32 end = llmin( selection_start, seg_end );
 		S32 length =  end - start;
-		font->render(text, start, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems());
+		font->render(text, start, rect.mLeft, rect.mTop, color, LLFontGL::LEFT, LLFontGL::TOP, 0, mStyle->getShadowType(), length, rect.getWidth(), &right_x, mEditor.getUseEllipses());
 	}
-	x = right_x;
+	rect.mLeft = (S32)ceil(right_x);
 	
 	if( (selection_start < seg_end) && (selection_end > seg_start) )
 	{
@@ -158,18 +2158,18 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
 		S32 end = llmin( selection_end, seg_end );
 		S32 length = end - start;
 
-		font->render(text, start, x, y,
+		font->render(text, start, rect.mLeft, rect.mTop,
 					 LLColor4( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], 1.f ),
-					 LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems());
+					 LLFontGL::LEFT, LLFontGL::TOP, 0, LLFontGL::NO_SHADOW, length, rect.mRight, &right_x, mEditor.getUseEllipses());
 	}
-	x = right_x;
+	rect.mLeft = (S32)ceil(right_x);
 	if( selection_end < seg_end )
 	{
 		// Draw normally
 		S32 start = llmax( selection_end, seg_start );
 		S32 end = seg_end;
 		S32 length = end - start;
-		font->render(text, start, x, y, color, LLFontGL::LEFT, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, length, S32_MAX, &right_x, mEditor.allowsEmbeddedItems());
+		font->render(text, start, rect.mLeft, rect.mTop, color, LLFontGL::LEFT, LLFontGL::TOP, 0, mStyle->getShadowType(), length, rect.mRight, &right_x, mEditor.getUseEllipses());
 	}
 	return right_x;
 }
@@ -179,21 +2179,54 @@ S32	LLNormalTextSegment::getMaxHeight() const
 	return mMaxHeight; 
 }
 
-BOOL LLNormalTextSegment::getToolTip(std::string& msg) const
+BOOL LLNormalTextSegment::handleHover(S32 x, S32 y, MASK mask)
+{
+	if (getStyle() && getStyle()->isLink())
+	{
+		LLUI::getWindow()->setCursor(UI_CURSOR_HAND);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+BOOL LLNormalTextSegment::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+	if (getStyle() && getStyle()->isLink())
+	{
+		mEditor.createUrlContextMenu(x, y, getStyle()->getLinkHREF());
+		return TRUE;
+	}
+	return FALSE;
+}
+
+BOOL LLNormalTextSegment::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+	if (getStyle() && getStyle()->isLink())
+	{
+		LLUrlAction::clickAction(getStyle()->getLinkHREF());
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+BOOL LLNormalTextSegment::handleToolTip(S32 x, S32 y, MASK mask)
 {
+	std::string msg;
 	// do we have a tooltip for a loaded keyword (for script editor)?
 	if (mToken && !mToken->getToolTip().empty())
 	{
 		const LLWString& wmsg = mToken->getToolTip();
-		msg = wstring_to_utf8str(wmsg);
+		LLToolTipMgr::instance().show(wstring_to_utf8str(wmsg));
 		return TRUE;
 	}
 	// or do we have an explicitly set tooltip (e.g., for Urls)
-	if (! mTooltip.empty())
+	if (!mTooltip.empty())
 	{
-		msg = mTooltip;
+		LLToolTipMgr::instance().show(mTooltip);
 		return TRUE;
 	}
+
 	return FALSE;
 }
 
@@ -258,201 +2291,69 @@ void LLNormalTextSegment::dump() const
 		llendl;
 }
 
-//////////////////////////////////////////////////////////////////////////
+
 //
-// LLTextBase
+// LLInlineViewSegment
 //
 
-LLTextBase::LLTextBase(const LLUICtrl::Params &p) :
-	mHoverSegment(NULL),
-	mDefaultFont(p.font),
-	mParseHTML(TRUE),
-	mPopupMenu(NULL)
-{
-}
-
-LLTextBase::~LLTextBase()
-{
-	clearSegments();
-}
-
-void LLTextBase::clearSegments()
-{
-	setHoverSegment(NULL);
-	mSegments.clear();
-}
-
-void LLTextBase::setHoverSegment(LLTextSegmentPtr segment)
+LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end)
+:	LLTextSegment(start, end),
+	mView(view)
 {
-	if (mHoverSegment)
-	{
-		mHoverSegment->setHasMouseHover(false);
-	}
-	if (segment)
-	{
-		segment->setHasMouseHover(true);
-	}
-	mHoverSegment = segment;
-}
+} 
 
-void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const
+LLInlineViewSegment::~LLInlineViewSegment()
 {
-	*seg_iter = getSegIterContaining(startpos);
-	if (*seg_iter == mSegments.end())
-	{
-		*offsetp = 0;
-	}
-	else
-	{
-		*offsetp = startpos - (**seg_iter)->getStart();
-	}
+	mView->die();
 }
 
-void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp )
+S32	LLInlineViewSegment::getWidth(S32 first_char, S32 num_chars) const
 {
-	*seg_iter = getSegIterContaining(startpos);
-	if (*seg_iter == mSegments.end())
+	if (first_char == 0 && num_chars == 0) 
 	{
-		*offsetp = 0;
+		return 0;
 	}
 	else
 	{
-		*offsetp = startpos - (**seg_iter)->getStart();
+		return mView->getRect().getWidth();
 	}
 }
 
-LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)
-{
-	segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index));
-	return it;
-}
-
-LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 index) const
-{
-	LLTextBase::segment_set_t::const_iterator it =  mSegments.upper_bound(new LLIndexSegment(index));
-	return it;
-}
-
-// Finds the text segment (if any) at the give local screen position
-LLTextSegmentPtr LLTextBase::getSegmentAtLocalPos( S32 x, S32 y )
+S32	LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
 {
-	// Find the cursor position at the requested local screen position
-	S32 offset = getDocIndexFromLocalCoord( x, y, FALSE );
-	segment_set_t::iterator seg_iter = getSegIterContaining(offset);
-	if (seg_iter != mSegments.end())
+	if (line_offset != 0 && num_pixels < mView->getRect().getWidth()) 
 	{
-		return *seg_iter;
+		return 0;
 	}
 	else
 	{
-		return LLTextSegmentPtr();
+		return mEnd - mStart;
 	}
 }
 
-BOOL LLTextBase::handleHoverOverUrl(S32 x, S32 y)
+void LLInlineViewSegment::updateLayout(const LLTextBase& editor)
 {
-	setHoverSegment(NULL);
-
-	// Check to see if we're over an HTML-style link
-	LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
-	if (cur_segment)
-	{
-		setHoverSegment(cur_segment);
-
-		LLStyleSP style =  cur_segment->getStyle();
-		if (style && style->isLink())
-		{
-			return TRUE;
-		}
-	}
-
-	return FALSE;
+	LLRect start_rect = editor.getLocalRectFromDocIndex(mStart);
+	LLRect doc_rect = editor.getDocumentPanel()->getRect();
+	mView->setOrigin(doc_rect.mLeft + start_rect.mLeft, doc_rect.mBottom + start_rect.mBottom);
 }
 
-BOOL LLTextBase::handleMouseUpOverUrl(S32 x, S32 y)
+F32	LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
 {
-	if (mParseHTML && mHoverSegment)
-	{
-		LLStyleSP style = mHoverSegment->getStyle();
-		if (style && style->isLink())
-		{
-			LLUrlAction::clickAction(style->getLinkHREF());
-			return TRUE;
-		}
-	}
-
-	return FALSE;
+	return (F32)(draw_rect.mLeft + mView->getRect().getWidth());
 }
 
-BOOL LLTextBase::handleRightMouseDownOverUrl(LLView *view, S32 x, S32 y)
+S32	LLInlineViewSegment::getMaxHeight() const
 {
-	// pop up a context menu for any Url under the cursor
-	const LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y);
-	if (cur_segment && cur_segment->getStyle() && cur_segment->getStyle()->isLink())
-	{
-		delete mPopupMenu;
-		mPopupMenu = createUrlContextMenu(cur_segment->getStyle()->getLinkHREF());
-		if (mPopupMenu)
-		{
-			mPopupMenu->show(x, y);
-			LLMenuGL::showPopup(view, mPopupMenu, x, y);
-			return TRUE;
-		}
-	}
-
-	return FALSE;
+	return mView->getRect().getHeight();
 }
 
-BOOL LLTextBase::handleToolTipForUrl(LLView *view, S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor)
 {
-	std::string tooltip_msg;
-	const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
-	if (cur_segment && cur_segment->getToolTip( tooltip_msg ) && view)
-	{
-		// Use a slop area around the cursor
-		const S32 SLOP = 8;
-		// Convert rect local to screen coordinates
-		view->localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect_screen.mLeft),
-								 &(sticky_rect_screen.mBottom));
-		sticky_rect_screen.mRight = sticky_rect_screen.mLeft + 2 * SLOP;
-		sticky_rect_screen.mTop = sticky_rect_screen.mBottom + 2 * SLOP;
-
-		LLToolTipMgr::instance().show(LLToolTipParams()
-			.message(tooltip_msg)
-			.sticky_rect(sticky_rect_screen));
-		return TRUE;
-	}
-	return FALSE;
+	editor->removeDocumentChild(mView);
 }
 
-LLContextMenu *LLTextBase::createUrlContextMenu(const std::string &in_url)
+void LLInlineViewSegment::linkToDocument(LLTextBase* editor)
 {
-	// work out the XUI menu file to use for this url
-	LLUrlMatch match;
-	std::string url = in_url;
-	if (! LLUrlRegistry::instance().findUrl(url, match))
-	{
-		return NULL;
-	}
-	
-	std::string xui_file = match.getMenuName();
-	if (xui_file.empty())
-	{
-		return NULL;
-	}
-
-	// set up the callbacks for all of the potential menu items, N.B. we
-	// don't use const ref strings in callbacks in case url goes out of scope
-	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
-	registrar.add("Url.Open", boost::bind(&LLUrlAction::openURL, url));
-	registrar.add("Url.OpenInternal", boost::bind(&LLUrlAction::openURLInternal, url));
-	registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url));
-	registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url));
-	registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));
-	registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
-	registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));
-
-	// create and return the context menu from the XUI file
-	return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer,
-																		 LLMenuHolderGL::child_registry_t::instance());	
+	editor->addDocumentChild(mView);
 }
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 82b9f6a43fa..d0287a99ca5 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -35,13 +35,16 @@
 #define LL_LLTEXTBASE_H
 
 #include "v4color.h"
+#include "lleditmenuhandler.h"
 #include "llstyle.h"
 #include "llkeywords.h"
-#include "lluictrl.h"
+#include "llpanel.h"
 
 #include <string>
 #include <set>
 
+#include <boost/signals2.hpp>
+
 class LLContextMenu;
 class LLTextSegment;
 
@@ -52,64 +55,307 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
 /// as LLTextEditor and LLTextBox. It implements shared functionality
 /// such as Url highlighting and opening.
 ///
-class LLTextBase
+class LLTextBase 
+:	public LLUICtrl,
+	protected LLEditMenuHandler
 {
 public:
-	LLTextBase(const LLUICtrl::Params &p);
-	virtual ~LLTextBase();
+	struct LineSpacingParams : public LLInitParam::Choice<LineSpacingParams>
+	{
+		Alternative<F32>	multiple;
+		Alternative<S32>	pixels;
+		LineSpacingParams();
+	};
+
+	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	{
+		Optional<LLUIColor>		cursor_color,
+								text_color,
+								text_readonly_color,
+								bg_readonly_color,
+								bg_writeable_color,
+								bg_focus_color;
+
+		Optional<bool>			bg_visible,
+								border_visible,
+								track_end,
+								read_only,
+								hide_scrollbar,
+								clip_to_rect,
+								wrap,
+								use_ellipses,
+								allow_html,
+								parse_highlights;
+								
+		Optional<S32>			v_pad,
+								h_pad;
+
+		Optional<LineSpacingParams>
+								line_spacing;
+
+		Optional<S32>			max_text_length;
+
+		Optional<LLFontGL::ShadowType>	font_shadow;
+
+		Params();
+	};
+
+	// 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);
+
+	// LLView interface
+	/*virtual*/ void		reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
+	/*virtual*/ void		draw();
+
+	// LLUICtrl interface
+	/*virtual*/ BOOL		acceptsTextInput() const { return !mReadOnly; }
+	/*virtual*/ void		clear();
+	/*virtual*/ void		setColor( const LLColor4& c );
+	/*virtual*/ void		setValue(const LLSD& value );
+	/*virtual*/ LLTextViewModel* getViewModel() const;
+
+	// LLEditMenuHandler interface
+	/*virtual*/ void		deselect();
 
-	/// specify the color to display Url hyperlinks in the text
-	static void setLinkColor(LLColor4 color) { mLinkColor = color; }
+	// used by LLTextSegment layout code
+	bool					getWordWrap() { return mWordWrap; }
+	bool					getUseEllipses() { return mUseEllipses; }
+	bool					truncate(); // returns true of truncation occurred
 
-	/// enable/disable the automatic hyperlinking of Urls in the text
-	void        setParseHTML(BOOL parsing) { mParseHTML=parsing; }
+	// TODO: move into LLTextSegment?
+	void					createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url
 
-	// public text editing virtual methods
-	virtual LLWString getWText() const = 0;
-	virtual BOOL      allowsEmbeddedItems() const { return FALSE; }
-	virtual BOOL      getWordWrap() { return mWordWrap; }
-	virtual S32       getLength() const = 0;
+
+	// Text accessors
+	// TODO: add optional style parameter
+	virtual void			setText(const LLStringExplicit &utf8str); // uses default style
+	virtual std::string		getText() const;
+
+	// wide-char versions
+	void					setWText(const LLWString& text);
+	LLWString       		getWText() const;
+
+	void					appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params());
+
+	S32						getLength() const { return getWText().length(); }
+	S32						getLineCount() const { return mLineInfoList.size(); }
+
+	class DocumentPanel : public LLPanel
+	{
+	public:
+		DocumentPanel(const Params&);
+	};
+	void					addDocumentChild(LLView* view);
+	void					removeDocumentChild(LLView* view);
+	const DocumentPanel*	getDocumentPanel() const { return mDocumentPanel; }
+	LLRect					getTextRect() { return mTextRect; }
+	LLRect					getContentsRect();
+
+	S32						getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const;
+	LLRect					getLocalRectFromDocIndex(S32 pos) const;
+
+	void					setReadOnly(bool read_only) { mReadOnly = read_only; }
+	bool					getReadOnly() { return mReadOnly; }
+
+	// cursor manipulation
+	bool					setCursor(S32 row, S32 column);
+	bool					setCursorPos(S32 cursor_pos, bool keep_cursor_offset = false);
+	void					startOfLine();
+	void					endOfLine();
+	void					startOfDoc();
+	void					endOfDoc();
+	void					changePage( S32 delta );
+	void					changeLine( S32 delta );
+
+	const LLFontGL*			getDefaultFont() const					{ return mDefaultFont; }
+
+public:
+	// Fired when a URL link is clicked
+	commit_signal_t mURLClickSignal;
 
 protected:
+	// helper structs
+	struct compare_bottom;
+	struct compare_top;
+	struct line_end_compare;
+	typedef std::vector<LLTextSegmentPtr> segment_vec_t;
+
+	// Abstract inner base class representing an undoable editor command.
+	// Concrete sub-classes can be defined for operations such as insert, remove, etc.
+	// Used as arguments to the execute() method below.
+	class TextCmd
+	{
+	public:
+		TextCmd( S32 pos, BOOL group_with_next, LLTextSegmentPtr segment = LLTextSegmentPtr() ) 
+		:	mPos(pos), 
+			mGroupWithNext(group_with_next)
+		{
+			if (segment.notNull())
+			{
+				mSegments.push_back(segment);
+			}
+		}
+		virtual			~TextCmd() {}
+		virtual BOOL	execute(LLTextBase* editor, S32* delta) = 0;
+		virtual S32		undo(LLTextBase* editor) = 0;
+		virtual S32		redo(LLTextBase* editor) = 0;
+		virtual BOOL	canExtend(S32 pos) const { return FALSE; }
+		virtual void	blockExtensions() {}
+		virtual BOOL	extendAndExecute( LLTextBase* editor, S32 pos, llwchar c, S32* delta ) { llassert(0); return 0; }
+		virtual BOOL	hasExtCharValue( llwchar value ) const { return FALSE; }
+
+		// Defined here so they can access protected LLTextEditor editing methods
+		S32				insert(LLTextBase* editor, S32 pos, const LLWString &wstr) { return editor->insertStringNoUndo( pos, wstr, &mSegments ); }
+		S32 			remove(LLTextBase* editor, S32 pos, S32 length) { return editor->removeStringNoUndo( pos, length ); }
+		S32				overwrite(LLTextBase* editor, S32 pos, llwchar wc) { return editor->overwriteCharNoUndo(pos, wc); }
+		
+		S32				getPosition() const { return mPos; }
+		BOOL			groupWithNext() const { return mGroupWithNext; }
+		
+	protected:
+		const S32			mPos;
+		BOOL				mGroupWithNext;
+		segment_vec_t		mSegments;
+	};
+
 	struct compare_segment_end
 	{
 		bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const;
 	};
 	typedef std::multiset<LLTextSegmentPtr, compare_segment_end> segment_set_t;
 
-	// routines to manage segments 
-	void                getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const;
-	void                getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp );
-	LLTextSegmentPtr    getSegmentAtLocalPos( S32 x, S32 y );
+	// protected member variables
+	// List of offsets and segment index of the start of each line.  Always has at least one node (0).
+	struct line_info
+	{
+		line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num);
+		S32 mDocIndexStart;
+		S32 mDocIndexEnd;
+		LLRect mRect;
+		S32 mLineNum; // actual line count (ignoring soft newlines due to word wrap)
+	};
+	typedef std::vector<line_info> line_list_t;
+
+	// member functions
+	LLTextBase(const Params &p);
+	virtual ~LLTextBase();
+	void							initFromParams(const Params& p);
+	LLStyle::Params					getDefaultStyle();
+	virtual void					onValueChange(S32 start, S32 end);
+
+	// draw methods
+	void							drawSelectionBackground(); // draws the black box behind the selected text
+	void							drawCursor();
+	void							drawText();
+
+	// modify contents
+	S32								insertStringNoUndo(S32 pos, const LLWString &wstr, segment_vec_t* segments = NULL); // returns num of chars actually inserted
+	S32 							removeStringNoUndo(S32 pos, S32 length);
+	S32								overwriteCharNoUndo(S32 pos, llwchar wc);
+	void							appendAndHighlightText(const std::string &new_text, bool prepend_newline, S32 highlight_part, const LLStyle::Params& stylep);
+
+
+	// manage segments 
+	void                			getSegmentAndOffset( S32 startpos, segment_set_t::const_iterator* seg_iter, S32* offsetp ) const;
+	void                			getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg_iter, S32* offsetp );
+	LLTextSegmentPtr    			getSegmentAtLocalPos( S32 x, S32 y );
 	segment_set_t::iterator			getSegIterContaining(S32 index);
 	segment_set_t::const_iterator	getSegIterContaining(S32 index) const;
-	void                clearSegments();
-	void                setHoverSegment(LLTextSegmentPtr segment);
+	void                			clearSegments();
+	void							createDefaultSegment();
+	virtual void					updateSegments();
+	void							insertSegment(LLTextSegmentPtr segment_to_insert);
+	
+	//  manage lines
+	S32								getLineStart( S32 line ) const;
+	S32								getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap = true) const;
+	S32								getLineOffsetFromDocIndex( S32 doc_index, bool include_wordwrap = true) const;
+	S32								getFirstVisibleLine() const;
+	std::pair<S32, S32>				getVisibleLines() const;
+	S32								getLeftOffset(S32 width);
+	void							reflow(S32 start_index = 0);
 
-	// event handling for Urls within the text field
-	BOOL                handleHoverOverUrl(S32 x, S32 y);
-	BOOL                handleMouseUpOverUrl(S32 x, S32 y);
-	BOOL                handleRightMouseDownOverUrl(LLView *view, S32 x, S32 y);
-	BOOL                handleToolTipForUrl(LLView *view, S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen);
+	// cursor
+	void							updateCursorXPos();
+	void							setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset=false );
+	S32								getEditableIndex(S32 index, bool increasing_direction); // constraint cursor to editable segments of document
+	void							resetCursorBlink() { mCursorBlinkTimer.reset(); }
+	void							updateScrollFromCursor();
 
-	// pure virtuals that have to be implemented by any subclasses
-	virtual S32         getLineCount() const = 0;
-	virtual S32         getLineStart( S32 line ) const = 0;
-	virtual S32         getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const = 0;
+	// text selection
+	bool							hasSelection() const { return (mSelectionStart !=mSelectionEnd); }
+	void 							startSelection();
+	void 							endSelection();
 
-	// protected member variables
-	static LLUIColor    mLinkColor;
-	const LLFontGL      *mDefaultFont;
-	segment_set_t       mSegments;
-	LLTextSegmentPtr    mHoverSegment;	
-	BOOL                mParseHTML;
-	BOOL                mWordWrap;
+	// misc
+	void							updateTextRect();
+	void							needsReflow() { mReflowNeeded = TRUE; }
+	void							needsScroll() { mScrollNeeded = TRUE; }
+	void							replaceUrlLabel(const std::string &url, const std::string &label);
 
-private:
-	// create a popup context menu for the given Url
-	static LLContextMenu *createUrlContextMenu(const std::string &url);
+protected:
+	// text segmentation and flow
+	segment_set_t       		mSegments;
+	line_list_t					mLineInfoList;
+	LLRect						mTextRect;			// The rect in which text is drawn.  Excludes borders.
+	LLRect						mContentsRect;
+
+	// colors
+	LLUIColor					mCursorColor;
+	LLUIColor					mFgColor;
+	LLUIColor					mReadOnlyFgColor;
+	LLUIColor					mWriteableBgColor;
+	LLUIColor					mReadOnlyBgColor;
+	LLUIColor					mFocusBgColor;
+
+	// cursor
+	S32							mCursorPos;			// I-beam is just after the mCursorPos-th character.
+	S32							mDesiredXPixel;		// X pixel position where the user wants the cursor to be
+	LLFrameTimer				mCursorBlinkTimer;  // timer that controls cursor blinking
+
+	// selection
+	S32							mSelectionStart;
+	S32							mSelectionEnd;
+	
+	BOOL						mIsSelecting;		// Are we in the middle of a drag-select? 
+
+	// configuration
+	S32							mHPad;				// padding on left of text
+	S32							mVPad;				// padding above text
+	LLFontGL::HAlign			mHAlign;
+	F32							mLineSpacingMult;	// multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding)
+	S32							mLineSpacingPixels;	// padding between lines
+	const LLFontGL*				mDefaultFont;		// font that is used when none specified
+	LLFontGL::ShadowType		mFontShadow;
+	bool						mBorderVisible;
+	bool                		mParseHTML;			// make URLs interactive
+	bool						mParseHighlights;	// highlight user-defined keywords
+	bool                		mWordWrap;
+	bool						mUseEllipses;
+	bool						mTrackEnd;			// if true, keeps scroll position at end of document during resize
+	bool						mReadOnly;
+	bool						mClip;
+	S32							mMaxTextByteLength;	// Maximum length mText is allowed to be in bytes
+
+	// support widgets
+	LLContextMenu*				mPopupMenu;
+	DocumentPanel*				mDocumentPanel;
+	class LLScrollContainer*	mScroller;
+
+	// transient state
+	bool						mReflowNeeded;		// need to reflow text because of change to text contents or display region
+	bool						mScrollNeeded;		// need to change scroll region because of change to cursor position
+	S32							mScrollIndex;		// index of first character to keep visible in scroll region
 
-	LLContextMenu        *mPopupMenu;
 };
 
 ///
@@ -118,7 +364,7 @@ class LLTextBase
 /// includes a start/end offset from the start of the string, a
 /// style to render with, an optional tooltip, etc.
 ///
-class LLTextSegment : public LLRefCount
+class LLTextSegment : public LLRefCount, public LLMouseHandler
 {
 public:
 	LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){};
@@ -134,17 +380,32 @@ class LLTextSegment : public LLRefCount
 	virtual void				unlinkFromDocument(class LLTextBase* editor);
 	virtual void				linkToDocument(class LLTextBase* editor);
 
-	virtual void				setHasMouseHover(bool hover);
 	virtual const LLColor4&		getColor() const;
 	virtual void 				setColor(const LLColor4 &color);
 	virtual const LLStyleSP		getStyle() const;
 	virtual void 				setStyle(const LLStyleSP &style);
 	virtual void				setToken( LLKeywordToken* token );
 	virtual LLKeywordToken*		getToken() const;
-	virtual BOOL				getToolTip( std::string& msg ) const;
 	virtual void				setToolTip(const std::string& tooltip);
 	virtual void				dump() const;
 
+	// 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; }
@@ -167,7 +428,6 @@ class LLNormalTextSegment : public LLTextSegment
 	/*virtual*/ F32					draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
 	/*virtual*/ S32					getMaxHeight() const;
 	/*virtual*/ bool				canEdit() const { return true; }
-	/*virtual*/ void				setHasMouseHover(bool hover)		{ mHasMouseHover = hover; }
 	/*virtual*/ const LLColor4&		getColor() const					{ return mStyle->getColor(); }
 	/*virtual*/ void 				setColor(const LLColor4 &color)		{ mStyle->setColor(color); }
 	/*virtual*/ const LLStyleSP		getStyle() const					{ return mStyle; }
@@ -178,15 +438,20 @@ class LLNormalTextSegment : public LLTextSegment
 	/*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				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, F32 x, F32 y);
+	F32					drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRect rect);
 
+protected:
 	class LLTextBase&	mEditor;
-	LLStyleSP		mStyle;
-	S32				mMaxHeight;
-	LLKeywordToken* mToken;
-	bool			mHasMouseHover;
-	std::string     mTooltip;
+	LLStyleSP			mStyle;
+	S32					mMaxHeight;
+	LLKeywordToken* 	mToken;
+	std::string     	mTooltip;
 };
 
 class LLIndexSegment : public LLTextSegment
@@ -195,4 +460,23 @@ class LLIndexSegment : public LLTextSegment
 	LLIndexSegment(S32 pos) : LLTextSegment(pos, pos) {}
 };
 
+class LLInlineViewSegment : public LLTextSegment
+{
+public:
+	LLInlineViewSegment(LLView* widget, S32 start, S32 end);
+	~LLInlineViewSegment();
+	/*virtual*/ S32			getWidth(S32 first_char, S32 num_chars) const;
+	/*virtual*/ S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
+	/*virtual*/ void		updateLayout(const class LLTextBase& editor);
+	/*virtual*/ F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
+	/*virtuaL*/ S32			getMaxHeight() const;
+	/*virtual*/ bool		canEdit() const { return false; }
+	/*virtual*/ void		unlinkFromDocument(class LLTextBase* editor);
+	/*virtual*/ void		linkToDocument(class LLTextBase* editor);
+
+private:
+	LLView* mView;
+};
+
+
 #endif
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 132bef02966..3feca136be5 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -40,47 +40,10 @@
 
 static LLDefaultChildRegistry::Register<LLTextBox> r("text");
 
-LLTextBox::Params::Params()
-:	text_color("text_color"),
-	length("length"),
-	type("type"),
-	border_visible("border_visible", false),
-	border_drop_shadow_visible("border_drop_shadow_visible", false),
-	bg_visible("bg_visible", false),
-	use_ellipses("use_ellipses"),
-	word_wrap("word_wrap", false),
-	drop_shadow_visible("drop_shadow_visible"),
-	disabled_color("disabled_color"),
-	background_color("background_color"),
-	v_pad("v_pad", 0),
-	h_pad("h_pad", 0),
-	line_spacing("line_spacing", 0),
-	text("text"),
-	font_shadow("font_shadow", LLFontGL::NO_SHADOW)
-{}
-
 LLTextBox::LLTextBox(const LLTextBox::Params& p)
-:	LLUICtrl(p),
-	LLTextBase(p),
-	mBackgroundVisible( p.bg_visible ),
-	mBorderVisible( p.border_visible ),
-	mShadowType( p.font_shadow ),
-	mBorderDropShadowVisible( p.border_drop_shadow_visible ),
-	mUseEllipses( p.use_ellipses ),
-	mHPad(p.h_pad),
-	mVPad(p.v_pad),
-	mVAlign( LLFontGL::TOP ),
-	mClickedCallback(NULL),
-	mTextColor(p.text_color()),
-	mDisabledColor(p.disabled_color()),
-	mBackgroundColor(p.background_color()),
-	mHAlign(p.font_halign),
-	mLineSpacing(p.line_spacing),
-	mDidWordWrap(FALSE)
-{
-	mWordWrap = p.word_wrap;
-	setText( p.text() );
-}
+:	LLTextBase(p),
+	mClickedCallback(NULL)
+{}
 
 BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask)
 {
@@ -101,6 +64,11 @@ BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask)
 		}
 	}
 
+	if (!handled)
+	{
+		handled = LLTextBase::handleMouseDown(x, y, mask);
+	}
+
 	return handled;
 }
 
@@ -125,528 +93,60 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask)
 		}
 
 		// handle clicks on Urls in the textbox first
-		if (! handleMouseUpOverUrl(x, y))
+		handled = LLTextBase::handleMouseUp(x, y, mask);
+
+		// DO THIS AT THE VERY END to allow the button to be destroyed
+		// as a result of being clicked.  If mouseup in the widget,
+		// it's been clicked
+		if (mClickedCallback && !handled)
 		{
-			// DO THIS AT THE VERY END to allow the button to be destroyed
-			// as a result of being clicked.  If mouseup in the widget,
-			// it's been clicked
-			if (mClickedCallback && ! handled)
-			{
-				mClickedCallback();
-			}
+			mClickedCallback();
 		}
 	}
 
 	return handled;
 }
 
-BOOL LLTextBox::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
-	// pop up a context menu for any Url under the cursor
-	return handleRightMouseDownOverUrl(this, x, y);
-}
-
-BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask)
-{
-	// Check to see if we're over an HTML-style link
-	if (handleHoverOverUrl(x, y))
-	{
-		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;		
-		getWindow()->setCursor(UI_CURSOR_HAND);
-		return TRUE;
-	}
-
-	return LLView::handleHover(x,y,mask);
-}
-
-BOOL LLTextBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
-{
-	if (handleToolTipForUrl(this, x, y, msg, sticky_rect_screen))
-	{
-		return TRUE;
-	}
-
-	return LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen);
-}
-
 void LLTextBox::setText(const LLStringExplicit& text)
 {
-	if(mWordWrap && !mDidWordWrap)
-	{
-		setWrappedText(text);
-	}
-	else
-	{
-		mText.assign(text);
-		updateDisplayTextAndSegments();
-	}
-}
-
-void LLTextBox::setLineLengths()
-{
-	mLineLengthList.clear();
+	// does string argument insertion
+	mText.assign(text);
 	
-	std::string::size_type  cur = 0;
-	std::string::size_type  len = mDisplayText.size();
-
-	while (cur < len) 
-	{
-		std::string::size_type end = mDisplayText.find('\n', cur);
-		std::string::size_type runLen;
-		
-		if (end == std::string::npos)
-		{
-			runLen = len - cur;
-			cur = len;
-		}
-		else
-		{
-			runLen = end - cur;
-			cur = end + 1; // skip the new line character
-		}
-
-		mLineLengthList.push_back( (S32)runLen );
-	}
-}
-
-LLWString LLTextBox::wrapText(const LLWString &wtext, S32 &hoffset, S32 &line_num, F32 max_width)
-{
-	LLWString final_wtext;
-
-	LLWString::size_type cur = 0;
-	LLWString::size_type len = wtext.size();
-	while (cur < len)
-	{
-		LLWString::size_type end = wtext.find('\n', cur);
-		if (end == LLWString::npos)
-		{
-			end = len;
-		}
-		
-		bool charsRemaining = true;
-		LLWString::size_type runLen = end - cur;
-		if (runLen > 0)
-		{
-			// work out how many chars can fit onto the current line
-			LLWString run(wtext, cur, runLen);
-			LLWString::size_type useLen =
-				mDefaultFont->maxDrawableChars(run.c_str(), max_width-hoffset, runLen, TRUE);
-			charsRemaining = (cur + useLen < len);
-
-			// try to break lines on word boundaries
-			if (useLen < run.size())
-			{
-				LLWString::size_type prev_use_len = useLen;
-				while (useLen > 0 && ! isspace(run[useLen-1]) && ! ispunct(run[useLen-1]))
-				{
-					--useLen;
-				}
-				if (useLen == 0)
-				{
-					useLen = prev_use_len;
-				}
-			}
-
-			// add the chars that could fit onto one line to our result
-			final_wtext.append(wtext, cur, useLen);
-			cur += useLen;
-			hoffset += mDefaultFont->getWidth(run.substr(0, useLen).c_str());
-
-			// abort if not enough room to add any more characters
-			if (useLen == 0)
-			{
-				break;
-			}
-		}
-
-		if (charsRemaining)
-		{
-			if (wtext[cur] == '\n')
-			{
-				cur += 1;
-			}
-			final_wtext += '\n';
-			hoffset = 0;
-			line_num += 1;
-		}
-	}
-
-	return final_wtext;
-}
-
-void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width)
-{
-	mDidWordWrap = TRUE;
-	setText(wstring_to_utf8str(getWrappedText(in_text, max_width)));
-}
-
-LLWString LLTextBox::getWrappedText(const LLStringExplicit& in_text, F32 max_width)
-{
-	//
-	// we don't want to wrap Urls otherwise we won't be able to detect their
-	// presence for hyperlinking. So we look for all Urls, and then word wrap
-	// the text before and after, but never break a Url in the middle. We
-	// also need to consider that the Url will be displayed as a label (not
-	// necessary the actual Url string).
-	//
-
-	if (max_width < 0.0f)
-	{
-		max_width = (F32)getRect().getWidth();
-	}
-
-	LLWString wtext = utf8str_to_wstring(in_text);
-	LLWString final_wtext;
-	S32 line_num = 1;
-	S32 hoffset = 0;
-
-	// find the next Url in the text string
-	LLUrlMatch match;
-	while ( LLUrlRegistry::instance().findUrl(wtext, match))
-	{
-		S32 start = match.getStart();
-		S32 end = match.getEnd() + 1;
-
-		// perform word wrap on the text before the Url
-		final_wtext += wrapText(wtext.substr(0, start), hoffset, line_num, max_width);
-
-		// add the Url (but compute width based on its label)
-		S32 label_width = mDefaultFont->getWidth(match.getLabel());
-		if (hoffset > 0 && hoffset + label_width > max_width)
-		{
-			final_wtext += '\n';
-			line_num++;
-			hoffset = 0;
-		}
-		final_wtext += wtext.substr(start, end-start);
-		hoffset += label_width;
-		if (hoffset > max_width)
-		{
-			final_wtext += '\n';
-			line_num++;
-			hoffset = 0;
-			// eat any leading whitespace on the next line
-			while (isspace(wtext[end]) && end < (S32)wtext.size())
-			{
-				end++;
-			}
-		}
-
-		// move on to the rest of the text after the Url
-		wtext = wtext.substr(end, wtext.size() - end + 1);
-	}
-
-	final_wtext += wrapText(wtext, hoffset, line_num, max_width);
-	return final_wtext;
+	LLTextBase::setText(mText.getString());
 }
 
 S32 LLTextBox::getTextPixelWidth()
 {
-	S32 max_line_width = 0;
-	if( mLineLengthList.size() > 0 )
-	{
-		S32 cur_pos = 0;
-		for (std::vector<S32>::iterator iter = mLineLengthList.begin();
-			iter != mLineLengthList.end(); ++iter)
-		{
-			S32 line_length = *iter;
-			S32 line_width = mDefaultFont->getWidth( mDisplayText.c_str(), cur_pos, line_length );
-			if( line_width > max_line_width )
-			{
-				max_line_width = line_width;
-			}
-			cur_pos += line_length+1;
-		}
-	}
-	else
-	{
-		max_line_width = mDefaultFont->getWidth(mDisplayText.c_str());
-	}
-	return max_line_width;
+	return getContentsRect().getWidth();
 }
 
 S32 LLTextBox::getTextPixelHeight()
 {
-	S32 num_lines = mLineLengthList.size();
-	if( num_lines < 1 )
-	{
-		num_lines = 1;
-	}
-	return (S32)(num_lines * mDefaultFont->getLineHeight());
-}
-
-void LLTextBox::setValue(const LLSD& value )
-{ 
-	mDidWordWrap = FALSE;
-	setText(value.asString());
+	return getContentsRect().getHeight();
 }
 
 BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text )
 {
 	mText.setArg(key, text);
-	updateDisplayTextAndSegments();
-	return TRUE;
-}
-
-void LLTextBox::draw()
-{
-	F32 alpha = getDrawContext().mAlpha;
+	LLTextBase::setText(mText.getString());
 
-	if (mBorderVisible)
-	{
-		gl_rect_2d_offset_local(getLocalRect(), 2, FALSE);
-	}
-
-	if( mBorderDropShadowVisible )
-	{
-		static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow");
-		static LLUICachedControl<S32> drop_shadow_tooltip ("DropShadowTooltip", 0);
-		gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
-			color_drop_shadow % alpha, drop_shadow_tooltip);
-	}
-
-	if (mBackgroundVisible)
-	{
-		LLRect r( 0, getRect().getHeight(), getRect().getWidth(), 0 );
-		gl_rect_2d( r, mBackgroundColor.get() % alpha );
-	}
-
-	S32 text_x = 0;
-	switch( mHAlign )
-	{
-	case LLFontGL::LEFT:	
-		text_x = mHPad;						
-		break;
-	case LLFontGL::HCENTER:
-		text_x = getRect().getWidth() / 2;
-		break;
-	case LLFontGL::RIGHT:
-		text_x = getRect().getWidth() - mHPad;
-		break;
-	}
-
-	S32 text_y = getRect().getHeight() - mVPad;
-
-	if ( getEnabled() )
-	{
-		drawText( text_x, text_y, mDisplayText, mTextColor.get() );
-	}
-	else
-	{
-		drawText( text_x, text_y, mDisplayText, mDisabledColor.get() );
-	}
-
-	if (sDebugRects)
-	{
-		drawDebugRect();
-	}
-
-	//// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview)
-	//std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);
-	//if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights))
-	//{
-	//	drawDebugRect();
-	//}
+	return TRUE;
 }
 
-void LLTextBox::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	// reparse line lengths (don't need to recalculate the display text)
-	setLineLengths();
-	LLView::reshape(width, height, called_from_parent);
-}
-
-void LLTextBox::drawText( S32 x, S32 y, const LLWString &text, const LLColor4& color )
-{
-	F32 alpha = getDrawContext().mAlpha;
-	if (mSegments.size() > 1)
-	{
-		// we have Urls (or other multi-styled segments)
-		drawTextSegments(x, y, text);
-	}
-	else if( mLineLengthList.empty() )
-	{
-		// simple case of 1 line of text in one style
-		mDefaultFont->render(text, 0, (F32)x, (F32)y, color % alpha,
-							 mHAlign, mVAlign, 
-							 0,
-							 mShadowType,
-							 S32_MAX, getRect().getWidth(), NULL, mUseEllipses);
-	}
-	else
-	{
-		// simple case of multiple lines of text, all in the same style
-		S32 cur_pos = 0;
-		for (std::vector<S32>::iterator iter = mLineLengthList.begin();
-			iter != mLineLengthList.end(); ++iter)
-		{
-			S32 line_length = *iter;
-			mDefaultFont->render(text, cur_pos, (F32)x, (F32)y, color % alpha,
-								 mHAlign, mVAlign,
-								 0,
-								 mShadowType,
-								 line_length, getRect().getWidth(), NULL, mUseEllipses );
-			cur_pos += line_length + 1;
-			S32 line_height = llfloor(mDefaultFont->getLineHeight()) + mLineSpacing; 
-			y -= line_height;
-			if(y < line_height)
-				break;
-		}
-	}
-}
 
 void LLTextBox::reshapeToFitText()
 {
-	// wrap remaining lines that did not fit on call to setWrappedText()
-	setLineLengths();
+	reflow();
 
 	S32 width = getTextPixelWidth();
 	S32 height = getTextPixelHeight();
-	reshape( width + 2 * mHPad, height + 2 * mVPad );
-}
-
-S32 LLTextBox::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const
-{
-	// Returns the character offset for the character under the local (x, y) coordinate.
-	// When round is true, if the position is on the right half of a character, the cursor
-	// will be put to its right.  If round is false, the cursor will always be put to the
-	// character's left.
-
-	LLRect rect = getLocalRect();
-	rect.mLeft += mHPad;
-	rect.mRight -= mHPad;
-	rect.mTop += mVPad;
-	rect.mBottom -= mVPad;
-
-	// Figure out which line we're nearest to.
-	S32 total_lines = getLineCount();
-	S32 line_height = llround( mDefaultFont->getLineHeight() ) + mLineSpacing;
-	S32 line = (rect.mTop - 1 - local_y) / line_height;
-	if (line >= total_lines)
-	{
-		return getLength(); // past the end
-	}
-
-	line = llclamp( line, 0, total_lines );
-	S32 line_start = getLineStart(line);
-	S32 next_start = getLineStart(line+1);
-	S32	line_end = (next_start != line_start) ? next_start - 1 : getLength();
-	if (line_start == -1)
-	{
-		return 0;
-	}
-
-	S32 line_len = line_end - line_start;
-	S32 pos = mDefaultFont->charFromPixelOffset(mDisplayText.c_str(), line_start,
-												(F32)(local_x - rect.mLeft),
-												(F32)rect.getWidth(),
-												line_len, round);
-
-	return line_start + pos;
+	reshape( width + 2 * mHPad, height + 2 * mVPad, FALSE );
 }
 
-S32 LLTextBox::getLineStart( S32 line ) const
-{
-	line = llclamp(line, 0, getLineCount()-1);
-
-	S32 result = 0;
-	for (int i = 0; i < line; i++)
-	{
-		result += mLineLengthList[i] + 1 /* add newline */;
-	}
-
-	return result;
-}
-
-void LLTextBox::updateDisplayTextAndSegments()
-{
-	// remove any previous segment list
-	clearSegments();
-
-	// if URL parsing is turned off, then not much to bo
-	if (! mParseHTML)
-	{
-		mDisplayText = mText.getWString();
-		setLineLengths();
-		return;
-	}
-
-	// create unique text segments for Urls
-	mDisplayText.clear();
-	S32 end = 0;
-	LLUrlMatch match;
-	LLWString text = mText.getWString();
-		
-	// find the next Url in the text string
-	while ( LLUrlRegistry::instance().findUrl(text, match,
-											  boost::bind(&LLTextBox::onUrlLabelUpdated, this, _1, _2)) )
-	{
-		// work out the char offset for the start/end of the url
-		S32 url_start = match.getStart();
-		S32 url_end = match.getEnd();
-
-		// and the char offset for the label in the display text
-		S32 seg_start = mDisplayText.size();
-		S32 start = seg_start + url_start;
-		S32 end = start + match.getLabel().size();
-
-		// create a segment for the text before the Url
-		mSegments.insert(new LLNormalTextSegment(new LLStyle(), seg_start, start, *this));
-		mDisplayText += text.substr(0, url_start);
-
-		// create a segment for the Url text
-		LLStyleSP html(new LLStyle);
-		html->setVisible(true);
-		html->setColor(mLinkColor);
-		html->mUnderline = TRUE;
-		html->setLinkHREF(match.getUrl());
-
-		LLNormalTextSegment *html_seg = new LLNormalTextSegment(html, start, end, *this); 
-		html_seg->setToolTip(match.getTooltip());
-
-		mSegments.insert(html_seg);
-		mDisplayText += utf8str_to_wstring(match.getLabel());
-
-		// move on to the rest of the text after the Url
-		text = text.substr(url_end+1, text.size() - url_end);
-	}
-
-	// output a segment for the remaining text
-	if (text.size() > 0)
-	{
-		mSegments.insert(new LLNormalTextSegment(new LLStyle(), end, end + text.size(), *this));
-		mDisplayText += text;
-	}
-
-	// strip whitespace from the end of the text
-	while (mDisplayText.size() > 0 && isspace(mDisplayText[mDisplayText.size()-1]))
-	{
-		mDisplayText = mDisplayText.substr(0, mDisplayText.size() - 1);
-
-		segment_set_t::iterator it = getSegIterContaining(mDisplayText.size());
-		if (it != mSegments.end())
-		{
-			LLTextSegmentPtr seg = *it;
-			seg->setEnd(seg->getEnd()-1);
-		}
-	}
-
-	// we may have changed the line lengths, so recalculate them
-	setLineLengths();
-}
 
 void LLTextBox::onUrlLabelUpdated(const std::string &url, const std::string &label)
 {
-	if (mDidWordWrap)
-	{
-		// re-word wrap as the url label lengths may have changed
-		setWrappedText(mText.getString());
-	}
-	else
-	{
-		// or just update the display text with the latest Url labels
-		updateDisplayTextAndSegments();
-	}
+	needsReflow();
 }
 
 bool LLTextBox::isClickable() const
@@ -676,89 +176,3 @@ bool LLTextBox::isClickable() const
 	return false;
 }
 
-void LLTextBox::drawTextSegments(S32 init_x, S32 init_y, const LLWString &text)
-{
-	F32 alpha = getDrawContext().mAlpha;
-
-	const S32 text_len = text.length();
-	if (text_len <= 0)
-	{
-		return;
-	}
-
-	S32 cur_line = 0;
-	S32 num_lines = getLineCount();
-	S32 line_start = getLineStart(cur_line);
-	S32 line_height = llround( mDefaultFont->getLineHeight() ) + mLineSpacing;
-	F32 text_y = (F32) init_y;
-	segment_set_t::iterator cur_seg = mSegments.begin();
-
-	// render a line of text at a time
-	const LLRect textRect = getLocalRect();
-	while((textRect.mBottom <= text_y) && (cur_line < num_lines))
-	{
-		S32 next_start = -1;
-		S32 line_end = text_len;
-
-		if ((cur_line + 1) < num_lines)
-		{
-			next_start = getLineStart(cur_line + 1);
-			line_end = next_start;
-		}
-		if ( text[line_end-1] == '\n' )
-		{
-			--line_end;
-		}
-		
-		// render all segments on this line
-		F32 text_x = init_x;
-		S32 seg_start = line_start;
-		while (seg_start < line_end && cur_seg != mSegments.end())
-		{
-			// move to the next segment (or continue the previous one)
-			LLTextSegment *cur_segment = *cur_seg;
-			while (cur_segment->getEnd() <= seg_start)
-			{
-				if (++cur_seg == mSegments.end())
-				{
-					return;
-				}
-				cur_segment = *cur_seg;
-			}
-
-			// Draw a segment within the line
-			S32 clipped_end	= llmin( line_end, cur_segment->getEnd() );
-			S32 clipped_len = clipped_end - seg_start;
-			if( clipped_len > 0 )
-			{
-				LLStyleSP style = cur_segment->getStyle();
-				if (style && style->isVisible())
-				{
-					// work out the color for the segment
-					LLColor4 color ;
-					if (getEnabled())
-					{
-						color = style->isLink() ? mLinkColor.get() : mTextColor.get();
-					}
-					else
-					{
-						color = mDisabledColor.get();
-					}
-					color = color % alpha;
-
-					// render a single line worth for this segment
-					mDefaultFont->render(text, seg_start, text_x, text_y, color,
-										 mHAlign, mVAlign, 0, mShadowType, clipped_len,
-										 textRect.getWidth(), &text_x, mUseEllipses);
-				}
-
-				seg_start += clipped_len;
-			}
-		}
-
-		// move down one line
-		text_y -= (F32)line_height;
-		line_start = next_start;
-		cur_line++;
-	}
-}
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index 0517325e70c..f8c4447b626 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -33,47 +33,21 @@
 #ifndef LL_LLTEXTBOX_H
 #define LL_LLTEXTBOX_H
 
-#include "lluictrl.h"
 #include "v4color.h"
 #include "llstring.h"
 #include "lluistring.h"
 #include "lltextbase.h"
 
 class LLTextBox :
-	public LLTextBase,
-	public LLUICtrl
+	public LLTextBase
 {
 public:
 	
 	// *TODO: Add callback to Params
 	typedef boost::function<void (void)> callback_t;
 	
-	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
-	{
-		Optional<std::string> text;
-
-		Optional<bool>		border_visible,
-							border_drop_shadow_visible,
-							bg_visible,
-							use_ellipses,
-							word_wrap;
-
-		Optional<LLFontGL::ShadowType>	font_shadow;
-
-		Ignored				drop_shadow_visible,
-							type,
-							length;
-
-		Optional<LLUIColor>	text_color,
-							disabled_color,
-							background_color;
-
-		Optional<S32>		v_pad,
-							h_pad,
-							line_spacing;
-
-		Params();
-	};
+	struct Params : public LLInitParam::Block<Params, LLTextBase::Params>
+	{};
 
 protected:
 	LLTextBox(const Params&);
@@ -82,84 +56,33 @@ class LLTextBox :
 public:
 	virtual ~LLTextBox() {}
 
-	virtual void	draw();
-	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleRightMouseDown(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen);
 
-	void			setColor( const LLColor4& c )			{ mTextColor = c; }
-	void			setDisabledColor( const LLColor4& c)	{ mDisabledColor = c; }
-	void			setBackgroundColor( const LLColor4& c)	{ mBackgroundColor = c; }	
-
-	void			setText( const LLStringExplicit& text );
-	void			setWrappedText(const LLStringExplicit& text, F32 max_width = -1.f); // -1 means use existing control width
-	void			setUseEllipses( BOOL use_ellipses )		{ mUseEllipses = use_ellipses; }
+	/*virtual*/ void			setText( const LLStringExplicit& text );
 	
-	void			setBackgroundVisible(BOOL visible)		{ mBackgroundVisible = visible; }
-	void			setBorderVisible(BOOL visible)			{ mBorderVisible = visible; }
-	void			setBorderDropshadowVisible(BOOL visible){ mBorderDropShadowVisible = visible; }
-	void			setHPad(S32 pixels)						{ mHPad = pixels; }
-	void			setVPad(S32 pixels)						{ mVPad = pixels; }
 	void			setRightAlign()							{ mHAlign = LLFontGL::RIGHT; }
 	void			setHAlign( LLFontGL::HAlign align )		{ mHAlign = align; }
 	void			setClickedCallback( boost::function<void (void*)> cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); }		// mouse down and up within button
 
-	const LLFontGL* getFont() const							{ return mDefaultFont; }
-	void			setFont(const LLFontGL* font)			{ mDefaultFont = font; }
+	//const LLFontGL* getFont() const							{ return mDefaultFont; }
+	//void			setFont(const LLFontGL* font)			{ mDefaultFont = font; }
 
 	void			reshapeToFitText();
 
-	const std::string&	getText() const							{ return mText.getString(); }
-	LLWString		getWText() const { return mDisplayText; }
+	//const std::string&	getText() const							{ return mText.getString(); }
 	S32				getTextPixelWidth();
 	S32				getTextPixelHeight();
-	S32				getLength() const { return mDisplayText.length(); }
 
-	virtual void	setValue(const LLSD& value );		
 	virtual LLSD	getValue() const						{ return LLSD(getText()); }
 	virtual BOOL	setTextArg( const std::string& key, const LLStringExplicit& text );
 
 protected:
-	S32 			getLineCount() const { return mLineLengthList.size(); }
-	S32 			getLineStart( S32 line ) const;
-	S32             getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const;
-	LLWString       getWrappedText(const LLStringExplicit& in_text, F32 max_width = -1.f);
-	void			setLineLengths();
-	void			updateDisplayTextAndSegments();
-	virtual void	drawText(S32 x, S32 y, const LLWString &text, const LLColor4& color );
 	void            onUrlLabelUpdated(const std::string &url, const std::string &label);
 	bool            isClickable() const;
-	LLWString       wrapText(const LLWString &wtext, S32 &hoffset, S32 &line_num, F32 max_width);
-	void            drawTextSegments(S32 x, S32 y, const LLWString &text);
-
-	LLUIString		mText;
-	LLWString		mDisplayText;
-	LLUIColor		mTextColor;
-	LLUIColor		mDisabledColor;
-	LLUIColor		mBackgroundColor;
-	LLUIColor		mBorderColor;
-
-	BOOL			mBackgroundVisible;
-	BOOL			mBorderVisible;
-	BOOL            mDidWordWrap;
-	
-	LLFontGL::ShadowType mShadowType;
-	BOOL			mBorderDropShadowVisible;
-	BOOL			mUseEllipses;
-
-	S32				mLineSpacing;
-
-	S32				mHPad;
-	S32				mVPad;
-	LLFontGL::HAlign mHAlign;
-	LLFontGL::VAlign mVAlign;
 
-	std::vector<S32> mLineLengthList;
-	callback_t		mClickedCallback;
+	LLUIString			mText;
+	callback_t			mClickedCallback;
 };
 
 #endif
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 39f09b297f5..997c5b8fa8e 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -77,106 +77,31 @@ static LLDefaultChildRegistry::Register<LLTextEditor> r("simple_text_editor");
 //
 const S32	UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 32;
 const S32	UI_TEXTEDITOR_LINE_NUMBER_DIGITS = 4;
-const F32	CURSOR_FLASH_DELAY = 1.0f;  // in seconds
-const S32	CURSOR_THICKNESS = 2;
 const S32	SPACES_PER_TAB = 4;
 
-
-// helper functors
-struct LLTextEditor::compare_bottom
-{
-	bool operator()(const S32& a, const LLTextEditor::line_info& b) const
-	{
-		return a > b.mBottom; // bottom of a is higher than bottom of b
-	}
-
-	bool operator()(const LLTextEditor::line_info& a, const S32& b) const
-	{
-		return a.mBottom > b; // bottom of a is higher than bottom of b
-	}
-
-	bool operator()(const LLTextEditor::line_info& a, const LLTextEditor::line_info& b) const
-	{
-		return a.mBottom > b.mBottom; // bottom of a is higher than bottom of b
-	}
-
-};
-
-// helper functors
-struct LLTextEditor::compare_top
-{
-	bool operator()(const S32& a, const LLTextEditor::line_info& b) const
-	{
-		return a > b.mTop; // top of a is higher than top of b
-	}
-
-	bool operator()(const LLTextEditor::line_info& a, const S32& b) const
-	{
-		return a.mTop > b; // top of a is higher than top of b
-	}
-
-	bool operator()(const LLTextEditor::line_info& a, const LLTextEditor::line_info& b) const
-	{
-		return a.mTop > b.mTop; // top of a is higher than top of b
-	}
-};
-
-struct LLTextEditor::line_end_compare
-{
-	bool operator()(const S32& pos, const LLTextEditor::line_info& info) const
-	{
-		return (pos < info.mDocIndexEnd);
-	}
-
-	bool operator()(const LLTextEditor::line_info& info, const S32& pos) const
-	{
-		return (info.mDocIndexEnd < pos);
-	}
-
-	bool operator()(const LLTextEditor::line_info& a, const LLTextEditor::line_info& b) const
-	{
-		return (a.mDocIndexEnd < b.mDocIndexEnd);
-	}
-
-};
-
-//
-// DocumentPanel
-//
-
-class DocumentPanel : public LLPanel
-{
-public:
-	DocumentPanel(const Params&);
-};
-
-DocumentPanel::DocumentPanel(const Params& p)
-: LLPanel(p)
-{}
-
 ///////////////////////////////////////////////////////////////////
 
-class LLTextEditor::LLTextCmdInsert : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd
 {
 public:
-	LLTextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment)
-		: LLTextCmd(pos, group_with_next, segment), mWString(ws)
+	TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment)
+		: TextCmd(pos, group_with_next, segment), mWString(ws)
 	{
 	}
-	virtual ~LLTextCmdInsert() {}
-	virtual BOOL execute( LLTextEditor* editor, S32* delta )
+	virtual ~TextCmdInsert() {}
+	virtual BOOL execute( LLTextBase* editor, S32* delta )
 	{
 		*delta = insert(editor, getPosition(), mWString );
 		LLWStringUtil::truncate(mWString, *delta);
 		//mWString = wstring_truncate(mWString, *delta);
 		return (*delta != 0);
 	}	
-	virtual S32 undo( LLTextEditor* editor )
+	virtual S32 undo( LLTextBase* editor )
 	{
 		remove(editor, getPosition(), mWString.length() );
 		return getPosition();
 	}
-	virtual S32 redo( LLTextEditor* editor )
+	virtual S32 redo( LLTextBase* editor )
 	{
 		insert(editor, getPosition(), mWString );
 		return getPosition() + mWString.length();
@@ -187,11 +112,11 @@ class LLTextEditor::LLTextCmdInsert : public LLTextEditor::LLTextCmd
 };
 
 ///////////////////////////////////////////////////////////////////
-class LLTextEditor::LLTextCmdAddChar : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd
 {
 public:
-	LLTextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment)
-		: LLTextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE)
+	TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment)
+		: TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE)
 	{
 	}
 	virtual void blockExtensions()
@@ -205,14 +130,14 @@ class LLTextEditor::LLTextCmdAddChar : public LLTextEditor::LLTextCmd
 
 		return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length());
 	}
-	virtual BOOL execute( LLTextEditor* editor, S32* delta )
+	virtual BOOL execute( LLTextBase* editor, S32* delta )
 	{
 		*delta = insert(editor, getPosition(), mWString);
 		LLWStringUtil::truncate(mWString, *delta);
 		//mWString = wstring_truncate(mWString, *delta);
 		return (*delta != 0);
 	}
-	virtual BOOL extendAndExecute( LLTextEditor* editor, S32 pos, llwchar wc, S32* delta )	
+	virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta )	
 	{ 
 		LLWString ws;
 		ws += wc;
@@ -224,12 +149,12 @@ class LLTextEditor::LLTextCmdAddChar : public LLTextEditor::LLTextCmd
 		}
 		return (*delta != 0);
 	}
-	virtual S32 undo( LLTextEditor* editor )
+	virtual S32 undo( LLTextBase* editor )
 	{
 		remove(editor, getPosition(), mWString.length() );
 		return getPosition();
 	}
-	virtual S32 redo( LLTextEditor* editor )
+	virtual S32 redo( LLTextBase* editor )
 	{
 		insert(editor, getPosition(), mWString );
 		return getPosition() + mWString.length();
@@ -243,25 +168,25 @@ class LLTextEditor::LLTextCmdAddChar : public LLTextEditor::LLTextCmd
 
 ///////////////////////////////////////////////////////////////////
 
-class LLTextEditor::LLTextCmdOverwriteChar : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd
 {
 public:
-	LLTextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc)
-		: LLTextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {}
+	TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc)
+		: TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {}
 
-	virtual BOOL execute( LLTextEditor* editor, S32* delta )
+	virtual BOOL execute( LLTextBase* editor, S32* delta )
 	{ 
-		mOldChar = editor->getWChar(getPosition());
+		mOldChar = editor->getWText()[getPosition()];
 		overwrite(editor, getPosition(), mChar);
 		*delta = 0;
 		return TRUE;
 	}	
-	virtual S32 undo( LLTextEditor* editor )
+	virtual S32 undo( LLTextBase* editor )
 	{
 		overwrite(editor, getPosition(), mOldChar);
 		return getPosition();
 	}
-	virtual S32 redo( LLTextEditor* editor )
+	virtual S32 redo( LLTextBase* editor )
 	{
 		overwrite(editor, getPosition(), mChar);
 		return getPosition()+1;
@@ -274,26 +199,26 @@ class LLTextEditor::LLTextCmdOverwriteChar : public LLTextEditor::LLTextCmd
 
 ///////////////////////////////////////////////////////////////////
 
-class LLTextEditor::LLTextCmdRemove : public LLTextEditor::LLTextCmd
+class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd
 {
 public:
-	LLTextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) :
-		LLTextCmd(pos, group_with_next), mLen(len)
+	TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) :
+		TextCmd(pos, group_with_next), mLen(len)
 	{
 		std::swap(mSegments, segments);
 	}
-	virtual BOOL execute( LLTextEditor* editor, S32* delta )
+	virtual BOOL execute( LLTextBase* editor, S32* delta )
 	{ 
-		mWString = editor->getWSubString(getPosition(), mLen);
+		mWString = editor->getWText().substr(getPosition(), mLen);
 		*delta = remove(editor, getPosition(), mLen );
 		return (*delta != 0);
 	}
-	virtual S32 undo( LLTextEditor* editor )
+	virtual S32 undo( LLTextBase* editor )
 	{
 		insert(editor, getPosition(), mWString);
 		return getPosition() + mWString.length();
 	}
-	virtual S32 redo( LLTextEditor* editor )
+	virtual S32 redo( LLTextBase* editor )
 	{
 		remove(editor, getPosition(), mLen );
 		return getPosition();
@@ -307,138 +232,61 @@ class LLTextEditor::LLTextCmdRemove : public LLTextEditor::LLTextCmd
 ///////////////////////////////////////////////////////////////////
 LLTextEditor::Params::Params()
 :	default_text("default_text"),
-	max_text_length("max_length", 255),
-	read_only("read_only", false),
 	embedded_items("embedded_items", false),
-	hide_scrollbar("hide_scrollbar"),
-	hide_border("hide_border", false),
-	word_wrap("word_wrap", false),
 	ignore_tab("ignore_tab", true),
-	track_bottom("track_bottom", false),
 	handle_edit_keys_directly("handle_edit_keys_directly", false),
 	show_line_numbers("show_line_numbers", false),
-	cursor_color("cursor_color"),
 	default_color("default_color"),
-	text_color("text_color"),
-	text_readonly_color("text_readonly_color"),
-	bg_readonly_color("bg_readonly_color"),
-	bg_writeable_color("bg_writeable_color"),
-	bg_focus_color("bg_focus_color"),
-	link_color("link_color"),
-    commit_on_focus_lost("commit_on_focus_lost", false),
-	length("length"),		// ignored
-	type("type"),			// ignored
-	is_unicode("is_unicode")// ignored
+    commit_on_focus_lost("commit_on_focus_lost", false)
 {}
 
 LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
-	LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),
 	LLTextBase(p),
-	mMaxTextByteLength( p.max_text_length ),
 	mBaseDocIsPristine(TRUE),
 	mPristineCmd( NULL ),
 	mLastCmd( NULL ),
-	mCursorPos( 0 ),
-	mIsSelecting( FALSE ),
-	mSelectionStart( 0 ),
-	mSelectionEnd( 0 ),
-	mOnScrollEndData( NULL ),
-	mCursorColor(		p.cursor_color() ),
-	mFgColor(			p.text_color() ),
 	mDefaultColor(		p.default_color() ),
-	mReadOnlyFgColor(	p.text_readonly_color() ),
-	mWriteableBgColor(	p.bg_writeable_color() ),
-	mReadOnlyBgColor(	p.bg_readonly_color() ),
-	mFocusBgColor(		p.bg_focus_color() ),
-	mLinkColor(			p.link_color() ),
-	mReadOnly(p.read_only),
 	mShowLineNumbers ( p.show_line_numbers ),
 	mCommitOnFocusLost( p.commit_on_focus_lost),
-	mTrackBottom( p.track_bottom ),
 	mAllowEmbeddedItems( p.embedded_items ),
 	mHandleEditKeysDirectly( p.handle_edit_keys_directly ),
 	mMouseDownX(0),
 	mMouseDownY(0),
-	mLastSelectionX(-1),
-	mReflowNeeded(FALSE),
-	mScrollNeeded(FALSE),
-	mLastSelectionY(-1),
-	mParseHighlights(FALSE),
-	mTabsToNextField(p.ignore_tab),
-	mScrollIndex(-1)
+	mTabsToNextField(p.ignore_tab)
 {
-	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
-
-	mWordWrap = p.word_wrap;
 	mDefaultFont = p.font;
-	mParseHTML = FALSE;
 
 	mSourceID.generate();
 
-	// reset desired x cursor position
-	mDesiredXPixel = -1;
-
-	LLScrollContainer::Params scroll_params;
-	scroll_params.name = "text scroller";
-	scroll_params.rect = getLocalRect();
-	scroll_params.follows.flags = FOLLOWS_ALL;
-	scroll_params.is_opaque = false;
-	scroll_params.mouse_opaque = false;
-	scroll_params.min_auto_scroll_rate = 200;
-	scroll_params.max_auto_scroll_rate = 800;
-	mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroll_params);
-	addChild(mScroller);
-
-	LLPanel::Params panel_params;
-	panel_params.name = "text_contents";
-	panel_params.rect =  LLRect(0, 500, 500, 0);
-	panel_params.background_visible = true;
-	panel_params.background_opaque = true;
-	panel_params.mouse_opaque = false;
-
-	mDocumentPanel = LLUICtrlFactory::create<DocumentPanel>(panel_params);
-	mScroller->addChild(mDocumentPanel);
-
-	updateTextRect();
-
-	static LLUICachedControl<S32> text_editor_border ("UITextEditorBorder", 0);
+	//FIXME: use image?
 	LLViewBorder::Params params;
 	params.name = "text ed border";
 	params.rect = getLocalRect();
 	params.bevel_style = LLViewBorder::BEVEL_IN;
-	params.border_thickness = text_editor_border;
+	params.border_thickness = 1;
+	params.visible = p.border_visible;
 	mBorder = LLUICtrlFactory::create<LLViewBorder> (params);
 	addChild( mBorder );
-	mBorder->setVisible(!p.hide_border);
 
-	createDefaultSegment();
-
-	appendText(p.default_text, FALSE, FALSE);
+	setText(p.default_text());
 
+	if (mShowLineNumbers)
+	{
+		mHPad += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
+		updateTextRect();
+	}
 }
 
 void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
 {
-	resetDirty();		// Update saved text state
-	LLUICtrl::initFromParams(p);
-	// HACK: work around enabled == readonly design bug -- RN
-	// setEnabled will modify our read only status, so do this after
-	// LLUICtrl::initFromParams
-	if (p.read_only.isProvided())
-	{
-		mReadOnly = p.read_only;
-	}
-	
+	LLTextBase::initFromParams(p);
+
 	if (p.commit_on_focus_lost.isProvided())
 	{
 		mCommitOnFocusLost = p.commit_on_focus_lost;
 	}
 	
-	updateSegments();
 	updateAllowingLanguageInput();
-
-	// HACK:  text editors always need to be enabled so that we can scroll
-	LLView::setEnabled(true);
 }
 
 LLTextEditor::~LLTextEditor()
@@ -455,282 +303,18 @@ LLTextEditor::~LLTextEditor()
 	std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer());
 }
 
-LLTextViewModel* LLTextEditor::getViewModel() const
-{
-	return (LLTextViewModel*)mViewModel.get();
-}
-
-static LLFastTimer::DeclareTimer FTM_TEXT_REFLOW ("Text Reflow");
-void LLTextEditor::reflow(S32 start_index)
-{
-	if (!mReflowNeeded) return;
-
-	LLFastTimer ft(FTM_TEXT_REFLOW);
-	static LLUICachedControl<S32> texteditor_vpad_top ("UITextEditorVPadTop", 0);
-
-	updateSegments();
-
-	while(mReflowNeeded)
-	{
-		bool scrolled_to_bottom = mScroller->isAtBottom();
-		mReflowNeeded = FALSE;
-
-		LLRect old_cursor_rect = getLocalRectFromDocIndex(mCursorPos);
-		bool follow_selection = mTextRect.overlaps(old_cursor_rect); // cursor is visible
-		S32 first_line = getFirstVisibleLine();
-		// if scroll anchor not on first line, update it to first character of first line
-		if (!mLineInfoList.empty()
-			&&	(mScrollIndex <  mLineInfoList[first_line].mDocIndexStart
-				||	mScrollIndex >= mLineInfoList[first_line].mDocIndexEnd))
-		{
-			mScrollIndex = mLineInfoList[first_line].mDocIndexStart;
-		}
-		LLRect first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
-		//first_char_rect.intersectWith(mTextRect);
-
-		S32 cur_top = -texteditor_vpad_top;
-		
-		if (getLength())
-		{
-			segment_set_t::iterator seg_iter = mSegments.begin();
-			S32 seg_offset = 0;
-			S32 line_start_index = 0;
-			S32 text_width = mTextRect.getWidth();  // optionally reserve room for margin
-			S32 remaining_pixels = text_width;
-			LLWString text(getWText());
-			S32 line_count = 0;
-
-			// find and erase line info structs starting at start_index and going to end of document
-			if (!mLineInfoList.empty())
-			{
-				// find first element whose end comes after start_index
-				line_list_t::iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), start_index, line_end_compare());
-				line_start_index = iter->mDocIndexStart;
-				line_count = iter->mLineNum;
-				getSegmentAndOffset(iter->mDocIndexStart, &seg_iter, &seg_offset);
-				mLineInfoList.erase(iter, mLineInfoList.end());
-			}
-
-			// reserve enough space for line numbers
-			S32 line_height = mShowLineNumbers ? (S32)(LLFontGL::getFontMonospace()->getLineHeight()) : 0;
-
-			while(seg_iter != mSegments.end())
-			{
-				LLTextSegmentPtr segment = *seg_iter;
-
-				// track maximum height of any segment on this line
-				line_height = llmax(line_height, segment->getMaxHeight());
-				S32 cur_index = segment->getStart() + seg_offset;
-				// find run of text from this segment that we can display on one line
-				S32 end_index = cur_index;
-				while(end_index < segment->getEnd() && text[end_index] != '\n')
-				{
-					++end_index;
-				}
-
-				// ask segment how many character fit in remaining space
-				S32 max_characters = end_index - cur_index;
-				S32 character_count = segment->getNumChars(llmax(0, remaining_pixels), seg_offset, cur_index - line_start_index, max_characters);
-
-				seg_offset += character_count;
-
-				S32 last_segment_char_on_line = segment->getStart() + seg_offset;
-
-				// if we didn't finish the current segment...
-				if (last_segment_char_on_line < segment->getEnd())
-				{
-					// set up index for next line
-					// ...skip newline, we don't want to draw
-					S32 next_line_count = line_count;
-					if (text[last_segment_char_on_line] == '\n')
-					{
-						seg_offset++;
-						last_segment_char_on_line++;
-						next_line_count++;
-					}
-
-					// add line info and keep going
-					mLineInfoList.push_back(line_info(line_start_index, last_segment_char_on_line, cur_top, cur_top - line_height, line_count));
-
-					line_start_index = segment->getStart() + seg_offset;
-					cur_top -= line_height;
-					remaining_pixels = text_width;
-					line_height = 0;
-					line_count = next_line_count;
-				}
-				// ...just consumed last segment..
-				else if (++segment_set_t::iterator(seg_iter) == mSegments.end())
-				{
-					mLineInfoList.push_back(line_info(line_start_index, last_segment_char_on_line, cur_top, cur_top - line_height, line_count));
-					cur_top -= line_height;
-					break;
-				}
-				// finished a segment and there are segments remaining on this line
-				else
-				{
-					// subtract pixels used and increment segment
-					remaining_pixels -= segment->getWidth(seg_offset, character_count);
-					++seg_iter;
-					seg_offset = 0;
-				}
-			}
-		}
-
-		// change mDocumentPanel document size to accomodate reflowed text
-		LLRect document_rect;
-		document_rect.setOriginAndSize(1, 1, 
-									mScroller->getContentWindowRect().getWidth(), 
-									llmax(mScroller->getContentWindowRect().getHeight(), -cur_top));
-		mDocumentPanel->setShape(document_rect);
-
-		// after making document big enough to hold all the text, move the text to fit in the document
-		if (!mLineInfoList.empty())
-		{
-			S32 delta_pos = mDocumentPanel->getRect().getHeight() - mLineInfoList.begin()->mTop - texteditor_vpad_top;
-			// move line segments to fit new document rect
-			for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it)
-			{
-				it->mTop += delta_pos;
-				it->mBottom += delta_pos;
-			}
-		}
-
-		// calculate visible region for diplaying text
-		updateTextRect();
-
-		for (segment_set_t::iterator segment_it = mSegments.begin();
-			segment_it != mSegments.end();
-			++segment_it)
-		{
-			LLTextSegmentPtr segmentp = *segment_it;
-			segmentp->updateLayout(*this);
-
-		}
-
-		// apply scroll constraints after reflowing text
-		if (!hasMouseCapture())
-		{
-			LLRect visible_content_rect = mScroller->getVisibleContentRect();
-			if (scrolled_to_bottom && mTrackBottom)
-			{
-				// 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 = getLocalRectFromDocIndex(mCursorPos);
-				new_cursor_rect_doc.translate(visible_content_rect.mLeft, visible_content_rect.mBottom);
-				mScroller->scrollToShowRect(new_cursor_rect_doc, old_cursor_rect);
-				//llassert_always(getLocalRectFromDocIndex(mCursorPos).mBottom == old_cursor_rect.mBottom);
-			}
-			else
-			{
-				// keep first line of text visible
-				LLRect new_first_char_rect = getLocalRectFromDocIndex(mScrollIndex);
-				new_first_char_rect.translate(visible_content_rect.mLeft, visible_content_rect.mBottom);
-				mScroller->scrollToShowRect(new_first_char_rect, first_char_rect);
-				//llassert_always(getLocalRectFromDocIndex(mScrollIndex).mBottom == first_char_rect.mBottom);
-			}
-		}
-	}
-
-	// reset desired x cursor position
-	updateCursorXPos();
-}
-
 ////////////////////////////////////////////////////////////
 // LLTextEditor
 // Public methods
 
-BOOL LLTextEditor::truncate()
-{
-	BOOL did_truncate = FALSE;
-
-	// First rough check - if we're less than 1/4th the size, we're OK
-	if (getLength() >= S32(mMaxTextByteLength / 4))
-	{	
-		// Have to check actual byte size
-        LLWString text(getWText());
-		S32 utf8_byte_size = wstring_utf8_length(text);
-		if ( utf8_byte_size > mMaxTextByteLength )
-		{
-			// Truncate safely in UTF-8
-			std::string temp_utf8_text = wstring_to_utf8str(text);
-			temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength );
-			getViewModel()->setDisplay(utf8str_to_wstring( temp_utf8_text ));
-			did_truncate = TRUE;
-		}
-	}
-
-	return did_truncate;
-}
-
 void LLTextEditor::setText(const LLStringExplicit &utf8str)
 {
-	// clear out the existing text and segments
-	clearSegments();
-
-	getViewModel()->setValue("");
-
-	truncate();
-	blockUndo();
-
-	createDefaultSegment();
-
-	startOfDoc();
-	deselect();
-
-	// append the new text (supports Url linking)
-	std::string text(utf8str);
-	LLStringUtil::removeCRLF(text);
-	appendStyledText(text, false, false, LLStyle::Params());
-
-	needsReflow();
-
-	resetDirty();
-
-	onValueChange(0, getLength());
-}
-
-void LLTextEditor::setWText(const LLWString &wtext)
-{
-	// clear out the existing text and segments
-	clearSegments();
-
-	getViewModel()->setDisplay(LLWString());
-
-	truncate();
 	blockUndo();
-
-	createDefaultSegment();
-
-	startOfDoc();
 	deselect();
 
-	// append the new text (supports Url linking)
-	appendStyledText(wstring_to_utf8str(wtext), false, false, LLStyle::Params());
-
-	needsReflow();
+	LLTextBase::setText(utf8str);
 
 	resetDirty();
-
-	onValueChange(0, getLength());
-}
-
-// virtual
-void LLTextEditor::setValue(const LLSD& value)
-{
-	setText(value.asString());
-}
-
-std::string LLTextEditor::getText() const
-{
-	if (mAllowEmbeddedItems)
-	{
-		llwarns << "getText() called on text with embedded items (not supported)" << llendl;
-	}
-	return getViewModel()->getValue().asString();
 }
 
 void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap)
@@ -828,12 +412,6 @@ void LLTextEditor::replaceTextAll(const std::string& search_text, const std::str
 	}
 }
 
-// Picks a new cursor position based on the screen size of text being drawn.
-void LLTextEditor::setCursorAtLocalPos( S32 local_x, S32 local_y, bool round, bool keep_cursor_offset )
-{
-	setCursorPos(getDocIndexFromLocalCoord(local_x, local_y, round), keep_cursor_offset);
-}
-
 S32 LLTextEditor::prevWordPos(S32 cursorPos) const
 {
 	LLWString wtext(getWText());
@@ -862,60 +440,6 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const
 	return cursorPos;
 }
 
-S32 LLTextEditor::getLineStart( S32 line ) const
-{
-	S32 num_lines = getLineCount();
-	if (num_lines == 0)
-    {
-		return 0;
-    }
-
-	line = llclamp(line, 0, num_lines-1);
-	return mLineInfoList[line].mDocIndexStart;
-}
-
-S32 LLTextEditor::getLineHeight( S32 line ) const
-{
-	S32 num_lines = getLineCount();
-	if (num_lines == 0)
-    {
-		return 0;
-    }
-
-	line = llclamp(line, 0, num_lines-1);
-	return mLineInfoList[line].mTop - mLineInfoList[line].mBottom;
-}
-
-// Given an offset into text (pos), find the corresponding line (from the start of the doc) and an offset into the line.
-void LLTextEditor::getLineAndOffset( S32 startpos, S32* linep, S32* offsetp, bool include_wordwrap) const
-{
-	if (mLineInfoList.empty())
-	{
-		*linep = 0;
-		*offsetp = startpos;
-	}
-	else
-	{
-		line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), startpos, line_end_compare());
-		if (include_wordwrap)
-		{
-			*linep = iter - mLineInfoList.begin();
-		}
-		else
-		{
-			if (iter == mLineInfoList.end())
-			{
-				*linep = mLineInfoList.back().mLineNum;
-			}
-			else
-			{
-				*linep = iter->mLineNum;
-			}
-		}
-		*offsetp = startpos - iter->mDocIndexStart;
-	}
-}
-
 const LLTextSegmentPtr	LLTextEditor::getPreviousSegment() const
 {
 	// find segment index at character to left of cursor (or rightmost edge of selection)
@@ -957,272 +481,58 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out,
 	}
 }
 
-// If round is true, if the position is on the right half of a character, the cursor
-// will be put to its right.  If round is false, the cursor will always be put to the
-// character's left.
+// virtual
+BOOL LLTextEditor::canDeselect() const
+{
+	return hasSelection(); 
+}
+
 
-S32 LLTextEditor::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const
+void LLTextEditor::deselect()
 {
-	// Figure out which line we're nearest to.
-	LLRect visible_region = mScroller->getVisibleContentRect();
+	mSelectionStart = 0;
+	mSelectionEnd = 0;
+	mIsSelecting = FALSE;
+}
 
-	// binary search for line that starts before local_y
-	line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mTextRect.mBottom + visible_region.mBottom, compare_bottom());
 
-	if (line_iter == mLineInfoList.end())
+BOOL LLTextEditor::selectionContainsLineBreaks()
+{
+	if (hasSelection())
 	{
-		return getLength(); // past the end
-	}
-	
-	S32 pos = getLength();
-	S32 start_x = mTextRect.mLeft;
-
-	segment_set_t::iterator line_seg_iter;
-	S32 line_seg_offset;
-	for(getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
-		line_seg_iter != mSegments.end(); 
-		++line_seg_iter, line_seg_offset = 0)
-	{
-		const LLTextSegmentPtr segmentp = *line_seg_iter;
-
-		S32 segment_line_start = segmentp->getStart() + line_seg_offset;
-		S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd - 1) - segment_line_start;
-		S32 text_width = segmentp->getWidth(line_seg_offset, segment_line_length);
-		if (local_x < start_x + text_width						// cursor to left of right edge of text
-			|| segmentp->getEnd() >= line_iter->mDocIndexEnd - 1)	// or this segment wraps to next line
+		S32 left = llmin(mSelectionStart, mSelectionEnd);
+		S32 right = left + llabs(mSelectionStart - mSelectionEnd);
+
+		LLWString wtext = getWText();
+		for( S32 i = left; i < right; i++ )
 		{
-			// Figure out which character we're nearest to.
-			S32 offset;
-			if (!segmentp->canEdit())
-			{
-				S32 segment_width = segmentp->getWidth(0, segmentp->getEnd() - segmentp->getStart());
-				if (round && local_x - start_x > segment_width / 2)
-				{
-					offset = segment_line_length;
-				}
-				else
-				{
-					offset = 0;
-				}
-			}
-			else
+			if (wtext[i] == '\n')
 			{
-				offset = segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round);
+				return TRUE;
 			}
-			pos = segment_line_start + offset;
-			break;
 		}
-		start_x += text_width;
 	}
-
-	return pos;
+	return FALSE;
 }
 
-LLRect LLTextEditor::getLocalRectFromDocIndex(S32 pos) const
-{
-	LLRect local_rect(mTextRect);
-	local_rect.mBottom = local_rect.mTop - (S32)(mDefaultFont->getLineHeight());
-	if (mLineInfoList.empty()) 
-	{ 
-		return local_rect;
-	}
-
-	// clamp pos to valid values
-	pos = llclamp(pos, 0, mLineInfoList.back().mDocIndexEnd - 1);
-
 
-	// find line that contains cursor
-	line_list_t::const_iterator line_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), pos, line_end_compare());
+S32 LLTextEditor::indentLine( S32 pos, S32 spaces )
+{
+	// Assumes that pos is at the start of the line
+	// spaces may be positive (indent) or negative (unindent).
+	// Returns the actual number of characters added or removed.
 
-	LLRect scrolled_view_rect = mScroller->getVisibleContentRect();
-	local_rect.mLeft = mTextRect.mLeft - scrolled_view_rect.mLeft; 
-	local_rect.mBottom = mTextRect.mBottom + (line_iter->mBottom - scrolled_view_rect.mBottom);
-	local_rect.mTop = mTextRect.mBottom + (line_iter->mTop - scrolled_view_rect.mBottom);
+	llassert(pos >= 0);
+	llassert(pos <= getLength() );
 
-	segment_set_t::iterator line_seg_iter;
-	S32 line_seg_offset;
-	segment_set_t::iterator cursor_seg_iter;
-	S32 cursor_seg_offset;
-	getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
-	getSegmentAndOffset(pos, &cursor_seg_iter, &cursor_seg_offset);
+	S32 delta_spaces = 0;
 
-	while(line_seg_iter != mSegments.end())
+	if (spaces >= 0)
 	{
-		const LLTextSegmentPtr segmentp = *line_seg_iter;
-
-		if (line_seg_iter == cursor_seg_iter)
-		{
-			// cursor advanced to right based on difference in offset of cursor to start of line
-			local_rect.mLeft += segmentp->getWidth(line_seg_offset, cursor_seg_offset - line_seg_offset);
-
-			break;
-		}
-		else
+		// Indent
+		for(S32 i=0; i < spaces; i++)
 		{
-			// add remainder of current text segment to cursor position
-			local_rect.mLeft += segmentp->getWidth(line_seg_offset, (segmentp->getEnd() - segmentp->getStart()) - line_seg_offset);
-			// offset will be 0 for all segments after the first
-			line_seg_offset = 0;
-			// go to next text segment on this line
-			++line_seg_iter;
-		}
-	}
-
-	local_rect.mRight = local_rect.mLeft; 
-
-	return local_rect;
-}
-
-void LLTextEditor::addDocumentChild(LLView* view) 
-{ 
-	mDocumentPanel->addChild(view); 
-}
-
-void LLTextEditor::removeDocumentChild(LLView* view) 
-{ 
-	mDocumentPanel->removeChild(view); 
-}
-
-bool LLTextEditor::setCursor(S32 row, S32 column)
-{
-	if (0 <= row && row < (S32)mLineInfoList.size())
-	{
-		S32 doc_pos = mLineInfoList[row].mDocIndexStart;
-		column = llclamp(column, 0, mLineInfoList[row].mDocIndexEnd - mLineInfoList[row].mDocIndexStart - 1);
-		doc_pos += column;
-		updateCursorXPos();
-
-		return setCursorPos(doc_pos);
-	}
-	return false;
-}
-
-bool LLTextEditor::setCursorPos(S32 cursor_pos, bool keep_cursor_offset)
-{
-	S32 new_cursor_pos = cursor_pos;
-	if (new_cursor_pos != mCursorPos)
-	{
-		new_cursor_pos = getEditableIndex(new_cursor_pos, new_cursor_pos >= mCursorPos);
-	}
-
-	mCursorPos = llclamp(new_cursor_pos, 0, (S32)getLength());
-	needsScroll();
-	if (!keep_cursor_offset)
-		updateCursorXPos();
-	// did we get requested position?
-	return new_cursor_pos == cursor_pos;
-}
-
-void LLTextEditor::updateCursorXPos()
-{
-	// reset desired x cursor position
-	mDesiredXPixel = getLocalRectFromDocIndex(mCursorPos).mLeft;
-}
-
-// constraint cursor to editable segments of document
-// NOTE: index must be within document range
-S32 LLTextEditor::getEditableIndex(S32 index, bool increasing_direction)
-{
-	segment_set_t::iterator segment_iter;
-	S32 offset;
-	getSegmentAndOffset(index, &segment_iter, &offset);
-
-	LLTextSegmentPtr segmentp = *segment_iter;
-
-	if (segmentp->canEdit()) 
-	{
-		return segmentp->getStart() + offset;			
-	}
-	else if (segmentp->getStart() < index && index < segmentp->getEnd())
-	{
-		// bias towards document end
-		if (increasing_direction)
-		{
-			return segmentp->getEnd();
-		}
-		// bias towards document start
-		else
-		{
-			return segmentp->getStart();
-		}
-	}
-	else
-	{
-		return index;
-	}
-}
-
-// virtual
-BOOL LLTextEditor::canDeselect() const
-{
-	return hasSelection(); 
-}
-
-
-void LLTextEditor::deselect()
-{
-	mSelectionStart = 0;
-	mSelectionEnd = 0;
-	mIsSelecting = FALSE;
-}
-
-
-void LLTextEditor::startSelection()
-{
-	if( !mIsSelecting )
-	{
-		mIsSelecting = TRUE;
-		mSelectionStart = mCursorPos;
-		mSelectionEnd = mCursorPos;
-	}
-}
-
-void LLTextEditor::endSelection()
-{
-	if( mIsSelecting )
-	{
-		mIsSelecting = FALSE;
-		mSelectionEnd = mCursorPos;
-	}
-}
-
-BOOL LLTextEditor::selectionContainsLineBreaks()
-{
-	if (hasSelection())
-	{
-		S32 left = llmin(mSelectionStart, mSelectionEnd);
-		S32 right = left + llabs(mSelectionStart - mSelectionEnd);
-
-		LLWString wtext = getWText();
-		for( S32 i = left; i < right; i++ )
-		{
-			if (wtext[i] == '\n')
-			{
-				return TRUE;
-			}
-		}
-	}
-	return FALSE;
-}
-
-
-S32 LLTextEditor::indentLine( S32 pos, S32 spaces )
-{
-	// Assumes that pos is at the start of the line
-	// spaces may be positive (indent) or negative (unindent).
-	// Returns the actual number of characters added or removed.
-
-	llassert(pos >= 0);
-	llassert(pos <= getLength() );
-
-	S32 delta_spaces = 0;
-
-	if (spaces >= 0)
-	{
-		// Indent
-		for(S32 i=0; i < spaces; i++)
-		{
-			delta_spaces += addChar(pos, ' ');
+			delta_spaces += addChar(pos, ' ');
 		}
 	}
 	else
@@ -1334,23 +644,12 @@ void LLTextEditor::selectAll()
 	setCursorPos(mSelectionEnd);
 }
 
-
-BOOL LLTextEditor::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
-{
-	if (childrenHandleToolTip(x, y, msg, sticky_rect_screen))
-	{
-		return TRUE;
-	}
-
-	return handleToolTipForUrl(this, x, y, msg, sticky_rect_screen);
-}
-
 BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	BOOL	handled = FALSE;
 
 	// Let scrollbar have first dibs
-	handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
+	handled = LLTextBase::handleMouseDown(x, y, mask);
 
 	if( !handled )
 	{
@@ -1398,7 +697,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 	}
 
 	// Delay cursor flashing
-	resetKeystrokeTimer();
+	resetCursorBlink();
 
 	return handled;
 }
@@ -1407,7 +706,7 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
 {
 	BOOL	handled = FALSE;
-	handled = childrenHandleMiddleMouseDown(x, y, mask) != NULL;
+	handled = LLTextBase::handleMouseDown(x, y, mask);
 
 	if (!handled)
 	{
@@ -1424,19 +723,12 @@ BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
 
 BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
 {
-	static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
 	BOOL handled = FALSE;
 
 	if(hasMouseCapture() )
 	{
 		if( mIsSelecting ) 
 		{
-			if (x != mLastSelectionX || y != mLastSelectionY)
-			{
-				mLastSelectionX = x;
-				mLastSelectionY = y;
-			}
-
 			mScroller->autoScroll(x, y);
 
 			S32 clamped_x = llclamp(x, mTextRect.mLeft, mTextRect.mRight);
@@ -1453,32 +745,19 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)
 	if( !handled )
 	{
 		// Pass to children
-		handled = LLView::childrenHandleHover(x, y, mask) != NULL;
+		handled = LLTextBase::handleHover(x, y, mask);
 	}
 
 	if( handled )
 	{
 		// Delay cursor flashing
-		resetKeystrokeTimer();
+		resetCursorBlink();
 	}
 
-	// Opaque
 	if( !handled )
 	{
-		// Check to see if we're over an HTML-style link
-		handled = handleHoverOverUrl(x, y);
-		if( handled )
-		{
-			lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;		
-			getWindow()->setCursor(UI_CURSOR_HAND);
-		}
-
-		if( !handled )
-		{
-			lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;		
-			getWindow()->setCursor(UI_CURSOR_IBEAM);
-			handled = TRUE;
-		}
+		getWindow()->setCursor(UI_CURSOR_IBEAM);
+		handled = TRUE;
 	}
 
 	return handled;
@@ -1489,8 +768,12 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
 {
 	BOOL	handled = FALSE;
 
-	// let scrollbar have first dibs
-	handled = LLView::childrenHandleMouseUp(x, y, mask) != NULL;
+	// if I'm not currently selecting text
+	if (!(hasSelection() && hasMouseCapture()))
+	{
+		// let text segments handle mouse event
+		handled = LLTextBase::handleMouseUp(x, y, mask);
+	}
 
 	if( !handled )
 	{
@@ -1503,11 +786,6 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
 			endSelection();
 		}
 		
-		if( !hasSelection() && hasMouseCapture() )
-		{
-			handleMouseUpOverUrl(x, y);
-		}
-
 		// take selection to 'primary' clipboard
 		updatePrimary();
 
@@ -1515,7 +793,7 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
 	}
 
 	// Delay cursor flashing
-	resetKeystrokeTimer();
+	resetCursorBlink();
 
 	if( hasMouseCapture()  )
 	{
@@ -1532,8 +810,8 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
 	BOOL	handled = FALSE;
 
-	// let scrollbar have first dibs
-	handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL;
+	// let scrollbar and text segments have first dibs
+	handled = LLTextBase::handleDoubleClick(x, y, mask);
 
 	if( !handled )
 	{
@@ -1571,7 +849,7 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 		mIsSelecting = FALSE;  
 
 		// delay cursor flashing
-		resetKeystrokeTimer();
+		resetCursorBlink();
 
 		// take selection to 'primary' clipboard
 		updatePrimary();
@@ -1583,35 +861,18 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 }
 
 
-// Allow calling cards to be dropped onto text fields.  Append the name and
-// a carriage return.
-// virtual
-BOOL LLTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask,
-					  BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
-					  EAcceptance *accept,
-					  std::string& tooltip_msg)
-{
-	*accept = ACCEPT_NO;
-
-	return TRUE;
-}
-
 //----------------------------------------------------------------------------
 // Returns change in number of characters in mText
 
-S32 LLTextEditor::execute( LLTextCmd* cmd )
+S32 LLTextEditor::execute( TextCmd* cmd )
 {
 	S32 delta = 0;
 	if( cmd->execute(this, &delta) )
 	{
 		// Delete top of undo stack
 		undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd);
-		if (enditer != mUndoStack.begin())
-		{
-			--enditer;
-			std::for_each(mUndoStack.begin(), enditer, DeletePointer());
-			mUndoStack.erase(mUndoStack.begin(), enditer);
-		}
+		std::for_each(mUndoStack.begin(), enditer, DeletePointer());
+		mUndoStack.erase(mUndoStack.begin(), enditer);
 		// Push the new command is now on the top (front) of the undo stack.
 		mUndoStack.push_front(cmd);
 		mLastCmd = cmd;
@@ -1627,7 +888,7 @@ S32 LLTextEditor::execute( LLTextCmd* cmd )
 
 S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment)
 {
-	return execute( new LLTextCmdInsert( pos, group_with_next_op, wstr, segment ) );
+	return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) );
 }
 
 S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op)
@@ -1638,12 +899,7 @@ S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op)
 	// store text segments
 	getSegmentsInRange(segments_to_remove, pos, pos + length, false);
 
-	return execute( new LLTextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) );
-}
-
-S32 LLTextEditor::append(const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment)
-{
-	return insert(getLength(), wstr, group_with_next_op, segment);
+	return execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) );
 }
 
 S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)
@@ -1654,7 +910,7 @@ S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)
 	}
 	else
 	{
-		return execute(new LLTextCmdOverwriteChar(pos, FALSE, wc));
+		return execute(new TextCmdOverwriteChar(pos, FALSE, wc));
 	}
 }
 
@@ -1674,8 +930,7 @@ void LLTextEditor::removeCharOrTab()
 		if (text[mCursorPos - 1] == ' ')
 		{
 			// Try to remove a "tab"
-			S32 line, offset;
-			getLineAndOffset(mCursorPos, &line, &offset);
+			S32 offset = getLineOffsetFromDocIndex(mCursorPos);
 			if (offset > 0)
 			{
 				chars_to_remove = offset % SPACES_PER_TAB;
@@ -1749,7 +1004,7 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc)
 	}
 	else
 	{
-		return execute(new LLTextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
+		return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
 	}
 }
 
@@ -2349,8 +1604,7 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask, BOOL* return
 				deleteSelection(FALSE);
 			}
 			
-			S32 line, offset;
-			getLineAndOffset( mCursorPos, &line, &offset );
+			S32 offset = getLineOffsetFromDocIndex(mCursorPos);
 
 			S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB);
 			for( S32 i=0; i < spaces_needed; i++ )
@@ -2481,7 +1735,7 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
 
 	if( handled )
 	{
-		resetKeystrokeTimer();
+		resetCursorBlink();
 
 		// Most keystrokes will make the selection box go away, but not all will.
 		if( !selection_modified &&
@@ -2534,7 +1788,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char)
 
 	if( handled )
 	{
-		resetKeystrokeTimer();
+		resetCursorBlink();
 
 		// Most keystrokes will make the selection box go away, but not all will.
 		deselect();
@@ -2573,8 +1827,7 @@ void LLTextEditor::doDelete()
 		if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) )
 		{
 			// Try to remove a full tab's worth of spaces
-			S32 line, offset;
-			getLineAndOffset( mCursorPos, &line, &offset );
+			S32 offset = getLineOffsetFromDocIndex(mCursorPos);
 			chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB);
 			if( chars_to_remove == 0 )
 			{
@@ -2694,7 +1947,7 @@ void LLTextEditor::redo()
 
 void LLTextEditor::onFocusReceived()
 {
-	LLUICtrl::onFocusReceived();
+	LLTextBase::onFocusReceived();
 	updateAllowingLanguageInput();
 }
 
@@ -2717,19 +1970,19 @@ void LLTextEditor::onFocusLost()
 	// Make sure cursor is shown again
 	getWindow()->showCursorFromMouseMove();
 
-	LLUICtrl::onFocusLost();
+	LLTextBase::onFocusLost();
 }
 
 void LLTextEditor::onCommit()
 {
 	setControlValue(getValue()); 
-	LLUICtrl::onCommit(); 
+	LLTextBase::onCommit(); 
 }
 
 void LLTextEditor::setEnabled(BOOL enabled)
 {
 	// just treat enabled as read-only flag
-	BOOL read_only = !enabled;
+	bool read_only = !enabled;
 	if (read_only != mReadOnly)
 	{
 		mReadOnly = read_only;
@@ -2738,195 +1991,6 @@ void LLTextEditor::setEnabled(BOOL enabled)
 	}
 }
 
-void LLTextEditor::drawBackground()
-{
-	S32 left = 0;
-	S32 top = getRect().getHeight();
-	S32 bottom = 0;
-
-	LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor.get()
-		: hasFocus() ? mFocusBgColor.get() : mWriteableBgColor.get();
-	if( mShowLineNumbers ) {
-		gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor.get() ); // line number area always read-only
-		gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN-1, bottom, LLColor4::grey3); // separator
-	} 
-}
-
-// Draws the black box behind the selected text
-void LLTextEditor::drawSelectionBackground()
-{
-	// Draw selection even if we don't have keyboard focus for search/replace
-	if( hasSelection() && !mLineInfoList.empty())
-	{
-		LLWString text = getWText();
-		std::vector<LLRect> selection_rects;
-
-		S32 selection_left		= llmin( mSelectionStart, mSelectionEnd );
-		S32 selection_right		= llmax( mSelectionStart, mSelectionEnd );
-		LLRect selection_rect = mTextRect;
-
-		// Skip through the lines we aren't drawing.
-		LLRect content_display_rect = mScroller->getVisibleContentRect();
-
-		// binary search for line that starts before top of visible buffer
-		line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
-		line_list_t::const_iterator end_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
-
-		bool done = false;
-
-		// Find the coordinates of the selected area
-		for (;line_iter != end_iter && !done; ++line_iter)
-		{
-			// is selection visible on this line?
-			if (line_iter->mDocIndexEnd > selection_left && line_iter->mDocIndexStart < selection_right)
-			{
-				segment_set_t::iterator segment_iter;
-				S32 segment_offset;
-				getSegmentAndOffset(line_iter->mDocIndexStart, &segment_iter, &segment_offset);
-				
-				LLRect selection_rect;
-				selection_rect.mLeft = 0;
-				selection_rect.mRight = 0;
-				selection_rect.mBottom = line_iter->mBottom;
-				selection_rect.mTop = line_iter->mTop;
-					
-				for(;segment_iter != mSegments.end(); ++segment_iter, segment_offset = 0)
-				{
-					LLTextSegmentPtr segmentp = *segment_iter;
-
-					S32 segment_line_start = segmentp->getStart() + segment_offset;
-					S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
-
-					// if selection after beginning of segment
-					if(selection_left >= segment_line_start)
-					{
-						S32 num_chars = llmin(selection_left, segment_line_end) - segment_line_start;
-						selection_rect.mLeft += segmentp->getWidth(segment_offset, num_chars);
-					}
-
-					// if selection spans end of current segment...
-					if (selection_right > segment_line_end)
-					{
-						// extend selection slightly beyond end of line
-						// to indicate selection of newline character (use "n" character to determine width)
-						selection_rect.mRight += segmentp->getWidth(segment_offset, segment_line_end - segment_line_start);
-					}
-					// else if selection ends on current segment...
-					else
-					{
-						S32 num_chars = selection_right - segment_line_start;
-						selection_rect.mRight += segmentp->getWidth(segment_offset, num_chars);
-
-						break;
-					}
-				}
-				selection_rects.push_back(selection_rect);
-			}
-		}
-		
-		// Draw the selection box (we're using a box instead of reversing the colors on the selected text).
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		const LLColor4& color = mReadOnly ? mReadOnlyBgColor.get() : mWriteableBgColor.get();
-		F32 alpha = hasFocus() ? 0.7f : 0.3f;
-		gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
-
-		for (std::vector<LLRect>::iterator rect_it = selection_rects.begin();
-			rect_it != selection_rects.end();
-			++rect_it)
-		{
-			LLRect selection_rect = *rect_it;
-			selection_rect.translate(mTextRect.mLeft - content_display_rect.mLeft, mTextRect.mBottom - content_display_rect.mBottom);
-			gl_rect_2d(selection_rect);
-		}
-	}
-}
-
-void LLTextEditor::drawCursor()
-{
-	if( hasFocus()
-		&& gFocusMgr.getAppHasFocus()
-		&& !mReadOnly)
-	{
-		LLWString wtext = getWText();
-		const llwchar* text = wtext.c_str();
-
-		LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos);
-		cursor_rect.translate(-1, 0);
-		segment_set_t::iterator seg_it = getSegIterContaining(mCursorPos);
-
-		// take style from last segment
-		LLTextSegmentPtr segmentp;
-
-		if (seg_it != mSegments.end())
-		{
-			segmentp = *seg_it;
-		}
-		else
-		{
-			//segmentp = mSegments.back();
-			return;
-		}
-
-		// Draw the cursor
-		// (Flash the cursor every half second starting a fixed time after the last keystroke)
-		F32 elapsed = mKeystrokeTimer.getElapsedTimeF32();
-		if( (elapsed < CURSOR_FLASH_DELAY ) || (S32(elapsed * 2) & 1) )
-		{
-
-			if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
-			{
-				S32 width = llmax(CURSOR_THICKNESS, segmentp->getWidth(mCursorPos - segmentp->getStart(), 1));
-				cursor_rect.mRight = cursor_rect.mLeft + width;
-			}
-			else
-			{
-				cursor_rect.mRight = cursor_rect.mLeft + CURSOR_THICKNESS;
-			}
-			
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-			gGL.color4fv( mCursorColor.get().mV );
-			
-			gl_rect_2d(cursor_rect);
-
-			if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n')
-			{
-				LLColor4 text_color;
-				const LLFontGL* fontp;
-				if (segmentp)
-				{
-					text_color = segmentp->getColor();
-					fontp = segmentp->getStyle()->getFont();
-				}
-				else if (mReadOnly)
-				{
-					text_color = mReadOnlyFgColor.get();
-					fontp = mDefaultFont;
-				}
-				else
-				{
-					text_color = mFgColor.get();
-					fontp = mDefaultFont;
-				}
-				fontp->render(text, mCursorPos, cursor_rect.mLeft, cursor_rect.mBottom, 
-					LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], 1.f),
-					LLFontGL::LEFT, LLFontGL::BOTTOM,
-					LLFontGL::NORMAL,
-					LLFontGL::NO_SHADOW,
-					1);
-			}
-
-			// Make sure the IME is in the right place
-			LLRect screen_pos = calcScreenRect();
-			LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_rect.mLeft), screen_pos.mBottom + llfloor(cursor_rect.mTop) );
-
-			ime_pos.mX = (S32) (ime_pos.mX * LLUI::sGLScaleFactor.mV[VX]);
-			ime_pos.mY = (S32) (ime_pos.mY * LLUI::sGLScaleFactor.mV[VY]);
-			getWindow()->setLanguageTextInput( ime_pos );
-		}
-	}
-}
-
 void LLTextEditor::drawPreeditMarker()
 {
 	static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0);
@@ -3032,96 +2096,6 @@ void LLTextEditor::drawPreeditMarker()
 }
 
 
-void LLTextEditor::drawText()
-{
-	LLWString text = getWText();
-	const S32 text_len = getLength();
-	if( text_len <= 0 )
-	{
-		return;
-	}
-	S32 selection_left = -1;
-	S32 selection_right = -1;
-	// Draw selection even if we don't have keyboard focus for search/replace
-	if( hasSelection())
-	{
-		selection_left = llmin( mSelectionStart, mSelectionEnd );
-		selection_right = llmax( mSelectionStart, mSelectionEnd );
-	}
-
-	LLGLSUIDefault gls_ui;
-	LLRect scrolled_view_rect = mScroller->getVisibleContentRect();
-	LLRect content_rect = mScroller->getContentWindowRect();
-	S32 first_line = getFirstVisibleLine();
-	S32 num_lines = getLineCount();
-	if (first_line >= num_lines)
-	{
-		return;
-	}
-	
-	S32 line_start = getLineStart(first_line);
-	// find first text segment that spans top of visible portion of text buffer
-	segment_set_t::iterator seg_iter = getSegIterContaining(line_start);
-	if (seg_iter == mSegments.end()) 
-	{
-		return;
-	}
-
-	LLTextSegmentPtr cur_segment = *seg_iter;
-
-	for (S32 cur_line = first_line; cur_line < num_lines; cur_line++)
-	{
-		line_info& line = mLineInfoList[cur_line];
-
-		if ((line.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom) 
-		{
-			break;
-		}
-
-		S32 next_start = -1;
-		S32 line_end = text_len;
-
-		if ((cur_line + 1) < num_lines)
-		{
-			next_start = getLineStart(cur_line + 1);
-			line_end = next_start;
-		}
-		if ( text[line_end-1] == '\n' )
-		{
-			--line_end;
-		}
-
-		LLRect text_rect(mTextRect.mLeft - scrolled_view_rect.mLeft,
-						line.mTop - scrolled_view_rect.mBottom + mTextRect.mBottom,
-						mTextRect.getWidth() - scrolled_view_rect.mLeft,
-						line.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom);
-
-		// draw a single line of text
-		S32 seg_start = line_start;
-		while( seg_start < line_end )
-		{
-			while( cur_segment->getEnd() <= seg_start )
-			{
-				seg_iter++;
-				if (seg_iter == mSegments.end())
-				{
-					llwarns << "Ran off the segmentation end!" << llendl;
-
-					return;
-				}
-				cur_segment = *seg_iter;
-			}
-			
-			S32 clipped_end	=	llmin( line_end, cur_segment->getEnd() )  - cur_segment->getStart();
-			text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect));
-
-			seg_start = clipped_end + cur_segment->getStart();
-		}
-
-		line_start = next_start;
-	}
-}
-
 void LLTextEditor::drawLineNumbers()
 {
 	LLGLSUIDefault gls_ui;
@@ -3136,24 +2110,31 @@ void LLTextEditor::drawLineNumbers()
 		return;
 	}
 	
-	S32 cursor_line = getCurrentLine();
+	S32 cursor_line = getLineNumFromDocIndex(mCursorPos);
 
 	if (mShowLineNumbers)
 	{
+		S32 left = 0;
+		S32 top = getRect().getHeight();
+		S32 bottom = 0;
+
+		gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor.get() ); // line number area always read-only
+		gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN-1, bottom, LLColor4::grey3); // separator
+
 		S32 last_line_num = -1;
 
 		for (S32 cur_line = first_line; cur_line < num_lines; cur_line++)
 		{
 			line_info& line = mLineInfoList[cur_line];
 
-			if ((line.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom) 
+			if ((line.mRect.mTop - scrolled_view_rect.mBottom) < mTextRect.mBottom) 
 			{
 				break;
 			}
 
-			S32 line_bottom = line.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom;
+			S32 line_bottom = line.mRect.mBottom - scrolled_view_rect.mBottom + mTextRect.mBottom;
 			// draw the line numbers
-			if(line.mLineNum != last_line_num && line.mTop <= scrolled_view_rect.mTop) 
+			if(line.mLineNum != last_line_num && line.mRect.mTop <= scrolled_view_rect.mTop) 
 			{
 				const LLFontGL *num_font = LLFontGL::getFontMonospace();
 				const LLWString ltext = utf8str_to_wstring(llformat("%d", line.mLineNum ));
@@ -3180,58 +2161,23 @@ void LLTextEditor::drawLineNumbers()
 
 void LLTextEditor::draw()
 {
-	// reflow if needed, on demand
-	reflow();
-
-	// then update scroll position, as cursor may have moved
-	updateScrollFromCursor();
-
-	LLColor4 bg_color = mReadOnly 
-						? mReadOnlyBgColor.get()
-						: hasFocus() 
-							? mFocusBgColor.get() 
-							: mWriteableBgColor.get();
-
-	mDocumentPanel->setBackgroundColor(bg_color);
-
-	LLView::draw();
-	drawBackground(); //overlays scrolling panel bg
-	drawLineNumbers();
-
 	{
 		// pad clipping rectangle so that cursor can draw at full width
 		// when at left edge of mTextRect
 		LLRect clip_rect(mTextRect);
 		clip_rect.stretch(1);
 		LLLocalClipRect clip(clip_rect);
-		drawSelectionBackground();
 		drawPreeditMarker();
-		drawText();
-		drawCursor();
 	}
 
+	LLTextBase::draw();
+	drawLineNumbers();
+
 	//RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret
 	// when in readonly mode
 	mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly);
 }
 
-
-S32	LLTextEditor::getFirstVisibleLine() const
-{
-	LLRect visible_region = mScroller->getVisibleContentRect();
-
-	// binary search for line that starts before top of visible buffer
-	line_list_t::const_iterator iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
-
-	return iter - mLineInfoList.begin();
-}
-
-// virtual
-void LLTextEditor::clear()
-{
-	setText(LLStringUtil::null);
-}
-
 // Start or stop the editor from accepting text-editing keystrokes
 // see also LLLineEditor
 void LLTextEditor::setFocus( BOOL new_state )
@@ -3247,7 +2193,7 @@ void LLTextEditor::setFocus( BOOL new_state )
 		getWindow()->allowLanguageTextInput(this, FALSE);
 	}
 
-	LLUICtrl::setFocus( new_state );
+	LLTextBase::setFocus( new_state );
 
 	if( new_state )
 	{
@@ -3255,461 +2201,80 @@ void LLTextEditor::setFocus( BOOL new_state )
 		gEditMenuHandler = this;
 
 		// Don't start the cursor flashing right away
-		resetKeystrokeTimer();
-	}
-	else
-	{
-		// Route menu back to the default
-		if( gEditMenuHandler == this )
-		{
-			gEditMenuHandler = NULL;
-		}
-
-		endSelection();
-	}
-}
-
-// virtual
-BOOL LLTextEditor::acceptsTextInput() const
-{
-	return !mReadOnly;
-}
-
-// Given a line (from the start of the doc) and an offset into the line, find the offset (pos) into text.
-S32 LLTextEditor::getPos( S32 line, S32 offset )
-{
-	S32 line_start = getLineStart(line);
-	S32 next_start = getLineStart(line+1);
-	if (next_start == line_start)
-	{
-		next_start = getLength() + 1;
-	}
-	S32 line_length = next_start - line_start - 1;
-	line_length = llmax(line_length, 0);
-	return line_start + llmin( offset, line_length );
-}
-
-
-void LLTextEditor::changePage( S32 delta )
-{
-	const S32 PIXEL_OVERLAP_ON_PAGE_CHANGE = 10;
-	if (delta == 0) return;
-
-	//RN: use pixel heights
-	S32 line, offset;
-	getLineAndOffset( mCursorPos, &line, &offset );
-
-	LLRect cursor_rect = getLocalRectFromDocIndex(mCursorPos);
-
-	if( delta == -1 )
-	{
-		mScroller->pageUp(PIXEL_OVERLAP_ON_PAGE_CHANGE);
-	}
-	else
-	if( delta == 1 )
-	{
-		mScroller->pageDown(PIXEL_OVERLAP_ON_PAGE_CHANGE);
-	}
-
-	if (getLocalRectFromDocIndex(mCursorPos) == cursor_rect)
-	{
-		// cursor didn't change apparent position, so move to top or bottom of document, respectively
-		if (delta < 0)
-		{
-			startOfDoc();
-		}
-		else
-		{
-			endOfDoc();
-		}
-	}
-	else
-	{
-		setCursorAtLocalPos(cursor_rect.getCenterX(), cursor_rect.getCenterY(), true, false);
-	}
-}
-
-void LLTextEditor::changeLine( S32 delta )
-{
-	S32 line, offset;
-	getLineAndOffset( mCursorPos, &line, &offset );
-
-	S32 new_line = line;
-	if( (delta < 0) && (line > 0 ) )
-	{
-		new_line = line - 1;
-	}
-	else if( (delta > 0) && (line < (getLineCount() - 1)) )
-	{
-		new_line = line + 1;
-	}
-
-	LLRect visible_region = mScroller->getVisibleContentRect();
-
-	S32 new_cursor_pos = getDocIndexFromLocalCoord(mDesiredXPixel, mLineInfoList[new_line].mBottom + mTextRect.mBottom - visible_region.mBottom, TRUE);
-	setCursorPos(new_cursor_pos, true);
-}
-
-
-void LLTextEditor::startOfLine()
-{
-	S32 line, offset;
-	getLineAndOffset( mCursorPos, &line, &offset );
-	setCursorPos(mCursorPos - offset);
-}
-
-
-// public
-void LLTextEditor::setCursorAndScrollToEnd()
-{
-	deselect();
-	endOfDoc();
-}
-
-void LLTextEditor::getLineAndColumnForPosition( S32 position, S32* line, S32* col, BOOL include_wordwrap )
-{
-	getLineAndOffset( mCursorPos, line, col, include_wordwrap );
-}
-
-void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) 
-{ 
-	getLineAndColumnForPosition(mCursorPos, line, col, include_wordwrap); 
-}
-
-S32 LLTextEditor::getCurrentLine()
-{
-	return getLineForPosition(mCursorPos);
-}
-
-S32 LLTextEditor::getLineForPosition(S32 position)
-{
-	S32 line, col;
-	getLineAndColumnForPosition(position, &line, &col, FALSE);
-	return line;
-}
-
-
-void LLTextEditor::endOfLine()
-{
-	S32 line, offset;
-	getLineAndOffset( mCursorPos, &line, &offset );
-	S32 num_lines = getLineCount();
-	if (line + 1 >= num_lines)
-	{
-		setCursorPos(getLength());
-	}
-	else
-	{
-		setCursorPos( getLineStart(line + 1) - 1 );
-	}
-}
-
-void LLTextEditor::startOfDoc()
-{
-	setCursorPos(0);
-}
-
-void LLTextEditor::endOfDoc()
-{
-	setCursorPos(getLength());
-}
-
-// Sets the scrollbar from the cursor position
-void LLTextEditor::updateScrollFromCursor()
-{
-	// Update scroll position even in read-only mode (when there's no cursor displayed)
-	// because startOfDoc()/endOfDoc() modify cursor position. See EXT-736.
-
-	if (!mScrollNeeded)
-	{
-		return;
-	}
-	mScrollNeeded = FALSE; 
-
-	S32 line, offset;
-	getLineAndOffset( mCursorPos, &line, &offset ); 
-
-	// scroll so that the cursor is at the top of the page
-	LLRect scroller_doc_window = mScroller->getVisibleContentRect();
-	LLRect cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos);
-	cursor_rect_doc.translate(scroller_doc_window.mLeft, scroller_doc_window.mBottom);
-	mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5));
-}
-
-void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	LLView::reshape( width, height, called_from_parent );
-
-	// do this first after reshape, because other things depend on
-	// up-to-date mTextRect
-	updateTextRect();
-	
-	needsReflow();
-}
-
-void LLTextEditor::autoIndent()
-{
-	// Count the number of spaces in the current line
-	S32 line, offset;
-	getLineAndOffset( mCursorPos, &line, &offset );
-	S32 line_start = getLineStart(line);
-	S32 space_count = 0;
-	S32 i;
-
-	LLWString text = getWText();
-	while( ' ' == text[line_start] )
-	{
-		space_count++;
-		line_start++;
-	}
-
-	// If we're starting a braced section, indent one level.
-	if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') )
-	{
-		space_count += SPACES_PER_TAB;
-	}
-
-	// Insert that number of spaces on the new line
-	addChar( '\n' );
-	for( i = 0; i < space_count; i++ )
-	{
-		addChar( ' ' );
-	}
-}
-
-// Inserts new text at the cursor position
-void LLTextEditor::insertText(const std::string &new_text)
-{
-	BOOL enabled = getEnabled();
-	setEnabled( TRUE );
-
-	// Delete any selected characters (the insertion replaces them)
-	if( hasSelection() )
-	{
-		deleteSelection(TRUE);
-	}
-
-	setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() ));
-	
-	needsReflow();
-
-	setEnabled( enabled );
-}
-
-
-void LLTextEditor::appendColoredText(const std::string &new_text, 
-									 bool allow_undo, 
-									 bool prepend_newline,
-									 const LLColor4 &color,
-									 const std::string& font_name)
-{
-	LLColor4 lcolor=color;
-	if (mParseHighlights)
-	{
-		LLTextParser* highlight = LLTextParser::getInstance();
-		highlight->parseFullLineHighlights(new_text, &lcolor);
-	}
-	
-	LLStyle::Params style_params;
-	style_params.color = lcolor;
-	if (font_name.empty())
-	{
-		style_params.font = mDefaultFont;
-	}
-	else
-	{
-		style_params.font.name = font_name;
-	}
-	appendStyledText(new_text, allow_undo, prepend_newline, style_params);
-}
-
-void LLTextEditor::appendStyledText(const std::string &new_text, 
-									 bool allow_undo, 
-									 bool prepend_newline,
-									 const LLStyle::Params& style_params)
-{
-	S32 part = (S32)LLTextParser::WHOLE;
-	if(mParseHTML)
-	{
-
-		S32 start=0,end=0;
-		LLUrlMatch match;
-		std::string text = new_text;
-		while ( LLUrlRegistry::instance().findUrl(text, match,
-		        boost::bind(&LLTextEditor::onUrlLabelUpdated, this, _1, _2)) )
-		{
-			start = match.getStart();
-			end = match.getEnd()+1;
-
-			LLStyle::Params link_params = style_params;
-			link_params.color = mLinkColor;
-			link_params.font.style = "UNDERLINE";
-			link_params.link_href = match.getUrl();
-
-			// output the text before the Url
-			if (start > 0)
-			{
-				if (part == (S32)LLTextParser::WHOLE ||
-					part == (S32)LLTextParser::START)
-				{
-					part = (S32)LLTextParser::START;
-				}
-				else
-				{
-					part = (S32)LLTextParser::MIDDLE;
-				}
-				std::string subtext=text.substr(0,start);
-				appendHighlightedText(subtext,allow_undo, prepend_newline, part, style_params); 
-				prepend_newline = false;
-			}
-
-			// output the styled Url
-			appendText(match.getLabel(),allow_undo, prepend_newline, link_params);
-			prepend_newline = false;
-
-			// set the tooltip for the Url label
-			if (! match.getTooltip().empty())
-			{
-				segment_set_t::iterator it = getSegIterContaining(getLength()-1);
-				if (it != mSegments.end())
-				{
-					LLTextSegmentPtr segment = *it;
-					segment->setToolTip(match.getTooltip());
-				}
-			}
-
-			// output an optional icon after the Url
-			if (! match.getIcon().empty())
-			{
-				LLUIImagePtr image = LLUI::getUIImage(match.getIcon());
-				if (image)
-				{
-					LLStyle::Params icon;
-					icon.image = image;
-					// TODO: fix spacing of images and remove the fixed char spacing
-					appendText("  ", allow_undo, prepend_newline, icon);
-				}
-			}
-
-			// move on to the rest of the text after the Url
-			if (end < (S32)text.length()) 
-			{
-				text = text.substr(end,text.length() - end);
-				end=0;
-				part=(S32)LLTextParser::END;
-			}
-			else
-			{
-				break;
-			}
-		}
-		if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END;
-		if (end < (S32)text.length()) appendHighlightedText(text,allow_undo, prepend_newline, part, style_params);		
-	}
-	else
-	{
-		appendHighlightedText(new_text, allow_undo, prepend_newline, part, style_params);
-	}
-}
-
-void LLTextEditor::appendHighlightedText(const std::string &new_text, 
-										 bool allow_undo, 
-										 bool prepend_newline,
-										 S32  highlight_part,
-										 const LLStyle::Params& style_params)
-{
-	if (mParseHighlights) 
+		resetCursorBlink();
+	}
+	else
 	{
-		LLTextParser* highlight = LLTextParser::getInstance();
-		
-		if (highlight && !style_params.isDefault())
+		// Route menu back to the default
+		if( gEditMenuHandler == this )
 		{
-			LLStyle::Params highlight_params = style_params;
-
-			LLSD pieces = highlight->parsePartialLineHighlights(new_text, highlight_params.color(), highlight_part);
-			bool lprepend=prepend_newline;
-			for (S32 i=0;i<pieces.size();i++)
-			{
-				LLSD color_llsd = pieces[i]["color"];
-				LLColor4 lcolor;
-				lcolor.setValue(color_llsd);
-				highlight_params.color = lcolor;
-				if (i != 0 && (pieces.size() > 1) ) lprepend=FALSE;
-				appendText((std::string)pieces[i]["text"], allow_undo, lprepend, highlight_params);
-			}
-			return;
+			gEditMenuHandler = NULL;
 		}
+
+		endSelection();
 	}
-	appendText(new_text, allow_undo, prepend_newline, style_params);
 }
 
-// Appends new text to end of document
-void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool prepend_newline,
-							  const LLStyle::Params& stylep)
+// public
+void LLTextEditor::setCursorAndScrollToEnd()
 {
-	if (new_text.empty()) return;
-
-	// Save old state
-	S32 selection_start = mSelectionStart;
-	S32 selection_end = mSelectionEnd;
-	BOOL was_selecting = mIsSelecting;
-	S32 cursor_pos = mCursorPos;
-	S32 old_length = getLength();
-	BOOL cursor_was_at_end = (mCursorPos == old_length);
-
 	deselect();
+	endOfDoc();
+}
 
-	setCursorPos(old_length);
+void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) 
+{ 
+	*line = getLineNumFromDocIndex(mCursorPos, include_wordwrap);
+	*col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap);
+}
 
-	LLWString wide_text;
+void LLTextEditor::autoIndent()
+{
+	// Count the number of spaces in the current line
+	S32 line = getLineNumFromDocIndex(mCursorPos);
+	S32 line_start = getLineStart(line);
+	S32 space_count = 0;
+	S32 i;
 
-	// Add carriage return if not first line
-	if (getLength() != 0
-		&& prepend_newline)
+	LLWString text = getWText();
+	while( ' ' == text[line_start] )
 	{
-		wide_text = utf8str_to_wstring(std::string("\n") + new_text);
+		space_count++;
+		line_start++;
 	}
-	else
+
+	// If we're starting a braced section, indent one level.
+	if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') )
 	{
-		wide_text = utf8str_to_wstring(new_text);
+		space_count += SPACES_PER_TAB;
 	}
 
-	LLTextSegmentPtr segmentp;
-	if (!stylep.isDefault())
+	// Insert that number of spaces on the new line
+	addChar( '\n' );
+	for( i = 0; i < space_count; i++ )
 	{
-		S32 segment_start = old_length;
-		S32 segment_end = old_length + wide_text.size();
-		segmentp = new LLNormalTextSegment(new LLStyle(stylep), segment_start, segment_end, *this );
+		addChar( ' ' );
 	}
+}
 
-	append(wide_text, TRUE, segmentp);
-
-	needsReflow();
-	
-	// Set the cursor and scroll position
-	if( selection_start != selection_end )
-	{
-		mSelectionStart = selection_start;
-		mSelectionEnd = selection_end;
+// Inserts new text at the cursor position
+void LLTextEditor::insertText(const std::string &new_text)
+{
+	BOOL enabled = getEnabled();
+	setEnabled( TRUE );
 
-		mIsSelecting = was_selecting;
-		setCursorPos(cursor_pos);
-	}
-	else if( cursor_was_at_end )
-	{
-		setCursorPos(getLength());
-	}
-	else
+	// Delete any selected characters (the insertion replaces them)
+	if( hasSelection() )
 	{
-		setCursorPos(cursor_pos);
+		deleteSelection(TRUE);
 	}
 
-	if( !allow_undo )
-	{
-		blockUndo();
-	}
-}
+	setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() ));
+	
+	needsReflow();
 
+	setEnabled( enabled );
+}
 
 void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool prepend_newline)
 {
@@ -3739,7 +2304,7 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,
 	}
 
 	LLTextSegmentPtr segment = new LLInlineViewSegment(widget, old_length, old_length + widget_text.size());
-	append(widget_wide_text, FALSE, segment);
+	insert(getLength(), widget_wide_text, FALSE, segment);
 
 	needsReflow();
 	
@@ -3767,12 +2332,6 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,
 	}
 }
 
-void LLTextEditor::onUrlLabelUpdated(const std::string &url,
-									 const std::string &label)
-{
-	// LLUrlRegistry has given us a new label for one of our Urls
-	replaceUrlLabel(url, label);
-}
 
 void LLTextEditor::replaceUrlLabel(const std::string &url,
 								   const std::string &label)
@@ -3830,164 +2389,10 @@ void LLTextEditor::removeTextFromEnd(S32 num_chars)
 	mSelectionStart = llclamp(mSelectionStart, 0, len);
 	mSelectionEnd = llclamp(mSelectionEnd, 0, len);
 
-	reflow();
+	needsReflow();
 	needsScroll();
 }
 
-///////////////////////////////////////////////////////////////////
-// Returns change in number of characters in mWText
-
-S32 LLTextEditor::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextEditor::segment_vec_t* segments )
-{
-	LLWString text(getWText());
-	S32 old_len = text.length();		// length() returns character length
-	S32 insert_len = wstr.length();
-
-	pos = getEditableIndex(pos, true);
-
-	segment_set_t::iterator seg_iter = getSegIterContaining(pos);
-
-	LLTextSegmentPtr default_segment;
-
-	LLTextSegmentPtr segmentp;
-	if (seg_iter != mSegments.end())
-	{
-		segmentp = *seg_iter;
-	}
-	else
-	{
-		//segmentp = mSegments.back();
-		return pos;
-	}
-
-	if (segmentp->canEdit())
-	{
-		segmentp->setEnd(segmentp->getEnd() + insert_len);
-		if (seg_iter != mSegments.end())
-		{
-			++seg_iter;
-		}
-	}
-	else
-	{
-		// create default editable segment to hold new text
-		default_segment = new LLNormalTextSegment( getDefaultStyle(), pos, pos + insert_len, *this);
-	}
-
-	// shift remaining segments to right
-	for(;seg_iter != mSegments.end(); ++seg_iter)
-	{
-		LLTextSegmentPtr segmentp = *seg_iter;
-		segmentp->setStart(segmentp->getStart() + insert_len);
-		segmentp->setEnd(segmentp->getEnd() + insert_len);
-	}
-
-	// insert new segments
-	if (segments)
-	{
-		if (default_segment.notNull())
-		{
-			// potentially overwritten by segments passed in
-			insertSegment(default_segment);
-		}
-		for (segment_vec_t::iterator seg_iter = segments->begin();
-			seg_iter != segments->end();
-			++seg_iter)
-		{
-			LLTextSegment* segmentp = *seg_iter;
-			insertSegment(segmentp);
-		}
-	}
-
-	text.insert(pos, wstr);
-    getViewModel()->setDisplay(text);
-
-	if ( truncate() )
-	{
-		// The user's not getting everything he's hoping for
-		make_ui_sound("UISndBadKeystroke");
-		insert_len = getLength() - old_len;
-	}
-
-	onValueChange(pos, pos + insert_len);
-
-	return insert_len;
-}
-
-S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length)
-{
-    LLWString text(getWText());
-	segment_set_t::iterator seg_iter = getSegIterContaining(pos);
-	while(seg_iter != mSegments.end())
-	{
-		LLTextSegmentPtr segmentp = *seg_iter;
-		S32 end = pos + length;
-		if (segmentp->getStart() < pos)
-		{
-			// deleting from middle of segment
-			if (segmentp->getEnd() > end)
-			{
-				segmentp->setEnd(segmentp->getEnd() - length);
-			}
-			// truncating segment
-			else
-			{
-				segmentp->setEnd(pos);
-			}
-		}
-		else if (segmentp->getStart() < end)
-		{
-			// deleting entire segment
-			if (segmentp->getEnd() <= end)
-			{
-				// remove segment
-				segmentp->unlinkFromDocument(this);
-				segment_set_t::iterator seg_to_erase(seg_iter++);
-				mSegments.erase(seg_to_erase);
-				continue;
-			}
-			// deleting head of segment
-			else
-			{
-				segmentp->setStart(pos);
-				segmentp->setEnd(segmentp->getEnd() - length);
-			}
-		}
-		else
-		{
-			// shifting segments backward to fill deleted portion
-			segmentp->setStart(segmentp->getStart() - length);
-			segmentp->setEnd(segmentp->getEnd() - length);
-		}
-		++seg_iter;
-	}
-
-	text.erase(pos, length);
-    getViewModel()->setDisplay(text);
-
-	// recreate default segment in case we erased everything
-	createDefaultSegment();
-
-	onValueChange(pos, pos);
-
-	return -length;	// This will be wrong if someone calls removeStringNoUndo with an excessive length
-}
-
-S32 LLTextEditor::overwriteCharNoUndo(S32 pos, llwchar wc)
-{
-	if (pos > (S32)getLength())
-	{
-		return 0;
-	}
-    LLWString text(getWText());
-	text[pos] = wc;
-    getViewModel()->setDisplay(text);
-
-	onValueChange(pos, pos + 1);
-
-	return 1;
-}
-
 //----------------------------------------------------------------------------
 
 void LLTextEditor::makePristine()
@@ -4051,29 +2456,13 @@ BOOL LLTextEditor::tryToRevertToPristineState()
 }
 
 
-void LLTextEditor::updateTextRect()
-{
-	static LLUICachedControl<S32> texteditor_border ("UITextEditorBorder", 0);
-	static LLUICachedControl<S32> texteditor_h_pad ("UITextEditorHPad", 0);
-	
-	LLRect old_text_rect = mTextRect;
-	mTextRect = mScroller->getContentWindowRect();
-	mTextRect.stretch(texteditor_border * -1);
-	mTextRect.mLeft += texteditor_h_pad;
-	mTextRect.mLeft += mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0;
-	if (mTextRect != old_text_rect)
-	{
-		needsReflow();
-	}
-}
-
-LLFastTimer::DeclareTimer FTM_TEXT_EDITOR_LOAD_KEYWORD("Text Editor Load Keywords");
+static LLFastTimer::DeclareTimer FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting");
 void LLTextEditor::loadKeywords(const std::string& filename,
 								const std::vector<std::string>& funcs,
 								const std::vector<std::string>& tooltips,
 								const LLColor3& color)
 {
-	LLFastTimer ft(FTM_TEXT_EDITOR_LOAD_KEYWORD);
+	LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING);
 	if(mKeywords.loadFromFile(filename))
 	{
 		S32 count = llmin(funcs.size(), tooltips.size());
@@ -4094,27 +2483,9 @@ void LLTextEditor::loadKeywords(const std::string& filename,
 	}
 }
 
-void LLTextEditor::createDefaultSegment()
-{
-	// ensures that there is always at least one segment
-	if (mSegments.empty())
-	{
-		LLTextSegmentPtr default_segment = new LLNormalTextSegment( getDefaultStyle(), 0, getLength() + 1, *this);
-		mSegments.insert(default_segment);
-		default_segment->linkToDocument(this);
-	}
-}
-
-LLStyleSP	LLTextEditor::getDefaultStyle()
-{
-	LLColor4 text_color = ( mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get() );
-	return LLStyleSP(new LLStyle(LLStyle::Params().color(text_color).font(mDefaultFont)));
-}
-
-LLFastTimer::DeclareTimer FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments");
 void LLTextEditor::updateSegments()
 {
-	LLFastTimer ft(FTM_UPDATE_TEXT_SEGMENTS);
+	LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING);
 	if (mKeywords.isLoaded())
 	{
 		// HACK:  No non-ascii keywords for now
@@ -4125,11 +2496,11 @@ void LLTextEditor::updateSegments()
 		segment_set_t::iterator insert_it = mSegments.begin();
 		for (segment_vec_t::iterator list_it = segment_list.begin(); list_it != segment_list.end(); ++list_it)
 		{
-			insert_it = mSegments.insert(insert_it, *list_it);
+			insertSegment(*list_it);
 		}
 	}
 
-	createDefaultSegment();
+	LLTextBase::updateSegments();
 }
 
 void LLTextEditor::updateLinkSegments()
@@ -4155,66 +2526,7 @@ void LLTextEditor::updateLinkSegments()
 	}
 }
 
-void LLTextEditor::insertSegment(LLTextSegmentPtr segment_to_insert)
-{
-	if (segment_to_insert.isNull()) 
-	{
-		return;
-	}
-
-	segment_set_t::iterator cur_seg_iter = getSegIterContaining(segment_to_insert->getStart());
-
-	if (cur_seg_iter == mSegments.end())
-	{
-		mSegments.insert(segment_to_insert);
-		segment_to_insert->linkToDocument(this);
-	}
-	else
-	{
-		LLTextSegmentPtr cur_segmentp = *cur_seg_iter;
-		if (cur_segmentp->getStart() < segment_to_insert->getStart())
-		{
-			S32 old_segment_end = cur_segmentp->getEnd();
-			// split old at start point for new segment
-			cur_segmentp->setEnd(segment_to_insert->getStart());
-			// advance to next segment
-			++cur_seg_iter;
-			// insert remainder of old segment
-			LLTextSegmentPtr remainder_segment = new LLNormalTextSegment( cur_segmentp->getStyle(), segment_to_insert->getStart(), old_segment_end, *this);
-			cur_seg_iter = mSegments.insert(cur_seg_iter, remainder_segment);
-			remainder_segment->linkToDocument(this);
-			// insert new segment before remainder of old segment
-			cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert);
-
-			segment_to_insert->linkToDocument(this);
-			// move to "remanider" segment and start truncation there
-			++cur_seg_iter;
-		}
-		else
-		{
-			cur_seg_iter = mSegments.insert(cur_seg_iter, segment_to_insert);
-			++cur_seg_iter;
-			segment_to_insert->linkToDocument(this);
-		}
 
-		// now delete/truncate remaining segments as necessary
-		while(cur_seg_iter != mSegments.end())
-		{
-			cur_segmentp = *cur_seg_iter;
-			if (cur_segmentp->getEnd() <= segment_to_insert->getEnd())
-			{
-				cur_segmentp->unlinkFromDocument(this);
-				segment_set_t::iterator seg_to_erase(cur_seg_iter++);
-				mSegments.erase(seg_to_erase);
-			}
-			else
-			{
-				cur_segmentp->setStart(segment_to_insert->getEnd());
-				break;
-			}
-		}
-	}
-}
 
 void LLTextEditor::onMouseCaptureLost()
 {
@@ -4400,7 +2712,7 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string,
 
 	if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
 	{
-		mPreeditOverwrittenWString = getWSubString(insert_preedit_at, mPreeditWString.length());
+		mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length());
 		removeStringNoUndo(insert_preedit_at, mPreeditWString.length());
 	}
 	else
@@ -4415,7 +2727,7 @@ void LLTextEditor::updatePreedit(const LLWString &preedit_string,
 	setCursorPos(insert_preedit_at + caret_position);
 
 	// Update of the preedit should be caused by some key strokes.
-	mKeystrokeTimer.reset();
+	resetCursorBlink();
 
 	onKeyStroke();
 }
@@ -4578,93 +2890,6 @@ S32 LLTextEditor::getPreeditFontSize() const
 	return llround(mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
 }
 
-LLWString       LLTextEditor::getWText() const
-{
-    return getViewModel()->getDisplay();
-}
-
-void	LLTextEditor::onValueChange(S32 start, S32 end)
-{
-}
-
-//
-// LLInlineViewSegment
-//
-
-LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end)
-:	LLTextSegment(start, end),
-	mView(view)
-{
-} 
-
-LLInlineViewSegment::~LLInlineViewSegment()
-{
-	mView->die();
-}
-
-S32	LLInlineViewSegment::getWidth(S32 first_char, S32 num_chars) const
-{
-	if (first_char == 0 && num_chars == 0) 
-	{
-		return 0;
-	}
-	else
-	{
-		return mView->getRect().getWidth();
-	}
-}
-
-S32	LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
-{
-	if (line_offset != 0 && num_pixels < mView->getRect().getWidth()) 
-	{
-		return 0;
-	}
-	else
-	{
-		return mEnd - mStart;
-	}
-}
-
-void LLInlineViewSegment::updateLayout(const LLTextBase& editor)
-{
-	const LLTextEditor *ed = dynamic_cast<const LLTextEditor *>(&editor);
-	if (ed)
-	{
-		LLRect start_rect = ed->getLocalRectFromDocIndex(mStart);
-		LLRect doc_rect = ed->getDocumentPanel()->getRect();
-		mView->setOrigin(doc_rect.mLeft + start_rect.mLeft, doc_rect.mBottom + start_rect.mBottom);
-	}
-}
-
-F32	LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
-{
-	return (F32)(draw_rect.mLeft + mView->getRect().getWidth());
-}
-
-S32	LLInlineViewSegment::getMaxHeight() const
-{
-	return mView->getRect().getHeight();
-}
-
-void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor)
-{
-	LLTextEditor *ed = dynamic_cast<LLTextEditor *>(editor);
-	if (ed)
-	{
-		ed->removeDocumentChild(mView);
-	}
-}
-
-void LLInlineViewSegment::linkToDocument(LLTextBase* editor)
-{
-	LLTextEditor *ed = dynamic_cast<LLTextEditor *>(editor);
-	if (ed)
-	{
-		ed->addDocumentChild(mView);
-	}
-}
-
 BOOL LLTextEditor::isDirty() const
 {
 	if(mReadOnly)
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index a04261c4be9..0e5707a3a63 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -37,7 +37,6 @@
 
 #include "llrect.h"
 #include "llkeywords.h"
-#include "lluictrl.h"
 #include "llframetimer.h"
 #include "lldarray.h"
 #include "llstyle.h"
@@ -52,66 +51,27 @@
 class LLFontGL;
 class LLScrollbar;
 class LLKeywordToken;
-class LLTextCmd;
+class TextCmd;
 class LLUICtrlFactory;
 class LLScrollContainer;
 
-class LLInlineViewSegment : public LLTextSegment
-{
-public:
-	LLInlineViewSegment(LLView* widget, S32 start, S32 end);
-	~LLInlineViewSegment();
-	/*virtual*/ S32			getWidth(S32 first_char, S32 num_chars) const;
-	/*virtual*/ S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const;
-	/*virtual*/ void		updateLayout(const class LLTextBase& editor);
-	/*virtual*/ F32			draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect);
-	/*virtuaL*/ S32			getMaxHeight() const;
-	/*virtual*/ bool		canEdit() const { return false; }
-	/*virtual*/ void		unlinkFromDocument(class LLTextBase* editor);
-	/*virtual*/ void		linkToDocument(class LLTextBase* editor);
-
-private:
-	LLView* mView;
-};
-
 class LLTextEditor :
 	public LLTextBase,
-	public LLUICtrl,
-	private LLEditMenuHandler,
 	protected LLPreeditor
 {
 public:
-	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
+	struct Params : public LLInitParam::Block<Params, LLTextBase::Params>
 	{
 		Optional<std::string>	default_text;
-		Optional<S32>			max_text_length;
 
-		Optional<bool>			read_only,
-								embedded_items,
-								word_wrap,
+		Optional<bool>			embedded_items,
 								ignore_tab,
-								hide_border,
-								track_bottom,
 								handle_edit_keys_directly,
 								show_line_numbers,
 								commit_on_focus_lost;
 
 		//colors
-		Optional<LLUIColor>		cursor_color,
-								default_color,
-								text_color,
-								text_readonly_color,
-								bg_readonly_color,
-								bg_writeable_color,
-								bg_focus_color,
-								link_color;
-
-		Optional<LLViewBorder::Params> border;
-
-		Ignored					type,
-								length,
-								is_unicode,
-								hide_scrollbar;
+		Optional<LLUIColor>		default_color;
 
 		Params();
 	};
@@ -128,15 +88,6 @@ class LLTextEditor :
 	static const llwchar LAST_EMBEDDED_CHAR =  0x10ffff;
 	static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1;
 
-
-	struct compare_segment_end
-	{
-		bool operator()(const LLTextSegmentPtr& a, const LLTextSegmentPtr& b) const
-		{
-			return a->getEnd() < b->getEnd();
-		}
-	};
-
 	virtual ~LLTextEditor();
 
 	typedef boost::signals2::signal<void (LLTextEditor* caller)> keystroke_signal_t;
@@ -155,14 +106,9 @@ class LLTextEditor :
 	virtual BOOL	handleKeyHere(KEY key, MASK mask );
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 
-	virtual BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect);
-	virtual BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
-									  EDragAndDropType cargo_type, void *cargo_data,
-									  EAcceptance *accept, std::string& tooltip_msg);
 	virtual void	onMouseCaptureLost();
 
 	// view overrides
-	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 	virtual void	draw();
 	virtual void	onFocusReceived();
 	virtual void	onFocusLost();
@@ -170,11 +116,8 @@ class LLTextEditor :
 	virtual void	setEnabled(BOOL enabled);
 
 	// uictrl overrides
-	virtual void	clear();
 	virtual void	setFocus( BOOL b );
-	virtual BOOL	acceptsTextInput() const;
 	virtual BOOL	isDirty() const;
-	virtual void 	setValue(const LLSD& value);
 
 	// LLEditMenuHandler interface
 	virtual void	undo();
@@ -201,12 +144,9 @@ class LLTextEditor :
 	virtual void	deselect();
 	virtual BOOL	canDeselect() const;
 
-	virtual void	onValueChange(S32 start, S32 end);
-
 	void			selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE);
 	BOOL			replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE);
 	void			replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive);
-	BOOL			hasSelection() const		{ return (mSelectionStart !=mSelectionEnd); }
 	void			replaceUrlLabel(const std::string &url, const std::string &label);
 	
 	// Undo/redo stack
@@ -216,9 +156,6 @@ class LLTextEditor :
 	virtual void	makePristine();
 	BOOL			isPristine() const;
 	BOOL			allowsEmbeddedItems() const { return mAllowEmbeddedItems; }
-	S32				getLength() const { return getWText().length(); }
-	void			setReadOnly(bool read_only) { mReadOnly = read_only; }
-	bool			getReadOnly() { return mReadOnly; }
 
 	//
 	// Text manipulation
@@ -226,25 +163,10 @@ class LLTextEditor :
 
 	// inserts text at cursor
 	void			insertText(const std::string &text);
-	// appends text at end
-	void 			appendText(const std::string &wtext, bool allow_undo, bool prepend_newline,
-								const LLStyle::Params& style = LLStyle::Params());
-
-	void 			appendColoredText(const std::string &wtext, bool allow_undo, 
-									  bool prepend_newline,
-									  const LLColor4 &color,
-									  const std::string& font_name = LLStringUtil::null);
-	// if styled text starts a line, you need to prepend a newline.
-	void 			appendStyledText(const std::string &new_text, bool allow_undo, 
-									 bool prepend_newline,
-									 const LLStyle::Params& style);
-	void			appendHighlightedText(const std::string &new_text,  bool allow_undo, 
-										  bool prepend_newline,	 S32  highlight_part,
-										  const LLStyle::Params& style);
+
 	void			appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool prepend_newline);
 	// Non-undoable
 	void			setText(const LLStringExplicit &utf8str);
-	void			setWText(const LLWString &wtext);
 
 
 	// Removes text from the end of document
@@ -253,14 +175,9 @@ class LLTextEditor :
 
 	BOOL			tryToRevertToPristineState();
 
-	bool			setCursor(S32 row, S32 column);
-	bool			setCursorPos(S32 offset, bool keep_cursor_offset = false);
 	void			setCursorAndScrollToEnd();
 
-	void			getLineAndColumnForPosition( S32 position,  S32* line, S32* col, BOOL include_wordwrap );
 	void			getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap );
-	S32				getLineForPosition(S32 position);
-	S32				getCurrentLine();
 
 	void			loadKeywords(const std::string& filename,
 								 const std::vector<std::string>& funcs,
@@ -277,55 +194,17 @@ class LLTextEditor :
 	virtual BOOL	importBuffer(const char* buffer, S32 length );
 	virtual BOOL	exportBuffer(std::string& buffer );
 
-	const class DocumentPanel*	getDocumentPanel() const { return mDocumentPanel; }
-
 	const LLUUID&	getSourceID() const						{ return mSourceID; }
 
-	// Callbacks
- 	std::string     getText() const;
-	
-	// Callback for when a Url has been resolved by the server
-	void            onUrlLabelUpdated(const std::string &url, const std::string &label);
-
-	// Getters
-	LLWString       getWText() const;
-	llwchar			getWChar(S32 pos) const { return getWText()[pos]; }
-	LLWString		getWSubString(S32 pos, S32 len) const { return getWText().substr(pos, len); }
-	
-	typedef std::vector<LLTextSegmentPtr> segment_vec_t;
-
 	const LLTextSegmentPtr	getPreviousSegment() const;
 	void getSelectedSegments(segment_vec_t& segments) const;
 
-	void getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const;
-	LLRect			getLocalRectFromDocIndex(S32 index) const; 
-
-	void			addDocumentChild(LLView* view);
-	void			removeDocumentChild(LLView* view);
-
 protected:
-	// Change cursor
-	void			startOfLine();
-	void			endOfLine();
-	void			startOfDoc();
-	void			endOfDoc();
-
 	void			drawPreeditMarker();
 
-	void			needsReflow() { mReflowNeeded = TRUE; }
-	void			needsScroll() { mScrollNeeded = TRUE; }
-	void			updateCursorXPos();
-
-	void			updateScrollFromCursor();
-	void			updateTextRect();
-	const LLRect&	getTextRect() const { return mTextRect; }
-
 	void 			assignEmbedded(const std::string &s);
-	BOOL 			truncate();				// Returns true if truncation occurs
 	
 	void			removeCharOrTab();
-	void			setCursorAtLocalPos(S32 x, S32 y, bool round, bool keep_cursor_offset = false);
-	/*virtual*/ S32 getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const;
 
 	void			indentSelectedLines( S32 spaces );
 	S32				indentLine( S32 pos, S32 spaces );
@@ -340,68 +219,21 @@ class LLTextEditor :
 	BOOL			handleEditKey(const KEY key, const MASK mask);
 
 	BOOL			selectionContainsLineBreaks();
-	void			startSelection();
-	void			endSelection();
 	void			deleteSelection(BOOL transient_operation);
 
 	S32				prevWordPos(S32 cursorPos) const;
 	S32				nextWordPos(S32 cursorPos) const;
 
-	S32 			getLineCount() const { return mLineInfoList.size(); }
-	S32 			getLineStart( S32 line ) const;
-	S32 			getLineHeight( S32 line ) const;
-	void			getLineAndOffset(S32 pos, S32* linep, S32* offsetp, bool include_wordwrap = true) const;
-	S32				getPos(S32 line, S32 offset);
-
-	void			changePage(S32 delta);
-	void			changeLine(S32 delta);
-
 	void			autoIndent();
 	
 	void			findEmbeddedItemSegments(S32 start, S32 end);
-	void			insertSegment(LLTextSegmentPtr segment_to_insert);
-	
+	void			getSegmentsInRange(segment_vec_t& segments, S32 start, S32 end, bool include_partial) const;
+
 	virtual llwchar	pasteEmbeddedItem(llwchar ext_char) { return ext_char; }
 	
-	// Abstract inner base class representing an undoable editor command.
-	// Concrete sub-classes can be defined for operations such as insert, remove, etc.
-	// Used as arguments to the execute() method below.
-	class LLTextCmd
-	{
-	public:
-		LLTextCmd( S32 pos, BOOL group_with_next, LLTextSegmentPtr segment = LLTextSegmentPtr() ) 
-		:	mPos(pos), 
-			mGroupWithNext(group_with_next)
-		{
-			if (segment.notNull())
-			{
-				mSegments.push_back(segment);
-			}
-		}
-		virtual			~LLTextCmd() {}
-		virtual BOOL	execute(LLTextEditor* editor, S32* delta) = 0;
-		virtual S32		undo(LLTextEditor* editor) = 0;
-		virtual S32		redo(LLTextEditor* editor) = 0;
-		virtual BOOL	canExtend(S32 pos) const { return FALSE; }
-		virtual void	blockExtensions() {}
-		virtual BOOL	extendAndExecute( LLTextEditor* editor, S32 pos, llwchar c, S32* delta ) { llassert(0); return 0; }
-		virtual BOOL	hasExtCharValue( llwchar value ) const { return FALSE; }
-
-		// Defined here so they can access protected LLTextEditor editing methods
-		S32				insert(LLTextEditor* editor, S32 pos, const LLWString &wstr) { return editor->insertStringNoUndo( pos, wstr, &mSegments ); }
-		S32 			remove(LLTextEditor* editor, S32 pos, S32 length) { return editor->removeStringNoUndo( pos, length ); }
-		S32				overwrite(LLTextEditor* editor, S32 pos, llwchar wc) { return editor->overwriteCharNoUndo(pos, wc); }
-		
-		S32				getPosition() const { return mPos; }
-		BOOL			groupWithNext() const { return mGroupWithNext; }
-		
-	protected:
-		const S32			mPos;
-		BOOL				mGroupWithNext;
-		segment_vec_t		mSegments;
-	};
+
 	// Here's the method that takes and applies text commands.
-	S32 			execute(LLTextCmd* cmd);
+	S32 			execute(TextCmd* cmd);
 
 	// Undoable operations
 	void			addChar(llwchar c); // at mCursorPos
@@ -411,15 +243,7 @@ class LLTextEditor :
 	S32 			removeChar(S32 pos);
 	S32				insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment);
 	S32				remove(S32 pos, S32 length, bool group_with_next_op);
-	S32				append(const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment);
 	
-	// Direct operations
-	S32				insertStringNoUndo(S32 pos, const LLWString &wstr, segment_vec_t* segments = NULL); // returns num of chars actually inserted
-	S32 			removeStringNoUndo(S32 pos, S32 length);
-	S32				overwriteCharNoUndo(S32 pos, llwchar wc);
-
-	void			resetKeystrokeTimer() { mKeystrokeTimer.reset(); }
-
 	void			updateAllowingLanguageInput();
 	BOOL			hasPreeditString() const;
 
@@ -432,6 +256,7 @@ class LLTextEditor :
 	virtual void	getSelectionRange(S32 *position, S32 *length) const;
 	virtual BOOL	getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const;
 	virtual S32		getPreeditFontSize() const;
+	virtual LLWString getPreeditString() const { return getWText(); }
 	//
 	// Protected data
 	//
@@ -439,74 +264,31 @@ class LLTextEditor :
 	// as possible behind protected accessor methods.
 	//
 
-	// I-beam is just after the mCursorPos-th character.
-	S32				mCursorPos;
-
 	// Use these to determine if a click on an embedded item is a drag or not.
 	S32				mMouseDownX;
 	S32				mMouseDownY;
 	
-	// Are we in the middle of a drag-select?  To figure out if there is a current
-	// selection, call hasSelection().
-	BOOL			mIsSelecting;
-	S32				mSelectionStart;
-	S32				mSelectionEnd;
-	S32				mLastSelectionX;
-	S32				mLastSelectionY;
-
-	BOOL			mParseHighlights;
-
-	// Scrollbar data
-	class DocumentPanel*	mDocumentPanel;
-	LLScrollContainer*	mScroller;
-
-	void			*mOnScrollEndData;
-
 	LLWString			mPreeditWString;
 	LLWString			mPreeditOverwrittenWString;
 	std::vector<S32> 	mPreeditPositions;
 	std::vector<BOOL> 	mPreeditStandouts;
 
-	S32			mScrollIndex; // index into document that controls default scroll position
-
 protected:
-	LLUIColor		mCursorColor;
-	LLUIColor		mFgColor;
-	LLUIColor		mDefaultColor;
-	LLUIColor		mReadOnlyFgColor;
-	LLUIColor		mWriteableBgColor;
-	LLUIColor		mReadOnlyBgColor;
-	LLUIColor		mFocusBgColor;
-	LLUIColor		mLinkColor;
+	LLUIColor			mDefaultColor;
 
-	BOOL			mReadOnly;
-	BOOL			mShowLineNumbers;
+	BOOL				mShowLineNumbers;
 
-	void			updateSegments();
-	void			updateLinkSegments();
+	/*virtual*/ void	updateSegments();
+	void				updateLinkSegments();
 
 private:
-
 	//
 	// Methods
 	//
 	void	        pasteHelper(bool is_primary);
 
-	virtual 		LLTextViewModel* getViewModel() const;
-	void			reflow(S32 startpos = 0);
-
-	void			createDefaultSegment();
-	LLStyleSP		getDefaultStyle();
-	S32				getEditableIndex(S32 index, bool increasing_direction);
-
-	void			drawBackground();
-	void			drawSelectionBackground();
-	void			drawCursor();
-	void			drawText();
 	void			drawLineNumbers();
 
-	S32				getFirstVisibleLine() const;
-
 	void			onKeyStroke();
 
 	//
@@ -514,56 +296,25 @@ class LLTextEditor :
 	//
 	LLKeywords		mKeywords;
 
-	// Concrete LLTextCmd sub-classes used by the LLTextEditor base class
-	class LLTextCmdInsert;
-	class LLTextCmdAddChar;
-	class LLTextCmdOverwriteChar;
-	class LLTextCmdRemove;
-
-	S32				mMaxTextByteLength;		// Maximum length mText is allowed to be in bytes
+	// Concrete TextCmd sub-classes used by the LLTextEditor base class
+	class TextCmdInsert;
+	class TextCmdAddChar;
+	class TextCmdOverwriteChar;
+	class TextCmdRemove;
 
 	class LLViewBorder*	mBorder;
 
 	BOOL			mBaseDocIsPristine;
-	LLTextCmd*		mPristineCmd;
+	TextCmd*		mPristineCmd;
 
-	LLTextCmd*		mLastCmd;
+	TextCmd*		mLastCmd;
 
-	typedef std::deque<LLTextCmd*> undo_stack_t;
+	typedef std::deque<TextCmd*> undo_stack_t;
 	undo_stack_t	mUndoStack;
 
-	S32				mDesiredXPixel;			// X pixel position where the user wants the cursor to be
-	LLRect			mTextRect;				// The rect in which text is drawn.  Excludes borders.
-	// List of offsets and segment index of the start of each line.  Always has at least one node (0).
-	struct line_info
-	{
-		line_info(S32 index_start, S32 index_end, S32 top, S32 bottom, S32 line_num) 
-		:	mDocIndexStart(index_start), 
-			mDocIndexEnd(index_end),
-			mTop(top),
-			mBottom(bottom),
-			mLineNum(line_num)
-		{}
-		S32 mDocIndexStart;
-		S32 mDocIndexEnd;
-		S32 mTop;
-		S32 mBottom;
-		S32 mLineNum; // actual line count (ignoring soft newlines due to word wrap)
-	};
-	struct compare_bottom;
-	struct compare_top;
-	struct line_end_compare;
-	typedef std::vector<line_info> line_list_t;
-	line_list_t		mLineInfoList;
-	BOOL			mReflowNeeded;
-	BOOL			mScrollNeeded;
-
-	LLFrameTimer	mKeystrokeTimer;
-
 	BOOL			mTabsToNextField;		// if true, tab moves focus to next field, else inserts spaces
 	BOOL			mCommitOnFocusLost;
 	BOOL			mTakesFocus;
-	BOOL			mTrackBottom;			// if true, keeps scroll position at bottom during resize
 
 	BOOL			mAllowEmbeddedItems;
 
diff --git a/indra/llui/lltextparser.cpp b/indra/llui/lltextparser.cpp
index 707dd0afdd9..76a39e30945 100644
--- a/indra/llui/lltextparser.cpp
+++ b/indra/llui/lltextparser.cpp
@@ -103,7 +103,7 @@ S32 LLTextParser::findPattern(const std::string &text, LLSD highlight)
 	return found;
 }
 
-LLSD LLTextParser::parsePartialLineHighlights(const std::string &text, const LLColor4 &color, S32 part, S32 index)
+LLSD LLTextParser::parsePartialLineHighlights(const std::string &text, const LLColor4 &color, EHighlightPosition part, S32 index)
 {
 	//evil recursive string atomizer.
 	LLSD ret_llsd, start_llsd, middle_llsd, end_llsd;
@@ -122,7 +122,7 @@ LLSD LLTextParser::parsePartialLineHighlights(const std::string &text, const LLC
 				{
 					S32 end =  std::string(mHighlights[i]["pattern"]).length();
 					S32 len = text.length();
-					S32 newpart;
+					EHighlightPosition newpart;
 					if (start==0)
 					{
 						start_llsd[0]["text"] =text.substr(0,end);
diff --git a/indra/llui/lltextparser.h b/indra/llui/lltextparser.h
index fb1a7758b7b..072ac0f3008 100644
--- a/indra/llui/lltextparser.h
+++ b/indra/llui/lltextparser.h
@@ -34,8 +34,6 @@
 #ifndef LL_LLTEXTPARSER_H
 #define LL_LLTEXTPARSER_H
 
-#include "lltextparser.h"
-
 #include "llsd.h"
 
 class LLUUID;
@@ -45,17 +43,17 @@ class LLColor4;
 class LLTextParser
 {
 public:
-	enum ConditionType { CONTAINS, MATCHES, STARTS_WITH, ENDS_WITH };
-	enum HighlightType { PART, ALL };
-	enum HighlightPosition { WHOLE, START, MIDDLE, END };
-	enum DialogAction  { ACTION_NONE, ACTION_CLOSE, ACTION_ADD, ACTION_COPY, ACTION_UPDATE };
+	typedef enum e_condition_type { CONTAINS, MATCHES, STARTS_WITH, ENDS_WITH } EConditionType;
+	typedef enum e_highlight_type { PART, ALL } EHighlightType;
+	typedef enum e_highlight_position { WHOLE, START, MIDDLE, END } EHighlightPosition;
+	typedef enum e_dialog_action { ACTION_NONE, ACTION_CLOSE, ACTION_ADD, ACTION_COPY, ACTION_UPDATE } EDialogAction;
 
 	static LLTextParser* getInstance();
 	LLTextParser(){};
 	~LLTextParser();
 
 	S32  findPattern(const std::string &text, LLSD highlight);
-	LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color,S32 part=WHOLE, S32 index=0);
+	LLSD parsePartialLineHighlights(const std::string &text,const LLColor4 &color, EHighlightPosition part=WHOLE, S32 index=0);
 	bool parseFullLineHighlights(const std::string &text, LLColor4 *color);
 
 	std::string getFileName();
diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp
new file mode 100644
index 00000000000..717e135412e
--- /dev/null
+++ b/indra/llui/lltoggleablemenu.cpp
@@ -0,0 +1,82 @@
+/** 
+ * @file lltoggleablemenu.cpp
+ * @brief Menu toggled by a button press
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "linden_common.h"
+
+#include "lltoggleablemenu.h"
+#include "lluictrlfactory.h"
+
+static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");
+
+LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)
+:	LLMenuGL(p),
+	mClosedByButtonClick(false)
+{
+}
+
+// virtual
+void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
+{
+	S32 x,y;
+	LLUI::getMousePositionLocal(LLUI::getRootView(), &x, &y);
+
+	if (!curVisibilityIn && mButtonRect.pointInRect(x, y))
+	{
+		mClosedByButtonClick = true;
+	}
+}
+
+void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view) 
+{
+	LLRect screen;
+	current_view->localRectToScreen(rect, &screen);
+	mButtonRect = screen;
+}
+
+bool LLToggleableMenu::toggleVisibility() 
+{
+	if (mClosedByButtonClick)
+	{
+		mClosedByButtonClick = false;
+		return false;
+	}
+
+	if (getVisible())
+	{
+		setVisible(FALSE);
+		mClosedByButtonClick = false;
+		return false;
+	}
+
+	return true;
+}
diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h
new file mode 100644
index 00000000000..3cd66e04a8b
--- /dev/null
+++ b/indra/llui/lltoggleablemenu.h
@@ -0,0 +1,65 @@
+/** 
+ * @file lltoggleablemenu.h
+ * @brief Menu toggled by a button press
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTOGGLEABLEMENU_H
+#define LL_LLTOGGLEABLEMENU_H
+
+#include "llmenugl.h"
+
+class LLToggleableMenu : public LLMenuGL
+{
+public:
+    //adding blank params to work around registration issue
+    //where LLToggleableMenu was owning the LLMenuGL param
+    //and menu.xml was never loaded
+	struct Params : public LLInitParam::Block<Params, LLMenuGL::Params>
+	{};
+protected:
+	LLToggleableMenu(const Params&);
+	friend class LLUICtrlFactory;
+public:
+	virtual void handleVisibilityChange (BOOL curVisibilityIn);
+
+	// Converts the given local button rect to a screen rect
+	void setButtonRect(const LLRect& rect, LLView* current_view);
+
+	// Returns "true" if menu was not closed by button click
+	// and is not still visible. If menu is visible toggles
+	// its visibility off.
+	bool toggleVisibility();
+	
+protected:
+	bool mClosedByButtonClick;
+	LLRect mButtonRect;
+};
+
+#endif // LL_LLTOGGLEABLEMENU_H
diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp
index 5c017dabd7c..8f5c0298165 100644
--- a/indra/llui/lltooltip.cpp
+++ b/indra/llui/lltooltip.cpp
@@ -36,7 +36,6 @@
 #include "lltooltip.h"
 
 // Library includes
-#include "llpanel.h"
 #include "lltextbox.h"
 #include "lliconctrl.h"
 #include "llui.h"			// positionViewNearMouse()
@@ -45,7 +44,6 @@
 //
 // Constants
 //
-const F32 DELAY_BEFORE_SHOW_TIP = 0.35f;
 
 //
 // Local globals
@@ -57,6 +55,11 @@ LLToolTipView *gToolTipView = NULL;
 // Member functions
 //
 
+LLToolTipView::Params::Params()
+{
+	mouse_opaque = false;
+}
+
 LLToolTipView::LLToolTipView(const LLToolTipView::Params& p)
 :	LLView(p)
 {
@@ -64,10 +67,7 @@ LLToolTipView::LLToolTipView(const LLToolTipView::Params& p)
 
 void LLToolTipView::draw()
 {
-	if (LLUI::getWindow()->isCursorHidden() )
-	{
-		LLToolTipMgr::instance().hideToolTips();
-	}
+	LLToolTipMgr::instance().updateToolTipVisibility();
 
 	// do the usual thing
 	LLView::draw();
@@ -80,17 +80,10 @@ BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask)
 
 	LLToolTipMgr& tooltip_mgr = LLToolTipMgr::instance();
 
-	// hide existing tooltips when mouse moves out of sticky rect
-	if (tooltip_mgr.toolTipVisible() 
-		&& !tooltip_mgr.getStickyRect().pointInRect(x, y))
-	{
-		tooltip_mgr.hideToolTips();
-	}
-
-	// allow new tooltips whenever mouse moves
 	if (x != last_x && y != last_y)
 	{
-		tooltip_mgr.enableToolTips();
+		// allow new tooltips because mouse moved
+		tooltip_mgr.unblockToolTips();
 	}
 
 	last_x = x;
@@ -100,96 +93,84 @@ BOOL LLToolTipView::handleHover(S32 x, S32 y, MASK mask)
 
 BOOL LLToolTipView::handleMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLToolTipMgr::instance().hideToolTips();
+	LLToolTipMgr::instance().blockToolTips();
 	return LLView::handleMouseDown(x, y, mask);
 }
 
 BOOL LLToolTipView::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLToolTipMgr::instance().hideToolTips();
+	LLToolTipMgr::instance().blockToolTips();
 	return LLView::handleMiddleMouseDown(x, y, mask);
 }
 
 BOOL LLToolTipView::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLToolTipMgr::instance().hideToolTips();
+	LLToolTipMgr::instance().blockToolTips();
 	return LLView::handleRightMouseDown(x, y, mask);
 }
 
 
 BOOL LLToolTipView::handleScrollWheel( S32 x, S32 y, S32 clicks )
 {
-	LLToolTipMgr::instance().hideToolTips();
+	LLToolTipMgr::instance().blockToolTips();
 	return FALSE;
 }
 
 void LLToolTipView::onMouseLeave(S32 x, S32 y, MASK mask)
 {
-	LLToolTipMgr::instance().hideToolTips();
+	LLToolTipMgr::instance().blockToolTips();
 }
 
 
 void LLToolTipView::drawStickyRect()
 {
-	gl_rect_2d(LLToolTipMgr::instance().getStickyRect(), LLColor4::white, false);
+	gl_rect_2d(LLToolTipMgr::instance().getMouseNearRect(), LLColor4::white, false);
 }
 //
 // LLToolTip
 //
-class LLToolTip : public LLPanel
-{
-public:
-	struct Params : public LLInitParam::Block<Params, LLPanel::Params> 
-	{
-		Mandatory<F32>				visible_time;
-	
-		Optional<LLToolTipParams::click_callback_t>	click_callback;
-		Optional<LLUIImage*>						image;
-
-		Params()
-		{
-			//use_bounding_rect = true;
-		}
-	};
-	/*virtual*/ void draw();
-	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
-
-	/*virtual*/ void setValue(const LLSD& value);
-	/*virtual*/ void setVisible(BOOL visible);
 
-	bool isFading() { return mFadeTimer.getStarted(); }
-
-	LLToolTip(const Params& p);
-
-private:
-	LLTextBox*		mTextBox;
-	LLFrameTimer	mFadeTimer;
-	F32				mVisibleTime;
-	bool			mHasClickCallback;
-};
 
 static LLDefaultChildRegistry::Register<LLToolTip> r("tool_tip");
 
-const S32 TOOLTIP_PADDING = 4;
+
+LLToolTip::Params::Params()
+:	max_width("max_width", 200),
+	padding("padding", 4),
+	pos("pos"),
+	message("message"),
+	delay_time("delay_time", LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" )),
+	visible_time_over("visible_time_over", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeOver" )),
+	visible_time_near("visible_time_near", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeNear" )),
+	visible_time_far("visible_time_far", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTimeFar" )),
+	sticky_rect("sticky_rect"),
+	image("image")
+{
+	name = "tooltip";
+	font = LLFontGL::getFontSansSerif();
+	bg_opaque_color = LLUIColorTable::instance().getColor( "ToolTipBgColor" );
+	background_visible = true;
+}
 
 LLToolTip::LLToolTip(const LLToolTip::Params& p)
 :	LLPanel(p),
-	mVisibleTime(p.visible_time),
-	mHasClickCallback(p.click_callback.isProvided())
+	mMaxWidth(p.max_width),
+	mHasClickCallback(p.click_callback.isProvided()),
+	mPadding(p.padding)
 {
 	LLTextBox::Params params;
-	params.text = "tip_text";
-	params.name = params.text;
+	params.initial_value = "tip_text";
+	params.name = params.initial_value().asString();
 	// bake textbox padding into initial rect
-	params.rect = LLRect (TOOLTIP_PADDING, TOOLTIP_PADDING + 1, TOOLTIP_PADDING + 1, TOOLTIP_PADDING);
+	params.rect = LLRect (mPadding, mPadding + 1, mPadding + 1, mPadding);
 	params.follows.flags = FOLLOWS_ALL;
-	params.h_pad = 4;
-	params.v_pad = 2;
+	params.h_pad = 0;
+	params.v_pad = 0;
 	params.mouse_opaque = false;
 	params.text_color = LLUIColorTable::instance().getColor( "ToolTipTextColor" );
 	params.bg_visible = false;
-	params.font.style = "NORMAL";
-	//params.border_drop_shadow_visible = true;
+	params.font = p.font;
+	params.use_ellipses = true;
 	mTextBox = LLUICtrlFactory::create<LLTextBox> (params);
 	addChild(mTextBox);
 
@@ -198,8 +179,9 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)
 		LLIconCtrl::Params icon_params;
 		icon_params.name = "tooltip_icon";
 		LLRect icon_rect;
-		const S32 TOOLTIP_ICON_SIZE = 18;
-		icon_rect.setOriginAndSize(TOOLTIP_PADDING, TOOLTIP_PADDING, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE);
+		LLUIImage* imagep = p.image;
+		const S32 TOOLTIP_ICON_SIZE = (imagep ? imagep->getWidth() : 16);
+		icon_rect.setOriginAndSize(mPadding, mPadding, TOOLTIP_ICON_SIZE, TOOLTIP_ICON_SIZE);
 		icon_params.rect = icon_rect;
 		icon_params.follows.flags = FOLLOWS_LEFT | FOLLOWS_BOTTOM;
 		icon_params.image = p.image;
@@ -218,13 +200,20 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)
 
 void LLToolTip::setValue(const LLSD& value)
 {
-	mTextBox->setWrappedText(value.asString());
-	mTextBox->reshapeToFitText();
+	const S32 REALLY_LARGE_HEIGHT = 10000;
+	reshape(mMaxWidth, REALLY_LARGE_HEIGHT);
+
+	mTextBox->setValue(value);
+
+	LLRect text_contents_rect = mTextBox->getContentsRect();
+	S32 text_width = llmin(mMaxWidth, text_contents_rect.getWidth());
+	S32 text_height = text_contents_rect.getHeight();
+	mTextBox->reshape(text_width, text_height);
 
 	// reshape tooltip panel to fit text box
 	LLRect tooltip_rect = calcBoundingRect();
-	tooltip_rect.mTop += TOOLTIP_PADDING;
-	tooltip_rect.mRight += TOOLTIP_PADDING;
+	tooltip_rect.mTop += mPadding;
+	tooltip_rect.mRight += mPadding;
 	tooltip_rect.mBottom = 0;
 	tooltip_rect.mLeft = 0;
 
@@ -234,19 +223,21 @@ void LLToolTip::setValue(const LLSD& value)
 void LLToolTip::setVisible(BOOL visible)
 {
 	// fade out tooltip over time
-	if (!visible)
+	if (visible)
+	{
+		mVisibleTimer.start();
+		mFadeTimer.stop();
+		LLPanel::setVisible(TRUE);
+	}
+	else
 	{
+		mVisibleTimer.stop();
 		// don't actually change mVisible state, start fade out transition instead
 		if (!mFadeTimer.getStarted())
 		{
 			mFadeTimer.start();
 		}
 	}
-	else
-	{
-		mFadeTimer.stop();
-		LLPanel::setVisible(TRUE);
-	}
 }
 
 BOOL LLToolTip::handleHover(S32 x, S32 y, MASK mask)
@@ -263,11 +254,6 @@ void LLToolTip::draw()
 {
 	F32 alpha = 1.f;
 
-	if (LLUI::getMouseIdleTime() > mVisibleTime)
-	{
-		LLToolTipMgr::instance().hideToolTips();
-	}
-
 	if (mFadeTimer.getStarted())
 	{
 		F32 tool_tip_fade_time = LLUI::sSettingGroups["config"]->getF32("ToolTipFadeTime");
@@ -287,94 +273,90 @@ void LLToolTip::draw()
 	}
 }
 
+bool LLToolTip::isFading() 
+{ 
+	return mFadeTimer.getStarted(); 
+}
+
+F32 LLToolTip::getVisibleTime() 
+{ 
+	return mVisibleTimer.getStarted() ? mVisibleTimer.getElapsedTimeF32() : 0.f; 
+}
+
+bool LLToolTip::hasClickCallback() 
+{
+	return mHasClickCallback; 
+}
 
 
 //
 // LLToolTipMgr
 //
-LLToolTipParams::LLToolTipParams()
-:	pos("pos"),
-	message("message"),
-	delay_time("delay_time", LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" )),
-	visible_time("visible_time", LLUI::sSettingGroups["config"]->getF32( "ToolTipVisibleTime" )),
-	sticky_rect("sticky_rect"),
-	width("width", 200),
-	image("image")
-{}
 
 LLToolTipMgr::LLToolTipMgr()
-:	mToolTip(NULL)
-{
-}
+:	mToolTip(NULL),
+	mNeedsToolTip(false)
+{}
 
-LLToolTip* LLToolTipMgr::createToolTip(const LLToolTipParams& params)
+void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
 {
-	S32 mouse_x;
-	S32 mouse_y;
-	LLUI::getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y);
+	// block all other tooltips until tooltips re-enabled (e.g. mouse moved)
+	blockToolTips(); 
 
+	delete mToolTip;
 
-	LLToolTip::Params tooltip_params;
-	tooltip_params.name = "tooltip";
-	tooltip_params.mouse_opaque = true;
+	LLToolTip::Params tooltip_params(params);
+	// block mouse events if there is a click handler registered (specifically, hover)
+	tooltip_params.mouse_opaque = params.click_callback.isProvided();
 	tooltip_params.rect = LLRect (0, 1, 1, 0);
-	tooltip_params.bg_opaque_color = LLUIColorTable::instance().getColor( "ToolTipBgColor" );
-	tooltip_params.background_visible = true;
-	tooltip_params.visible_time = params.visible_time;
-	if (params.image.isProvided())
-	{
-		tooltip_params.image = params.image;
-	}
-	if (params.click_callback.isProvided())
-	{
-		tooltip_params.click_callback = params.click_callback;
-	}
-
-	LLToolTip* tooltip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
 
-	// make tooltip fixed width and tall enough to fit text
-	tooltip->reshape(params.width, 2000);
-	tooltip->setValue(params.message());
-	gToolTipView->addChild(tooltip);
+	mToolTip = LLUICtrlFactory::create<LLToolTip> (tooltip_params);
+	mToolTip->setValue(params.message());
+	gToolTipView->addChild(mToolTip);
 
 	if (params.pos.isProvided())
 	{
+		LLCoordGL pos = params.pos;
 		// try to spawn at requested position
-		LLUI::positionViewNearMouse(tooltip, params.pos.x, params.pos.y);
+		LLUI::positionViewNearMouse(mToolTip, pos.mX, pos.mY);
 	}
 	else
 	{
 		// just spawn at mouse location
-		LLUI::positionViewNearMouse(tooltip);
+		LLUI::positionViewNearMouse(mToolTip);
 	}
 
 	//...update "sticky" rect and tooltip position
 	if (params.sticky_rect.isProvided())
 	{
-		mToolTipStickyRect = params.sticky_rect;
+		mMouseNearRect = params.sticky_rect;
 	}
 	else
 	{
-		// otherwise just use one pixel rect around mouse cursor
-		mToolTipStickyRect.setOriginAndSize(mouse_x, mouse_y, 1, 1);
+		S32 mouse_x;
+		S32 mouse_y;
+		LLUI::getMousePositionLocal(gToolTipView->getParent(), &mouse_x, &mouse_y);
+
+		// allow mouse a little bit of slop before changing tooltips
+		mMouseNearRect.setCenterAndSize(mouse_x, mouse_y, 3, 3);
 	}
-	
-	if (params.click_callback.isProvided())
+
+	// allow mouse to move all the way to the tooltip without changing tooltips
+	// (tooltip can still time out)
+	if (mToolTip->hasClickCallback())
 	{
 		// keep tooltip up when we mouse over it
-		mToolTipStickyRect.unionWith(tooltip->getRect());
+		mMouseNearRect.unionWith(mToolTip->getRect());
 	}
-
-	return tooltip;
 }
 
 
 void LLToolTipMgr::show(const std::string& msg)
 {
-	show(LLToolTipParams().message(msg));
+	show(LLToolTip::Params().message(msg));
 }
 
-void LLToolTipMgr::show(const LLToolTipParams& params)
+void LLToolTipMgr::show(const LLToolTip::Params& params)
 {
 	if (!params.validateBlock()) 
 	{
@@ -382,38 +364,42 @@ void LLToolTipMgr::show(const LLToolTipParams& params)
 		return;
 	}
 	
-	bool tooltip_shown =	mToolTip 
-							&& mToolTip->getVisible() 
-							&& !mToolTip->isFading();
-
-	// if tooltip contents change, hide existing tooltip
-	if (tooltip_shown && mLastToolTipMessage != params.message())
-	{
-		hideToolTips();
-	}
+	S32 mouse_x;
+	S32 mouse_y;
+	LLUI::getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y);
 
+	// are we ready to show the tooltip?
 	if (!mToolTipsBlocked									// we haven't hit a key, moved the mouse, etc.
-		&& LLUI::getMouseIdleTime() > params.delay_time		// the mouse has been still long enough
-		&& !tooltip_shown)									// tooltip not visible
+		&& LLUI::getMouseIdleTime() > params.delay_time)	// the mouse has been still long enough
 	{
-		// create new tooltip at mouse cursor position
-		delete mToolTip;
-		mToolTip = createToolTip(params);
+		bool tooltip_changed = mLastToolTipParams.message() != params.message()
+								|| mLastToolTipParams.pos() != params.pos();
+
+		bool tooltip_shown = mToolTip 
+							 && mToolTip->getVisible() 
+							 && !mToolTip->isFading();
 
-		// remember this tooltip so we know when it changes
-		mLastToolTipMessage = params.message();
+		mNeedsToolTip = tooltip_changed || !tooltip_shown;
+		// store description of tooltip for later creation
+		mNextToolTipParams = params;
 	}
 }
 
 // allow new tooltips to be created, e.g. after mouse has moved
-void LLToolTipMgr::enableToolTips()
+void LLToolTipMgr::unblockToolTips()
 {
 	mToolTipsBlocked = false;
 }
 
+// disallow new tooltips until unblockTooltips called
+void LLToolTipMgr::blockToolTips()
+{
+	hideToolTips();
+	mToolTipsBlocked = true;
+}
+
 void LLToolTipMgr::hideToolTips() 
 { 
-	mToolTipsBlocked = true; 
 	if (mToolTip)
 	{
 		mToolTip->setVisible(FALSE);
@@ -422,7 +408,7 @@ void LLToolTipMgr::hideToolTips()
 
 bool LLToolTipMgr::toolTipVisible()
 {
-	return mToolTip ? mToolTip->getVisible() : false;
+	return mToolTip ? mToolTip->isInVisibleChain() : false;
 }
 
 LLRect LLToolTipMgr::getToolTipRect()
@@ -435,11 +421,63 @@ LLRect LLToolTipMgr::getToolTipRect()
 }
 
 
-LLRect LLToolTipMgr::getStickyRect() 
+LLRect LLToolTipMgr::getMouseNearRect() 
 { 
-	if (!mToolTip) return LLRect();
+	return toolTipVisible() ? mMouseNearRect : LLRect(); 
+}
+
+// every frame, determine if current tooltip should be hidden
+void LLToolTipMgr::updateToolTipVisibility()
+{
+	// create new tooltip if we have one ready to go
+	if (mNeedsToolTip)
+	{
+		mNeedsToolTip = false;
+		createToolTip(mNextToolTipParams);
+		mLastToolTipParams = mNextToolTipParams;
+		
+		return;
+	}
 
-	return mToolTip->isInVisibleChain() ? mToolTipStickyRect : LLRect(); 
+	// hide tooltips when mouse cursor is hidden
+	if (LLUI::getWindow()->isCursorHidden())
+	{
+		blockToolTips();
+		return;
+	}
+
+	// hide existing tooltips if they have timed out
+	S32 mouse_x, mouse_y;
+	LLUI::getMousePositionLocal(gToolTipView, &mouse_x, &mouse_y);
+
+	F32 tooltip_timeout = 0.f;
+	if (toolTipVisible())
+	{
+		// mouse far away from tooltip
+		tooltip_timeout = mLastToolTipParams.visible_time_far;
+		// mouse near rect will only include the tooltip if the 
+		// tooltip is clickable
+		if (mMouseNearRect.pointInRect(mouse_x, mouse_y))
+		{
+			// mouse "close" to tooltip
+			tooltip_timeout = mLastToolTipParams.visible_time_near;
+
+			// if tooltip is clickable (has large mMouseNearRect)
+			// than having cursor over tooltip keeps it up indefinitely
+			if (mToolTip->parentPointInView(mouse_x, mouse_y))
+			{
+				// mouse over tooltip itself, don't time out
+				tooltip_timeout = mLastToolTipParams.visible_time_over;
+			}
+		}
+
+		if (mToolTip->getVisibleTime() > tooltip_timeout)
+		{
+			hideToolTips();
+		}
+	}
 }
 
+
+
 // EOF
diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h
index fb7f9420994..6715da16115 100644
--- a/indra/llui/lltooltip.h
+++ b/indra/llui/lltooltip.h
@@ -36,7 +36,7 @@
 // Library includes
 #include "llsingleton.h"
 #include "llinitparam.h"
-#include "llview.h"
+#include "llpanel.h"
 
 //
 // Classes
@@ -46,10 +46,7 @@ class LLToolTipView : public LLView
 public:
 	struct Params : public LLInitParam::Block<Params, LLView::Params>
 	{
-		Params()
-		{
-			mouse_opaque = false;
-		}
+		Params();
 	};
 	LLToolTipView(const LLToolTipView::Params&);
 	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
@@ -65,57 +62,82 @@ class LLToolTipView : public LLView
 	/*virtual*/ void draw();
 };
 
-struct LLToolTipPosParams : public LLInitParam::Block<LLToolTipPosParams>
+class LLToolTip : public LLPanel
 {
-	Mandatory<S32>		x, 
-						y;
-	LLToolTipPosParams()
-	:	x("x"),
-		y("y")
-	{}
-};
+public:
+	struct Params : public LLInitParam::Block<Params, LLPanel::Params> 
+	{
+		typedef boost::function<void(void)> click_callback_t;
 
-struct LLToolTipParams : public LLInitParam::Block<LLToolTipParams>
-{
-	typedef boost::function<void(void)> click_callback_t;
+		Mandatory<std::string>		message;
+
+		Optional<LLCoordGL>			pos;
+		Optional<F32>				delay_time,
+									visible_time_over,  // time for which tooltip is visible while mouse on it
+									visible_time_near,	// time for which tooltip is visible while mouse near it
+									visible_time_far;	// time for which tooltip is visible while mouse moved away
+		Optional<LLRect>			sticky_rect;
+		Optional<const LLFontGL*>	font;
 
-	Mandatory<std::string>		message;
-	
-	Optional<LLToolTipPosParams>	pos;
-	Optional<F32>					delay_time,
-									visible_time;
-	Optional<LLRect>				sticky_rect;
-	Optional<S32>					width;
-	Optional<LLUIImage*>			image;
+		Optional<click_callback_t>	click_callback;
+		Optional<LLUIImage*>		image;
+		Optional<S32>				max_width;
+		Optional<S32>				padding;
+
+		Params();
+	};
+	/*virtual*/ void draw();
+	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
 
-	Optional<click_callback_t>		click_callback;
+	/*virtual*/ void setValue(const LLSD& value);
+	/*virtual*/ void setVisible(BOOL visible);
 
-	LLToolTipParams();
-	LLToolTipParams(const std::string& message);
+	bool isFading();
+	F32 getVisibleTime();
+	bool hasClickCallback();
+
+	LLToolTip(const Params& p);
+
+private:
+	class LLTextBox*	mTextBox;
+	LLFrameTimer	mFadeTimer;
+	LLFrameTimer	mVisibleTimer;
+	S32				mMaxWidth;
+	bool			mHasClickCallback;
+	S32				mPadding;	// pixels
 };
 
+
 class LLToolTipMgr : public LLSingleton<LLToolTipMgr>
 {
 	LOG_CLASS(LLToolTipMgr);
 public:
 	LLToolTipMgr();
-	void show(const LLToolTipParams& params);
+	void show(const LLToolTip::Params& params);
 	void show(const std::string& message);
 
-	void enableToolTips();
+	void unblockToolTips();
+	void blockToolTips();
+
 	void hideToolTips();
 	bool toolTipVisible();
 	LLRect getToolTipRect();
-
-	LLRect getStickyRect();
+	LLRect getMouseNearRect();
+	void updateToolTipVisibility();
 
 private:
-	class LLToolTip* createToolTip(const LLToolTipParams& params);
+	void createToolTip(const LLToolTip::Params& params);
 
 	bool				mToolTipsBlocked;
 	class LLToolTip*	mToolTip;
-	std::string			mLastToolTipMessage;
-	LLRect				mToolTipStickyRect;
+
+	// tooltip creation is deferred until the UI is drawn every frame
+	// so the last tooltip to be created in a given frame will win
+	LLToolTip::Params	mLastToolTipParams;	// description of last tooltip we showed
+	LLToolTip::Params	mNextToolTipParams; // description of next tooltip we want to show
+	bool				mNeedsToolTip;		// do we want to show a tooltip
+
+	LLRect				mMouseNearRect;
 };
 
 //
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index d5b67f53b76..c89e5944fab 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -55,6 +55,7 @@
 #include "llfloater.h"
 #include "llfloaterreg.h"
 #include "llmenugl.h"
+#include "llmenubutton.h"
 #include "llwindow.h"
 
 // for registration
@@ -90,6 +91,7 @@ std::list<std::string> gUntranslated;
 static LLDefaultChildRegistry::Register<LLFilterEditor> register_filter_editor("filter_editor");
 static LLDefaultChildRegistry::Register<LLFlyoutButton> register_flyout_button("flyout_button");
 static LLDefaultChildRegistry::Register<LLSearchEditor> register_search_editor("search_editor");
+static LLDefaultChildRegistry::Register<LLMenuButton> register_menu_button("menu_button");
 
 
 //
@@ -1643,6 +1645,17 @@ void LLUI::setMousePositionScreen(S32 x, S32 y)
 	LLView::getWindow()->setCursorPosition(window_point);
 }
 
+//static 
+void LLUI::getMousePositionScreen(S32 *x, S32 *y)
+{
+	LLCoordWindow cursor_pos_window;
+	getWindow()->getCursorPosition(&cursor_pos_window);
+	LLCoordGL cursor_pos_gl;
+	getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
+	*x = llround((F32)cursor_pos_gl.mX / sGLScaleFactor.mV[VX]);
+	*y = llround((F32)cursor_pos_gl.mY / sGLScaleFactor.mV[VX]);
+}
+
 //static 
 void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y)
 {
@@ -1655,15 +1668,12 @@ void LLUI::setMousePositionLocal(const LLView* viewp, S32 x, S32 y)
 //static 
 void LLUI::getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y)
 {
-	LLCoordWindow cursor_pos_window;
-	LLView::getWindow()->getCursorPosition(&cursor_pos_window);
-	LLCoordGL cursor_pos_gl;
-	LLView::getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl);
-	cursor_pos_gl.mX = llround((F32)cursor_pos_gl.mX / LLUI::sGLScaleFactor.mV[VX]);
-	cursor_pos_gl.mY = llround((F32)cursor_pos_gl.mY / LLUI::sGLScaleFactor.mV[VY]);
-	viewp->screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, x, y);
+	S32 screen_x, screen_y;
+	getMousePositionScreen(&screen_x, &screen_y);
+	viewp->screenPointToLocal(screen_x, screen_y, x, y);
 }
 
+
 // On Windows, the user typically sets the language when they install the
 // app (by running it with a shortcut that sets InstallLanguage).  On Mac,
 // or on Windows if the SecondLife.exe executable is run directly, the 
@@ -1835,14 +1845,14 @@ LLControlGroup& LLUI::getControlControlGroup (const std::string& controlname)
 // spawn_x and spawn_y are top left corner of view in screen GL coordinates
 void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
 {
-	const S32 CURSOR_HEIGHT = 22;		// Approximate "normal" cursor size
-	const S32 CURSOR_WIDTH = 12;
+	const S32 CURSOR_HEIGHT = 18;		// Approximate "normal" cursor size
+	const S32 CURSOR_WIDTH = 9;
 
 	LLView* parent = view->getParent();
 
 	S32 mouse_x;
 	S32 mouse_y;
-	LLUI::getMousePositionLocal(parent, &mouse_x, &mouse_y);
+	LLUI::getMousePositionScreen(&mouse_x, &mouse_y);
 
 	// If no spawn location provided, use mouse position
 	if (spawn_x == S32_MAX || spawn_y == S32_MAX)
@@ -1856,12 +1866,13 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
 	LLRect mouse_rect;
 	const S32 MOUSE_CURSOR_PADDING = 5;
 	mouse_rect.setLeftTopAndSize(mouse_x - MOUSE_CURSOR_PADDING, 
-		mouse_y + MOUSE_CURSOR_PADDING, 
-		CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, 
-		CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2);
+								mouse_y + MOUSE_CURSOR_PADDING, 
+								CURSOR_WIDTH + MOUSE_CURSOR_PADDING * 2, 
+								CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2);
 
 	S32 local_x, local_y;
-	view->getParent()->screenPointToLocal(spawn_x, spawn_y, &local_x, &local_y);
+	// convert screen coordinates to tooltipview-local coordinates
+	parent->screenPointToLocal(spawn_x, spawn_y, &local_x, &local_y);
 
 	// Start at spawn position (using left/top)
 	view->setOrigin( local_x, local_y - view->getRect().getHeight());
@@ -1915,12 +1926,14 @@ namespace LLInitParam
 		}
 	};
 
-	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),
-		name(""),
+	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),
+		name("name"),
 		size("size"),
 		style("style")
-	{}
+	{
+		addSynonym(name, "");
+	}
 
 	const LLFontGL* TypedParam<const LLFontGL*>::getValueFromBlock() const
 	{
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 86cb5165008..f071e8dc474 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -190,6 +190,7 @@ class LLUI
 	static void setRootView(LLView* view) { sRootView = view; }
 	static std::string locateSkin(const std::string& filename);
 	static void setMousePositionScreen(S32 x, S32 y);
+	static void getMousePositionScreen(S32 *x, S32 *y);
 	static void setMousePositionLocal(const LLView* viewp, S32 x, S32 y);
 	static void getMousePositionLocal(const LLView* viewp, S32 *x, S32 *y);
 	static void setScaleFactor(const LLVector2& scale_factor);
@@ -409,8 +410,8 @@ namespace LLInitParam
 	{
         typedef BlockValue<const LLFontGL*> super_t;
 	public:
-		Optional<std::string>	name,
-								size,
+		Mandatory<std::string>	name;
+		Optional<std::string>	size,
 								style;
 
 		TypedParam(BlockDescriptor& descriptor, const char* name, const LLFontGL* const value, ParamDescriptor::validation_func_t func, S32 min_count, S32 max_count);
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index fe99d9c2672..5b72f87a784 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -49,7 +49,12 @@ LLUICtrl::Params::Params()
 	validate_callback("validate_callback"),
 	mouseenter_callback("mouseenter_callback"),
 	mouseleave_callback("mouseleave_callback"),
-	control_name("control_name")
+	control_name("control_name"),
+	font("font", LLFontGL::getFontSansSerif()),
+	font_halign("halign"),
+	font_valign("valign"),
+	length("length"), 	// ignore LLXMLNode cruft
+	type("type")   		// ignore LLXMLNode cruft
 {
 	addSynonym(initial_value, "initial_value");
 }
@@ -212,6 +217,29 @@ void LLUICtrl::initEnableCallback(const EnableCallbackParam& cb, enable_signal_t
 	}
 }
 
+void LLUICtrl::initVisibleCallback(const VisibleCallbackParam& cb, visible_signal_t& sig)
+{
+	// Set the callback function
+	if (cb.function.isProvided())
+	{
+		if (cb.parameter.isProvided())
+			sig.connect(boost::bind(cb.function(), this, cb.parameter));
+		else
+			sig.connect(cb.function());
+	}
+	else
+	{
+		visible_callback_t* func = (VisibleCallbackRegistry::getValue(cb.function_name));
+		if (func)
+		{
+			if (cb.parameter.isProvided())
+				sig.connect(boost::bind((*func), this, cb.parameter));
+			else
+				sig.connect(*func);
+		}
+	}
+}
+
 // virtual
 void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask)
 {
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index c2502732f37..69207eb8ea5 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -34,14 +34,15 @@
 #ifndef LL_LLUICTRL_H
 #define LL_LLUICTRL_H
 
-#include "llboost.h"
+//#include "llboost.h"
 #include "llrect.h"
 #include "llsd.h"
 #include <boost/function.hpp>
+#include <boost/signals2.hpp>
 
 #include "llinitparam.h"
 #include "llview.h"
-#include "llviewmodel.h"
+#include "llviewmodel.h"		// *TODO move dependency to .cpp file
 
 const BOOL TAKE_FOCUS_YES = TRUE;
 const BOOL TAKE_FOCUS_NO  = FALSE;
@@ -62,6 +63,9 @@ class LLUICtrl
 	typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> enable_callback_t;
 	typedef boost::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> enable_signal_t;
 	
+	typedef boost::function<bool (LLUICtrl* ctrl, const LLSD& param)> visible_callback_t;
+	typedef boost::signals2::signal<bool (LLUICtrl* ctrl, const LLSD& param), boost_boolean_combiner> visible_signal_t;
+	
 	struct CallbackParam : public LLInitParam::Block<CallbackParam>
 	{
 		Ignored					name;
@@ -91,6 +95,11 @@ class LLUICtrl
 		Optional<enable_callback_t> function;
 	};
 	
+	struct VisibleCallbackParam : public LLInitParam::Block<VisibleCallbackParam, CallbackParam >
+	{
+		Optional<visible_callback_t> function;
+	};
+	
 	struct EnableControls : public LLInitParam::Choice<EnableControls>
 	{
 		Alternative<std::string> enabled;
@@ -107,9 +116,12 @@ class LLUICtrl
 		Alternative<std::string> invisible;
 
 		ControlVisibility()
-			: visible("visiblity_control"),
-			invisible("invisiblity_control")
-		{}
+		:	visible("visibility_control"),
+			invisible("invisibility_control")
+		{
+			addSynonym(visible, "visiblity_control");
+			addSynonym(invisible, "invisiblity_control");
+		}
 	};	
 	struct Params : public LLInitParam::Block<Params, LLView::Params>
 	{
@@ -128,6 +140,15 @@ class LLUICtrl
 		Optional<EnableControls>		enabled_controls;
 		Optional<ControlVisibility>		controls_visibility;
 		
+		// font params
+		Optional<const LLFontGL*>		font;
+		Optional<LLFontGL::HAlign>		font_halign;
+		Optional<LLFontGL::VAlign>		font_valign;
+
+		// cruft from LLXMLNode implementation
+		Ignored							type,
+										length;
+
 		Params();
 	};
 
@@ -142,6 +163,7 @@ class LLUICtrl
 	
 	void initCommitCallback(const CommitCallbackParam& cb, commit_signal_t& sig);
 	void initEnableCallback(const EnableCallbackParam& cb, enable_signal_t& sig);
+	void initVisibleCallback(const VisibleCallbackParam& cb, visible_signal_t& sig);
 
 	// We need this virtual so we can override it with derived versions
 	virtual LLViewModel* getViewModel() const;
@@ -259,6 +281,8 @@ class LLUICtrl
 
 	class CommitCallbackRegistry : public CallbackRegistry<commit_callback_t, CommitCallbackRegistry>{};
 	class EnableCallbackRegistry : public CallbackRegistry<enable_callback_t, EnableCallbackRegistry>{};
+	class VisibleCallbackRegistry : public CallbackRegistry<visible_callback_t, VisibleCallbackRegistry>{};
+
 	
 protected:
 
diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp
index 538e1ec492c..4ce66772945 100644
--- a/indra/llui/lluictrlfactory.cpp
+++ b/indra/llui/lluictrlfactory.cpp
@@ -113,8 +113,20 @@ void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const wid
 
 		if (!instance().createFromXML(child_node, viewp, LLStringUtil::null, registry, outputChild))
 		{
+			// child_node is not a valid child for the current parent
 			std::string child_name = std::string(child_node->getName()->mString);
-			llwarns << "Could not create widget named " << child_node->getName()->mString << llendl;
+			if (LLDefaultChildRegistry::instance().getValue(child_name))
+			{
+				// This means that the registry assocaited with the parent widget does not have an entry
+				// for the child widget
+				// You might need to add something like:
+				// static ParentWidgetRegistry::Register<ChildWidgetType> register("child_widget_name");
+				llwarns << child_name << " is not a valid child of " << node->getName()->mString << llendl;
+			}
+			else
+			{
+				llwarns << "Could not create widget named " << child_node->getName()->mString << llendl;
+			}
 		}
 
 		if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty())
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index c20212c3759..c1da73fa839 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -36,8 +36,10 @@
 #include "lluri.h"
 #include "llcachename.h"
 #include "lltrans.h"
+#include "lluicolortable.h"
 
 LLUrlEntryBase::LLUrlEntryBase()
+: mColor(LLUIColorTable::instance().getColor("HTMLLinkColor"))
 {
 }
 
@@ -260,10 +262,11 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const
 //
 LLUrlEntryAgent::LLUrlEntryAgent()
 {
-	mPattern = boost::regex("secondlife:///app/agent/[\\da-f-]+/about",
+	mPattern = boost::regex("secondlife:///app/agent/[\\da-f-]+/\\w+",
 							boost::regex::perl|boost::regex::icase);
 	mMenuName = "menu_url_agent.xml";
-	mTooltip = LLTrans::getString("TooltipAgentUrl");
+	mIcon = "Generic_Person";
+	mColor = LLUIColorTable::instance().getColor("AgentLinkColor");
 }
 
 void LLUrlEntryAgent::onAgentNameReceived(const LLUUID& id,
@@ -293,7 +296,7 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
 		}
 	}
 
-	return unescapeUrl(url);
+	return LLTrans::getString("LoadingData");//unescapeUrl(url);
 }
 
 //
@@ -305,6 +308,7 @@ LLUrlEntryGroup::LLUrlEntryGroup()
 	mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/about",
 							boost::regex::perl|boost::regex::icase);
 	mMenuName = "menu_url_group.xml";
+	mIcon = "Generic_Group";
 	mTooltip = LLTrans::getString("TooltipGroupUrl");
 }
 
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 54053872df4..afb2fdcde9f 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -35,7 +35,7 @@
 #define LL_LLURLENTRY_H
 
 #include "lluuid.h"
-
+#include "lluicolor.h"
 #include <boost/signals2.hpp>
 #include <boost/regex.hpp>
 #include <string>
@@ -77,13 +77,16 @@ class LLUrlEntryBase
 	virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; }
 
 	/// Return an icon that can be displayed next to Urls of this type
-	const std::string &getIcon() const { return mIcon; }
+	std::string getIcon() const { return mIcon; }
+
+	/// Return the color to render the displayed text
+	LLUIColor getColor() const { return mColor; }
 
 	/// Given a matched Url, return a tooltip string for the hyperlink
 	std::string getTooltip() const { return mTooltip; }
 
 	/// Return the name of a XUI file containing the context menu items
-	const std::string getMenuName() const { return mMenuName; }
+	std::string getMenuName() const { return mMenuName; }
 
 	/// Return the name of a SL location described by this Url, if any
 	virtual std::string getLocation(const std::string &url) const { return ""; }
@@ -102,11 +105,12 @@ class LLUrlEntryBase
 		LLUrlLabelSignal *signal;
 	} LLUrlEntryObserver;
 
-	boost::regex                                   mPattern;
-	std::string                                    mIcon;
-	std::string                                    mMenuName;
-	std::string                                    mTooltip;
-	std::multimap<std::string, LLUrlEntryObserver> mObservers;
+	boost::regex                                   	mPattern;
+	std::string                                    	mIcon;
+	std::string                                    	mMenuName;
+	std::string                                    	mTooltip;
+	LLUIColor										mColor;
+	std::multimap<std::string, LLUrlEntryObserver>	mObservers;
 };
 
 ///
diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp
index 7eec4c4a659..3b47145a225 100644
--- a/indra/llui/llurlmatch.cpp
+++ b/indra/llui/llurlmatch.cpp
@@ -47,8 +47,8 @@ LLUrlMatch::LLUrlMatch() :
 
 void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
 						   const std::string &label, const std::string &tooltip,
-						   const std::string &icon, const std::string &menu,
-						   const std::string &location)
+						   const std::string &icon, const LLUIColor& color,
+						   const std::string &menu, const std::string &location)
 {
 	mStart = start;
 	mEnd = end;
@@ -56,6 +56,7 @@ void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url,
 	mLabel = label;
 	mTooltip = tooltip;
 	mIcon = icon;
+	mColor = color;
 	mMenuName = menu;
 	mLocation = location;
 }
diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h
index 0711e414438..7f5767923af 100644
--- a/indra/llui/llurlmatch.h
+++ b/indra/llui/llurlmatch.h
@@ -38,6 +38,7 @@
 
 #include <string>
 #include <vector>
+#include "lluicolor.h"
 
 ///
 /// LLUrlMatch describes a single Url that was matched within a string by 
@@ -62,27 +63,31 @@ class LLUrlMatch
 	U32 getEnd() const { return mEnd; }
 
 	/// return the Url that has been matched in the input string
-	const std::string &getUrl() const { return mUrl; }
+	std::string getUrl() const { return mUrl; }
 
 	/// return a label that can be used for the display of this Url
-	const std::string &getLabel() const { return mLabel; }
+	std::string getLabel() const { return mLabel; }
 
 	/// return a message that could be displayed in a tooltip or status bar
-	const std::string &getTooltip() const { return mTooltip; }
+	std::string getTooltip() const { return mTooltip; }
 
 	/// return the filename for an icon that can be displayed next to this Url
-	const std::string &getIcon() const { return mIcon; }
+	std::string getIcon() const { return mIcon; }
+
+	/// Return the color to render the displayed text
+	LLUIColor getColor() const { return mColor; }
 
 	/// Return the name of a XUI file containing the context menu items
-	const std::string getMenuName() const { return mMenuName; }
+	std::string getMenuName() const { return mMenuName; }
 
 	/// return the SL location that this Url describes, or "" if none.
-	const std::string &getLocation() const { return mLocation; }
+	std::string getLocation() const { return mLocation; }
 
 	/// Change the contents of this match object (used by LLUrlRegistry)
 	void setValues(U32 start, U32 end, const std::string &url, const std::string &label,
 	               const std::string &tooltip, const std::string &icon,
-				   const std::string &menu, const std::string &location);
+				   const LLUIColor& color, const std::string &menu, 
+				   const std::string &location);
 
 private:
 	U32         mStart;
@@ -93,6 +98,7 @@ class LLUrlMatch
 	std::string mIcon;
 	std::string mMenuName;
 	std::string mLocation;
+	LLUIColor	mColor;
 };
 
 #endif
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index 6f5c694b1b6..8413de0837d 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -155,6 +155,7 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
 						match_entry->getLabel(url, cb),
 						match_entry->getTooltip(),
 						match_entry->getIcon(),
+						match_entry->getColor(),
 						match_entry->getMenuName(),
 						match_entry->getLocation(url));
 		return true;
@@ -183,9 +184,10 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr
 		}
 		S32 end = start + wurl.size() - 1;
 
-		match.setValues(start, end, match.getUrl(), match.getLabel(),
-						match.getTooltip(), match.getIcon(),
-						match.getMenuName(), match.getLocation());
+		match.setValues(start, end, match.getUrl(), 
+			match.getLabel(), match.getTooltip(),
+			match.getIcon(), match.getColor(),
+			match.getMenuName(), match.getLocation());
 		return true;
 	}
 	return false;
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 10cb3fb3770..1df88387386 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -92,9 +92,6 @@ LLView::Params::Params()
 	default_tab_group("default_tab_group"),
 	tool_tip("tool_tip"),
 	sound_flags("sound_flags", MOUSE_UP),
-	font("font", LLFontGL::getFontSansSerif()),
-	font_halign("halign"),
-	font_valign("valign"),
 	layout("layout"),
 	rect("rect"),
 	bottom_delta("bottom_delta", S32_MAX),
@@ -171,12 +168,6 @@ LLView::~LLView()
 	}
 }
 
-// virtual
-BOOL LLView::isView() const
-{
-	return TRUE;
-}
-
 // virtual
 BOOL LLView::isCtrl() const
 {
@@ -227,10 +218,9 @@ BOOL LLView::getUseBoundingRect()
 }
 
 // virtual
-const std::string& LLView::getName() const
+std::string LLView::getName() const
 {
-	static const std::string unnamed("(no name)");
-	return mName.empty() ? unnamed : mName;
+	return mName.empty() ? std::string("(no name)") : mName;
 }
 
 void LLView::sendChildToFront(LLView* child)
@@ -634,16 +624,7 @@ void LLView::setSnappedTo(const LLView* snap_view)
 
 BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = childrenHandleHover( x, y, mask ) != NULL;
-	if( !handled 
-		&& blockMouseEvent(x, y) )
-	{
-		LLUI::sWindow->setCursor(mHoverCursor);
-		lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
-		handled = TRUE;
-	}
-
-	return handled;
+	return childrenHandleHover( x, y, mask ) != NULL;
 }
 
 void LLView::onMouseEnter(S32 x, S32 y, MASK mask)
@@ -657,7 +638,7 @@ void LLView::onMouseLeave(S32 x, S32 y, MASK mask)
 }
 
 
-LLView* LLView::childrenHandleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask)
 {
 	LLView* handled_view = NULL;
 	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
@@ -665,13 +646,13 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, std::string& msg, LLRect& st
 		LLView* viewp = *child_it;
 		S32 local_x = x - viewp->getRect().mLeft;
 		S32 local_y = y - viewp->getRect().mBottom;
-		if(!viewp->pointInView(local_x, local_y) ||
-			!viewp->getVisible())
+		if(!viewp->pointInView(local_x, local_y) 
+			|| !viewp->getVisible())
 		{
 			continue;
 		}
 
-		if(viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen) )
+		if (viewp->handleToolTip(local_x, local_y, mask) )
 		{
 			if (sDebugMouseHandling)
 			{
@@ -682,20 +663,22 @@ LLView* LLView::childrenHandleToolTip(S32 x, S32 y, std::string& msg, LLRect& st
 			break;
 		}
 
-		if( viewp->blockMouseEvent(x, y) )
+		if (viewp->blockMouseEvent(local_x, local_y))
 		{
 			handled_view = viewp;
+			break;
 		}
 	}
 	return handled_view;
 }
 
-BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+
+BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = FALSE;
 
 	// parents provide tooltips first, which are optionally
-	// overridden by children
+	// overridden by children, in case child is mouse_opaque
 	if (!mToolTipMsg.empty())
 	{
 		// allow "scrubbing" over ui by showing next tooltip immediately
@@ -703,7 +686,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_s
 		F32 timeout = LLToolTipMgr::instance().toolTipVisible() 
 			? 0.f
 			: LLUI::sSettingGroups["config"]->getF32( "ToolTipDelay" );
-		LLToolTipMgr::instance().show(LLToolTipParams()
+		LLToolTipMgr::instance().show(LLToolTip::Params()
 			.message(mToolTipMsg)
 			.sticky_rect(calcScreenRect())
 			.delay_time(timeout));
@@ -712,7 +695,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_s
 	}
 
 	// child tooltips will override our own
-	LLView* child_handler = childrenHandleToolTip(x, y, msg, sticky_rect_screen);
+	LLView* child_handler = childrenHandleToolTip(x, y, mask);
 	if (child_handler)
 	{
 		handled = TRUE;
@@ -720,7 +703,6 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_s
 
 	return handled;
 }
-
 BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
@@ -801,20 +783,7 @@ BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 							   EAcceptance* accept,
 							   std::string& tooltip_msg)
 {
-	// CRO this is an experiment to allow drag and drop into object inventory based on the DragAndDrop tool's permissions rather than the parent
-	BOOL handled = childrenHandleDragAndDrop( x, y, mask, drop,
-											cargo_type,
-											cargo_data,
-											accept,
-											tooltip_msg) != NULL;
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		*accept = ACCEPT_NO;
-		handled = TRUE;
-		lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLView " << getName() << llendl;
-	}
-
-	return handled;
+	return childrenHandleDragAndDrop( x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL;
 }
 
 LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
@@ -824,28 +793,33 @@ LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
 									   EAcceptance* accept,
 									   std::string& tooltip_msg)
 {
-	LLView* handled_view = FALSE;
-	// CRO this is an experiment to allow drag and drop into object inventory based on the DragAndDrop tool's permissions rather than the parent
-	if( getVisible() )
-//	if( getVisible() && getEnabled() )
+	LLView* handled_view = NULL;
+	for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
 	{
-		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+		LLView* viewp = *child_it;
+		S32 local_x = x - viewp->getRect().mLeft;
+		S32 local_y = y - viewp->getRect().mBottom;
+		if( !viewp->pointInView(local_x, local_y) ||
+			!viewp->getVisible() ||
+			!viewp->getEnabled())
 		{
-			LLView* viewp = *child_it;
-			S32 local_x = x - viewp->getRect().mLeft;
-			S32 local_y = y - viewp->getRect().mBottom;
-			if( viewp->pointInView(local_x, local_y) && 
-				viewp->getVisible() &&
-				viewp->getEnabled() &&
-				viewp->handleDragAndDrop(local_x, local_y, mask, drop,
-										 cargo_type,
-										 cargo_data,
-										 accept,
-										 tooltip_msg))
-			{
-				handled_view = viewp;
-				break;
-			}
+			continue;
+		}
+		if (viewp->handleDragAndDrop(local_x, local_y, mask, drop,
+									 cargo_type,
+									 cargo_data,
+									 accept,
+									 tooltip_msg))
+		{
+			handled_view = viewp;
+			break;
+		}
+
+		if (viewp->blockMouseEvent(x, y))
+		{
+			*accept = ACCEPT_NO;
+			handled_view = viewp;
+			break;
 		}
 	}
 	return handled_view;
@@ -862,105 +836,42 @@ BOOL LLView::hasMouseCapture()
 
 BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = childrenHandleMouseUp( x, y, mask ) != NULL;
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		handled = TRUE;
-	}
-	return handled;
+	return childrenHandleMouseUp( x, y, mask ) != NULL;
 }
 
 BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = childrenHandleMouseDown( x, y, mask );
-	BOOL handled = (handled_view != NULL);
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		handled = TRUE;
-		handled_view = this;
-	}
-
-	//// HACK If we're editing UI, select the leaf view that ate the click.
-	//if (sEditingUI && handled_view)
-	//{
-	//	// need to find leaf views, big hack
-	//	LLButton* buttonp = dynamic_cast<LLButton*>(handled_view);
-	//	LLLineEditor* line_editorp = dynamic_cast<LLLineEditor*>(handled_view);
-	//	LLTextEditor* text_editorp = dynamic_cast<LLTextEditor*>(handled_view);
-	//	LLTextBox* text_boxp = dynamic_cast<LLTextBox*>(handled_view);
-	//	if (buttonp
-	//		|| line_editorp
-	//		|| text_editorp
-	//		|| text_boxp)
-	//	{
-	//		sEditingUIView = handled_view;
-	//	}
-	//}
-
-	return handled;
+	return childrenHandleMouseDown( x, y, mask ) != NULL;
 }
 
 BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		handleMouseDown(x, y, mask);
-		handled = TRUE;
-	}
-	return handled;
+	return childrenHandleDoubleClick( x, y, mask ) != NULL;
 }
 
 BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
-	if( getVisible() && getEnabled() )
-	{
-		return childrenHandleScrollWheel( x, y, clicks ) != NULL;
-	}
-	return FALSE;
+	return childrenHandleScrollWheel( x, y, clicks ) != NULL;
 }
 
 BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = childrenHandleRightMouseDown( x, y, mask ) != NULL;
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		handled = TRUE;
-	}
-	return handled;
+	return childrenHandleRightMouseDown( x, y, mask ) != NULL;
 }
 
 BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = childrenHandleRightMouseUp( x, y, mask ) != NULL;
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		handled = TRUE;
-	}
-	return handled;
+	return childrenHandleRightMouseUp( x, y, mask ) != NULL;
 }
  
 BOOL LLView::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
 {
-	LLView* handled_view = childrenHandleMiddleMouseDown( x, y, mask );
-	BOOL handled = (handled_view != NULL);
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		handled = TRUE;
-		handled_view = this;
-	}
-
-	return handled;
+	return childrenHandleMiddleMouseDown( x, y, mask ) != NULL;
 }
 
 BOOL LLView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
 {
-	BOOL handled = childrenHandleMiddleMouseUp( x, y, mask ) != NULL;
-	if( !handled && blockMouseEvent(x, y) )
-	{
-		handled = TRUE;
-	}
-	return handled;
+	return childrenHandleMiddleMouseUp( x, y, mask ) != NULL;
 }
 
 
@@ -974,10 +885,14 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if (viewp->pointInView(local_x, local_y) 
-				&& viewp->getVisible()
-				&& viewp->getEnabled()
-				&& viewp->handleScrollWheel( local_x, local_y, clicks ))
+			if (!viewp->pointInView(local_x, local_y) 
+				|| !viewp->getVisible()
+				|| !viewp->getEnabled())
+			{
+				continue;
+			}
+
+			if (viewp->handleScrollWheel( local_x, local_y, clicks ))
 			{
 				if (sDebugMouseHandling)
 				{
@@ -987,6 +902,12 @@ LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
 				handled_view = viewp;
 				break;
 			}
+
+			if (viewp->blockMouseEvent(local_x, local_y))
+			{
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1002,10 +923,14 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if(viewp->pointInView(local_x, local_y) &&
-				viewp->getVisible() &&
-				viewp->getEnabled() &&
-				viewp->handleHover(local_x, local_y, mask) )
+			if(!viewp->pointInView(local_x, local_y) 
+				|| !viewp->getVisible() 
+				|| !viewp->getEnabled())
+			{
+				continue;
+			}
+
+			if (viewp->handleHover(local_x, local_y, mask) )
 			{
 				if (sDebugMouseHandling)
 				{
@@ -1015,6 +940,14 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
 				handled_view = viewp;
 				break;
 			}
+
+			if (viewp->blockMouseEvent(local_x, local_y))
+			{
+				LLUI::sWindow->setCursor(viewp->getHoverCursor());
+
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1080,10 +1013,14 @@ LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
 		S32 local_x = x - viewp->getRect().mLeft;
 		S32 local_y = y - viewp->getRect().mBottom;
 
-		if (viewp->pointInView(local_x, local_y) && 
-			viewp->getVisible() && 
-			viewp->getEnabled() && 
-			viewp->handleMouseDown( local_x, local_y, mask ))
+		if (!viewp->pointInView(local_x, local_y) 
+			|| !viewp->getVisible() 
+			|| !viewp->getEnabled())
+		{
+			continue;
+		}
+
+		if(viewp->handleMouseDown( local_x, local_y, mask ))
 		{
 			if (sDebugMouseHandling)
 			{
@@ -1092,6 +1029,12 @@ LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
 			handled_view = viewp;
 			break;
 		}
+
+		if(viewp->blockMouseEvent(local_x, local_y))
+		{
+			handled_view = viewp;
+			break;
+		}
 	}
 	return handled_view;
 }
@@ -1107,10 +1050,15 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if (viewp->pointInView(local_x, local_y) &&
-				viewp->getVisible() &&
-				viewp->getEnabled() &&
-				viewp->handleRightMouseDown( local_x, local_y, mask ))
+
+			if (!viewp->pointInView(local_x, local_y)
+				|| !viewp->getVisible() 
+				|| !viewp->getEnabled())
+			{
+				continue;
+			}
+
+			if (viewp->handleRightMouseDown( local_x, local_y, mask ))
 			{
 				if (sDebugMouseHandling)
 				{
@@ -1120,6 +1068,12 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
 				handled_view = viewp;
 				break;
 			}
+
+			if (viewp->blockMouseEvent(local_x, local_y))
+			{
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1136,10 +1090,14 @@ LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if (viewp->pointInView(local_x, local_y) &&
-				viewp->getVisible() &&
-				viewp->getEnabled() &&
-				viewp->handleMiddleMouseDown( local_x, local_y, mask ))
+			if (!viewp->pointInView(local_x, local_y)
+				|| !viewp->getVisible() 
+				|| !viewp->getEnabled())
+			{
+				continue;
+			}
+
+			if(viewp->handleMiddleMouseDown( local_x, local_y, mask ))
 			{
 				if (sDebugMouseHandling)
 				{
@@ -1148,6 +1106,12 @@ LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask)
 				handled_view = viewp;
 				break;
 			}
+
+			if (viewp->blockMouseEvent(local_x, local_y))
+			{
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1164,10 +1128,15 @@ LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if (viewp->pointInView(local_x, local_y) &&
-				viewp->getVisible() &&
-				viewp->getEnabled() &&
-				viewp->handleDoubleClick( local_x, local_y, mask ))
+
+			if (!viewp->pointInView(local_x, local_y) 
+				|| !viewp->getVisible() 
+				|| !viewp->getEnabled())
+			{
+				continue;
+			}
+
+			if (viewp->handleDoubleClick( local_x, local_y, mask ))
 			{
 				if (sDebugMouseHandling)
 				{
@@ -1176,6 +1145,12 @@ LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
 				handled_view = viewp;
 				break;
 			}
+
+			if (viewp->blockMouseEvent(local_x, local_y))
+			{
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1191,12 +1166,13 @@ LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if (!viewp->pointInView(local_x, local_y))
-				continue;
-			if (!viewp->getVisible())
-				continue;
-			if (!viewp->getEnabled())
+			if (!viewp->pointInView(local_x, local_y)
+				|| !viewp->getVisible()
+				|| !viewp->getEnabled())
+			{
 				continue;
+			}
+			
 			if (viewp->handleMouseUp( local_x, local_y, mask ))
 			{
 				if (sDebugMouseHandling)
@@ -1206,6 +1182,12 @@ LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
 				handled_view = viewp;
 				break;
 			}
+
+			if (viewp->blockMouseEvent(local_x, local_y))
+			{
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1221,10 +1203,14 @@ LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if (viewp->pointInView(local_x, local_y) &&
-				viewp->getVisible() &&
-				viewp->getEnabled() &&
-				viewp->handleRightMouseUp( local_x, local_y, mask ))
+			if (!viewp->pointInView(local_x, local_y) 
+				|| !viewp->getVisible() 
+				|| !viewp->getEnabled() )
+			{
+				continue;
+			}
+
+			if(viewp->handleRightMouseUp( local_x, local_y, mask ))
 			{
 				if (sDebugMouseHandling)
 				{
@@ -1233,6 +1219,12 @@ LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
 				handled_view = viewp;
 				break;
 			}
+
+			if(viewp->blockMouseEvent(local_x, local_y))
+			{
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1248,10 +1240,14 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
 			LLView* viewp = *child_it;
 			S32 local_x = x - viewp->getRect().mLeft;
 			S32 local_y = y - viewp->getRect().mBottom;
-			if (viewp->pointInView(local_x, local_y) &&
-				viewp->getVisible() &&
-				viewp->getEnabled() &&
-				viewp->handleMiddleMouseUp( local_x, local_y, mask ))
+			if (!viewp->pointInView(local_x, local_y) 
+				|| !viewp->getVisible() 
+				|| !viewp->getEnabled())
+			{
+				continue;
+			}
+				
+			if(viewp->handleMiddleMouseUp( local_x, local_y, mask ))
 			{
 				if (sDebugMouseHandling)
 				{
@@ -1260,6 +1256,12 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask)
 				handled_view = viewp;
 				break;
 			}
+
+			if (viewp->blockMouseEvent(local_x, local_y))
+			{
+				handled_view = viewp;
+				break;
+			}
 		}
 	}
 	return handled_view;
@@ -1272,18 +1274,6 @@ void LLView::draw()
 
 void LLView::drawChildren()
 {
-	if (sDebugRects)
-	{
-		drawDebugRect();
-
-		// Check for bogus rectangle
-		if (getRect().mRight <= getRect().mLeft
-			|| getRect().mTop <= getRect().mBottom)
-		{
-			llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl;
-		}
-	}
-
 	if (!mChildList.empty())
 	{
 		LLRect rootRect = getRootView()->getRect();
@@ -1307,6 +1297,17 @@ void LLView::drawChildren()
 					{
 						LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
 						viewp->draw();
+
+						if (sDebugRects)
+						{
+							viewp->drawDebugRect();
+
+							// Check for bogus rectangle
+							if (!getRect().isValid())
+							{
+								llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl;
+							}
+						}
 					}
 					LLUI::popMatrix();
 				}
@@ -1353,10 +1354,6 @@ void LLView::drawDebugRect()
 
 		// draw red rectangle for the border
 		LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
-		//if (sEditingUI)
-		//{
-		//	border_color.mV[0] = 1.f;
-		//}
 		if(preview_iter != sPreviewHighlightedElements.end())
 		{
 			if(LLView::sPreviewClickedElement && this == sPreviewClickedElement)
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 7a37d6f4303..7ddff2bd9ef 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -42,8 +42,6 @@
 #include "llfontgl.h"
 #include "llmortician.h"
 #include "llmousehandler.h"
-#include "llnametable.h"
-#include "llsd.h"
 #include "llstring.h"
 #include "llrect.h"
 #include "llui.h"
@@ -58,6 +56,8 @@
 
 #include <list>
 
+class LLSD;
+
 const U32	FOLLOWS_NONE	= 0x00;
 const U32	FOLLOWS_LEFT	= 0x01;
 const U32	FOLLOWS_RIGHT	= 0x02;
@@ -124,21 +124,16 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 		Optional<bool>				enabled,
 									visible,
 									mouse_opaque,
-									use_bounding_rect;
+									use_bounding_rect,
+									from_xui;
 
 		Optional<S32>				tab_group,
 									default_tab_group;
 		Optional<std::string>		tool_tip;
 
 		Optional<S32>				sound_flags;
-		Optional<bool>				from_xui;
 		Optional<Follows>			follows;
 		Optional<std::string>		hover_cursor;
-		
-		// font params
-		Optional<const LLFontGL*>	font;
-		Optional<LLFontGL::HAlign>	font_halign;
-		Optional<LLFontGL::VAlign>	font_valign;
 
 		Optional<std::string>		layout;
 		Optional<LLRect>			rect;
@@ -223,9 +218,6 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 
 	virtual ~LLView();
 
-	// Hack to support LLFocusMgr (from LLMouseHandler)
-	/*virtual*/ BOOL isView() const;
-
 	// Some UI widgets need to be added as controls.  Others need to
 	// be added as regular view children.  isCtrl should return TRUE
 	// if a widget needs to be added as a ctrl
@@ -258,6 +250,8 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	void		setUseBoundingRect( BOOL use_bounding_rect );
 	BOOL		getUseBoundingRect();
 
+	ECursorType	getHoverCursor() { return mHoverCursor; }
+
 	const std::string& getToolTip() const			{ return mToolTipMsg.getString(); }
 
 	void		sendChildToFront(LLView* child);
@@ -443,12 +437,11 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	/*virtual*/ BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks);
 	/*virtual*/ BOOL	handleRightMouseDown(S32 x, S32 y, MASK mask);
 	/*virtual*/ BOOL	handleRightMouseUp(S32 x, S32 y, MASK mask);	
-	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect); // Display mToolTipMsg if no child handles it.
+	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, MASK mask);
 
-	/*virtual*/ const std::string&	getName() const;
+	/*virtual*/ std::string	getName() const;
 	/*virtual*/ void	onMouseCaptureLost();
 	/*virtual*/ BOOL	hasMouseCapture();
-	/*virtual*/ BOOL isView(); // Hack to support LLFocusMgr
 	/*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;
 
@@ -545,7 +538,7 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	LLView*	childrenHandleScrollWheel(S32 x, S32 y, S32 clicks);
 	LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask);
 	LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask);
-	LLView* childrenHandleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect);
+	LLView* childrenHandleToolTip(S32 x, S32 y, MASK mask);
 
 	ECursorType mHoverCursor;
 	
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 1e7a0f7f2c9..468fae2ec59 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -24,9 +24,17 @@
 #include "../llurlentry.h"
 #include "llurlentry_stub.cpp"
 #include "lltut.h"
+#include "../lluicolortable.h"
 
 #include <boost/regex.hpp>
 
+LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const
+{
+	return LLUIColor();
+}
+
+LLUIColor::LLUIColor() {}
+
 namespace tut
 {
 	struct LLUrlEntryData
@@ -276,6 +284,11 @@ namespace tut
 		testRegex("Agent Url multicase", r,
 				  "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About XXX",
 				  "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/About");
+
+		testRegex("Agent Url alternate command", r,
+				  "XXX secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar",
+				  "secondlife:///App/AGENT/0E346D8B-4433-4d66-a6b0-fd37083abc4c/foobar");
+
 	}
 
 	template<> template<>
diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp
index 4dae49db903..e8cf1353464 100644
--- a/indra/llui/tests/llurlmatch_test.cpp
+++ b/indra/llui/tests/llurlmatch_test.cpp
@@ -23,6 +23,10 @@
 #include "../llurlmatch.h"
 #include "lltut.h"
 
+// link seam
+LLUIColor::LLUIColor()
+{}
+
 namespace tut
 {
 	struct LLUrlMatchData
@@ -49,7 +53,7 @@ namespace tut
 		LLUrlMatch match;
 		ensure("empty()", match.empty());
 
-		match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", "", "");
+		match.setValues(0, 1, "http://secondlife.com", "Second Life", "", "", LLUIColor(), "", "");
 		ensure("! empty()", ! match.empty());
 	}
 
@@ -62,7 +66,7 @@ namespace tut
 		LLUrlMatch match;
 		ensure_equals("getStart() == 0", match.getStart(), 0);
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure_equals("getStart() == 10", match.getStart(), 10);
 	}
 
@@ -75,7 +79,7 @@ namespace tut
 		LLUrlMatch match;
 		ensure_equals("getEnd() == 0", match.getEnd(), 0);
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure_equals("getEnd() == 20", match.getEnd(), 20);
 	}
 
@@ -88,10 +92,10 @@ namespace tut
 		LLUrlMatch match;
 		ensure_equals("getUrl() == ''", match.getUrl(), "");
 
-		match.setValues(10, 20, "http://slurl.com/", "", "", "", "", "");
+		match.setValues(10, 20, "http://slurl.com/", "", "", "", LLUIColor(), "", "");
 		ensure_equals("getUrl() == 'http://slurl.com/'", match.getUrl(), "http://slurl.com/");
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure_equals("getUrl() == '' (2)", match.getUrl(), "");
 	}
 
@@ -104,10 +108,10 @@ namespace tut
 		LLUrlMatch match;
 		ensure_equals("getLabel() == ''", match.getLabel(), "");
 
-		match.setValues(10, 20, "", "Label", "", "", "", "");
+		match.setValues(10, 20, "", "Label", "", "", LLUIColor(), "", "");
 		ensure_equals("getLabel() == 'Label'", match.getLabel(), "Label");
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure_equals("getLabel() == '' (2)", match.getLabel(), "");
 	}
 
@@ -120,10 +124,10 @@ namespace tut
 		LLUrlMatch match;
 		ensure_equals("getTooltip() == ''", match.getTooltip(), "");
 
-		match.setValues(10, 20, "", "", "Info", "", "", "");
+		match.setValues(10, 20, "", "", "Info", "", LLUIColor(), "", "");
 		ensure_equals("getTooltip() == 'Info'", match.getTooltip(), "Info");
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure_equals("getTooltip() == '' (2)", match.getTooltip(), "");
 	}
 
@@ -136,10 +140,10 @@ namespace tut
 		LLUrlMatch match;
 		ensure_equals("getIcon() == ''", match.getIcon(), "");
 
-		match.setValues(10, 20, "", "", "", "Icon", "", "");
+		match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "", "");
 		ensure_equals("getIcon() == 'Icon'", match.getIcon(), "Icon");
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure_equals("getIcon() == '' (2)", match.getIcon(), "");
 	}
 
@@ -152,10 +156,10 @@ namespace tut
 		LLUrlMatch match;
 		ensure("getMenuName() empty", match.getMenuName().empty());
 
-		match.setValues(10, 20, "", "", "", "Icon", "xui_file.xml", "");
+		match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "");
 		ensure_equals("getMenuName() == \"xui_file.xml\"", match.getMenuName(), "xui_file.xml");
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure("getMenuName() empty (2)", match.getMenuName().empty());
 	}
 
@@ -168,10 +172,10 @@ namespace tut
 		LLUrlMatch match;
 		ensure("getLocation() empty", match.getLocation().empty());
 
-		match.setValues(10, 20, "", "", "", "Icon", "xui_file.xml", "Paris");
+		match.setValues(10, 20, "", "", "", "Icon", LLUIColor(), "xui_file.xml", "Paris");
 		ensure_equals("getLocation() == \"Paris\"", match.getLocation(), "Paris");
 
-		match.setValues(10, 20, "", "", "", "", "", "");
+		match.setValues(10, 20, "", "", "", "", LLUIColor(), "", "");
 		ensure("getLocation() empty (2)", match.getLocation().empty());
 	}
 }
diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h
index b5dbbc53fbd..d758a1638ac 100644
--- a/indra/llwindow/llmousehandler.h
+++ b/indra/llwindow/llmousehandler.h
@@ -70,14 +70,11 @@ class LLMouseHandler
 
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask) = 0;
 	virtual BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks) = 0;
-	virtual BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen) = 0;
-	virtual const std::string& getName() const = 0;
+	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask) = 0;
+	virtual std::string getName() const = 0;
 
 	virtual void	onMouseCaptureLost() = 0;
 
-	// Hack to support LLFocusMgr
-	virtual BOOL isView() const = 0;
-
 	virtual void	screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const = 0;
 	virtual void	localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const = 0;
 
diff --git a/indra/llwindow/llpreeditor.h b/indra/llwindow/llpreeditor.h
index dd63a98606e..fcb39515e7f 100644
--- a/indra/llwindow/llpreeditor.h
+++ b/indra/llwindow/llpreeditor.h
@@ -94,7 +94,7 @@ class LLPreeditor
 	// Get the contents of this preeditor as a LLWString.  If there is an active preedit,
 	// the returned LLWString contains it.
 
-	virtual LLWString getWText() const = 0;
+	virtual LLWString getPreeditString() const = 0;
 
 	// Handle a UTF-32 char on this preeditor, i.e., add the character
 	// to the contents.
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 82dc5e4a13c..d2760e3d593 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -2016,7 +2016,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 							// Although the spec. is unclear, replace range should
 							// not present when there is an active preedit.  We just
 							// ignore the case.  markAsPreedit will detect the case and warn it.
-							const LLWString & text = mPreeditor->getWText();
+							const LLWString & text = mPreeditor->getPreeditString();
 							const S32 location = wstring_wstring_length_from_utf16_length(text, 0, range.location);
 							const S32 length = wstring_wstring_length_from_utf16_length(text, location, range.length);
 							mPreeditor->markAsPreedit(location, length);
@@ -2214,7 +2214,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 					{
 						S32 preedit, preedit_length;
 						mPreeditor->getPreeditRange(&preedit, &preedit_length);
-						const LLWString & text = mPreeditor->getWText();
+						const LLWString & text = mPreeditor->getPreeditString();
 						 
 						LLCoordGL caret_coord;
 						LLRect preedit_bounds;
@@ -2251,7 +2251,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 						mPreeditor->getSelectionRange(&selection, &selection_length);
 						if (selection_length)
 						{
-							const LLWString text = mPreeditor->getWText().substr(selection, selection_length);
+							const LLWString text = mPreeditor->getPreeditString().substr(selection, selection_length);
 							const llutf16string text_utf16 = wstring_to_utf16str(text);
 							result = SetEventParameter(event, kEventParamTextInputReplyText, typeUnicodeText,
 										text_utf16.length() * sizeof(U16), text_utf16.c_str());
@@ -2637,7 +2637,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 
 					S32 preedit, preedit_length;
 					mPreeditor->getPreeditRange(&preedit, &preedit_length);
-					const LLWString & text = mPreeditor->getWText();
+					const LLWString & text = mPreeditor->getPreeditString();
 					const CFIndex length = wstring_utf16_length(text, 0, preedit)
 						+ wstring_utf16_length(text, preedit + preedit_length, text.length());
 					result = SetEventParameter(event, kEventParamTSMDocAccessCharacterCount, typeCFIndex, sizeof(length), &length);
@@ -2654,7 +2654,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 
 					S32 preedit, preedit_length;
 					mPreeditor->getPreeditRange(&preedit, &preedit_length);
-					const LLWString & text = mPreeditor->getWText();
+					const LLWString & text = mPreeditor->getPreeditString();
 					
 					CFRange range;
 					if (preedit_length)
@@ -2688,7 +2688,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 					{
 						S32 preedit, preedit_length;
 						mPreeditor->getPreeditRange(&preedit, &preedit_length);
-						const LLWString & text = mPreeditor->getWText();
+						const LLWString & text = mPreeditor->getPreeditString();
 
 						// The GetCharacters event of TSMDA has a fundamental flaw;
 						// An input method need to decide the starting offset and length
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 9936b24292c..0faa3e93ffb 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -3544,7 +3544,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
 				// WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the
 				// number to getPreeditLocation.  
 
-				const LLWString & wtext = mPreeditor->getWText();
+				const LLWString & wtext = mPreeditor->getPreeditString();
 				S32 preedit, preedit_length;
 				mPreeditor->getPreeditRange(&preedit, &preedit_length);
 				LLCoordGL caret_coord;
@@ -3571,7 +3571,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
 			case IMR_RECONVERTSTRING:
 			{
 				mPreeditor->resetPreedit();
-				const LLWString & wtext = mPreeditor->getWText();
+				const LLWString & wtext = mPreeditor->getPreeditString();
 				S32 select, select_length;
 				mPreeditor->getSelectionRange(&select, &select_length);
 
@@ -3613,7 +3613,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
 			}
 			case IMR_DOCUMENTFEED:
 			{
-				const LLWString & wtext = mPreeditor->getWText();
+				const LLWString & wtext = mPreeditor->getPreeditString();
 				S32 preedit, preedit_length;
 				mPreeditor->getPreeditRange(&preedit, &preedit_length);
 				
diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h
index 818d774f73f..7823607c3b3 100644
--- a/indra/llxml/llxmlnode.h
+++ b/indra/llxml/llxmlnode.h
@@ -34,7 +34,7 @@
 #define LL_LLXMLNODE_H
 
 #ifndef XML_STATIC
-#define XML_STATIC 1
+#define XML_STATIC
 #endif
 #ifdef LL_STANDALONE
 #include <expat.h>
diff --git a/indra/llxml/llxmlparser.h b/indra/llxml/llxmlparser.h
index d7595f6a68f..fa9e8175e21 100644
--- a/indra/llxml/llxmlparser.h
+++ b/indra/llxml/llxmlparser.h
@@ -34,7 +34,7 @@
 #define LL_LLXMLPARSER_H
 
 #ifndef XML_STATIC
-#define XML_STATIC 1
+#define XML_STATIC
 #endif
 #ifdef LL_STANDALONE
 #include <expat.h>
diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h
index baa782916e6..88bc4305040 100644
--- a/indra/llxuixml/llinitparam.h
+++ b/indra/llxuixml/llinitparam.h
@@ -1568,11 +1568,11 @@ namespace LLInitParam
 		public Param
 	{
 	public:
-		typedef BlockValue<T>																self_t;
-		typedef Block<TypedParam<T, TypeValues<T>, false> >									block_t;
-		typedef const T&															value_const_ref_t;
-		typedef value_const_ref_t															value_assignment_t;
-		typedef typename TypeValues<T>::KeyCache											key_cache_t;
+		typedef BlockValue<T>										self_t;
+		typedef Block<TypedParam<T, TypeValues<T>, false> >			block_t;
+		typedef const T&											value_const_ref_t;
+		typedef value_const_ref_t									value_assignment_t;
+		typedef typename TypeValues<T>::KeyCache					key_cache_t;
 
 		BlockValue(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
 		:	Param(block_descriptor.mCurrentBlockPtr),
@@ -1754,11 +1754,16 @@ namespace LLInitParam
 	protected:
 		value_assignment_t get() const
 		{
-			if (mData.mLastParamVersion < BaseBlock::getLastChangeVersion() && block_t::validateBlock(true))
+			// if some parameters were provided, issue warnings on invalid blocks
+			if (Param::getProvided() && (mData.mLastParamVersion < BaseBlock::getLastChangeVersion()))
 			{
-				mData.mValue = static_cast<const DERIVED*>(this)->getValueFromBlock();
-				mData.clearKey();
-				mData.mLastParamVersion = BaseBlock::getLastChangeVersion();
+				// go ahead and issue warnings at this point if any param is invalid
+				if(block_t::validateBlock(false))
+				{
+					mData.mValue = static_cast<const DERIVED*>(this)->getValueFromBlock();
+					mData.clearKey();
+					mData.mLastParamVersion = BaseBlock::getLastChangeVersion();
+				}
 			}
 
 			return mData.mValue;
diff --git a/indra/llxuixml/lltrans.cpp b/indra/llxuixml/lltrans.cpp
index 2efc475f573..e974dbd0ba0 100644
--- a/indra/llxuixml/lltrans.cpp
+++ b/indra/llxuixml/lltrans.cpp
@@ -194,3 +194,68 @@ bool LLTrans::findString(std::string &result, const std::string &xml_desc, const
 		return false;
 	}
 }
+
+//static
+std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count)
+{
+	// Compute which string identifier to use
+	const char* form = "";
+	if (language == "ru") // Russian
+	{
+		// From GNU ngettext()
+		// Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
+		if (count % 10 == 1
+			&& count % 100 != 11)
+		{
+			// singular, "1 item"
+			form = "A";
+		}
+		else if (count % 10 >= 2
+			&& count % 10 <= 4
+			&& (count % 100 < 10 || count % 100 >= 20) )
+		{
+			// special case "2 items", "23 items", but not "13 items"
+			form = "B";
+		}
+		else
+		{
+			// English-style plural, "5 items"
+			form = "C";
+		}
+	}
+	else if (language == "fr" || language == "pt") // French, Brazilian Portuguese
+	{
+		// French and Portuguese treat zero as a singular "0 item" not "0 items"
+		if (count == 0 || count == 1)
+		{
+			form = "A";
+		}
+		else
+		{
+			// English-style plural
+			form = "B";
+		}
+	}
+	else // default
+	{
+		// languages like English with 2 forms, singular and plural
+		if (count == 1)
+		{
+			// "1 item"
+			form = "A";
+		}
+		else
+		{
+			// "2 items", also use plural for "0 items"
+			form = "B";
+		}
+	}
+
+	// Translate that string
+	LLStringUtil::format_map_t args;
+	args["[COUNT]"] = llformat("%d", count);
+
+	// Look up "AgeYearsB" or "AgeWeeksC" including the "form"
+	std::string key = llformat("%s%s", xml_desc.c_str(), form);
+	return getString(key, args);
+}
diff --git a/indra/llxuixml/lltrans.h b/indra/llxuixml/lltrans.h
index 340d70e4347..79df5802e5f 100644
--- a/indra/llxuixml/lltrans.h
+++ b/indra/llxuixml/lltrans.h
@@ -80,6 +80,12 @@ class LLTrans
 	static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args);
 	static bool findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& args);
 
+	// Returns translated string with [COUNT] replaced with a number, following
+	// special per-language logic for plural nouns.  For example, some languages
+	// may have different plurals for 0, 1, 2 and > 2.
+	// See "AgeWeeksA", "AgeWeeksB", etc. in strings.xml for examples.
+	static std::string getCountString(const std::string& language, const std::string& xml_desc, S32 count);
+
 	/**
 	 * @brief Returns a translated string
 	 * @param xml_desc String's description
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b217a5b781e..14a37981a6e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -106,6 +106,7 @@ set(viewer_SOURCE_FILES
     llconfirmationmanager.cpp
     llcurrencyuimanager.cpp
     llcylinder.cpp
+    lldateutil.cpp
     lldebugmessagebox.cpp
     lldebugview.cpp
     lldelayedgestureerror.cpp
@@ -241,6 +242,7 @@ set(viewer_SOURCE_FILES
     llimview.cpp
     llimcontrolpanel.cpp
     llinspectavatar.cpp
+    llinspectobject.cpp
     llinventorybridge.cpp
     llinventoryclipboard.cpp
     llinventoryfilter.cpp
@@ -395,7 +397,6 @@ set(viewer_SOURCE_FILES
     lltoastimpanel.cpp
     lltoastnotifypanel.cpp
     lltoastpanel.cpp
-    lltoggleablemenu.cpp
     lltoolbar.cpp
     lltoolbrush.cpp
     lltoolcomp.cpp
@@ -576,6 +577,7 @@ set(viewer_HEADER_FILES
     llconfirmationmanager.h
     llcurrencyuimanager.h
     llcylinder.h
+    lldateutil.h
     lldebugmessagebox.h
     lldebugview.h
     lldelayedgestureerror.h
@@ -711,6 +713,7 @@ set(viewer_HEADER_FILES
     llimview.h
     llimcontrolpanel.h
     llinspectavatar.h
+    llinspectobject.h
     llinventorybridge.h
     llinventoryclipboard.h
     llinventoryfilter.h
@@ -865,7 +868,6 @@ set(viewer_HEADER_FILES
     lltoastimpanel.h
     lltoastnotifypanel.h
     lltoastpanel.h
-    lltoggleablemenu.h
     lltool.h
     lltoolbar.h
     lltoolbrush.h
@@ -1538,9 +1540,12 @@ if (INSTALL)
   include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake)
 endif (INSTALL)
 
+# To add a viewer unit test, just add the test .cpp file below
+# This creates a separate test project per file listed.
 include(LLAddBuildTest)
 SET(viewer_TEST_SOURCE_FILES
   llagentaccess.cpp
+  lldateutil.cpp
   llviewerhelputil.cpp
   )
 set_source_files_properties(
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 99b662a63f3..94a5f5c52bc 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3673,7 +3673,7 @@
       <key>Type</key>
       <string>F32</string>
       <key>Value</key>
-      <string>0.1</string>
+      <real>0.15</real>
     </map> 
     <key>InstallLanguage</key>
     <map>
@@ -7585,7 +7585,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>    
     <key>ShowCameraButton</key>                
     <map>
@@ -8456,18 +8456,40 @@
       <key>Value</key>
       <real>0.2</real>
     </map>
-  <key>ToolTipVisibleTime</key>
-  <map>
-    <key>Comment</key>
-    <string>Fade tooltip after mouse is idle for this long</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>F32</string>
-    <key>Value</key>
-    <real>10.0</real>
-  </map>
-  <key>ToolboxAutoMove</key>
+    <key>ToolTipVisibleTimeFar</key>
+    <map>
+      <key>Comment</key>
+      <string>Fade tooltip after after time passes (seconds) while mouse not near tooltip</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>1.0</real>
+    </map>
+    <key>ToolTipVisibleTimeNear</key>
+    <map>
+      <key>Comment</key>
+      <string>Fade tooltip after after time passes (seconds) while mouse near tooltip</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>5.0</real>
+    </map>
+    <key>ToolTipVisibleTimeOver</key>
+    <map>
+      <key>Comment</key>
+      <string>Fade tooltip after after time passes (seconds) while mouse over tooltip</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>1000.0</real>
+    </map>
+    <key>ToolboxAutoMove</key>
     <map>
       <key>Comment</key>
       <string>[NOT USED]</string>
@@ -9654,39 +9676,6 @@
       <string>S32</string>
       <key>Value</key>
       <integer>15</integer>
-    </map>
-    <key>UITextEditorBorder</key>
-    <map>
-      <key>Comment</key>
-      <string>UI Text Editor Border</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>S32</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
-    <key>UITextEditorHPad</key>
-    <map>
-      <key>Comment</key>
-      <string>UI Text Horizontal Pad</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>S32</string>
-      <key>Value</key>
-      <integer>4</integer>
-    </map>
-    <key>UITextEditorVPadTop</key>
-    <map>
-      <key>Comment</key>
-      <string>UI Text Vertical Pad Top</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>S32</string>
-      <key>Value</key>
-      <integer>4</integer>
     </map>
 	<key>UploadBakedTexOld</key>
     <map>
diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index 73a548cdc6e..a7322749ca8 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -758,7 +758,7 @@ CreateShortCut	"$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \
 
 WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Create Account.url" \
 				"InternetShortcut" "URL" \
-				"http://www.secondlife.com/registration/"
+				"http://join.secondlife.com/"
 WriteINIStr		"$SMPROGRAMS\$INSTSHORTCUT\SL Your Account.url" \
 				"InternetShortcut" "URL" \
 				"http://www.secondlife.com/account/"
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 30e0a5770c3..41cbc21fe9b 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -696,9 +696,6 @@ bool LLAppViewer::init()
 	// Let code in llui access the viewer help floater
 	LLUI::sHelpImpl = LLViewerHelp::getInstance();
 
-	// Set the link color for any Urls in text fields
-	LLTextBase::setLinkColor( LLUIColorTable::instance().getColor("HTMLLinkColor") );
-
 	// Load translations for tooltips
 	LLFloater::initClass();
 
@@ -1424,6 +1421,9 @@ bool LLAppViewer::cleanup()
 		gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
 	}
 
+	// Turn off Space Navigator and similar devices
+	LLViewerJoystick::getInstance()->terminate();
+
 	removeMarkerFile(); // Any crashes from here on we'll just have to ignore
 	
 	writeDebugInfo();
@@ -2379,7 +2379,6 @@ void LLAppViewer::cleanupSavedSettings()
 	}
 
 	gSavedSettings.setF32("MapScale", gMapScale );
-	gSavedSettings.setBOOL("ShowHoverTips", gToolTipView->getVisible());
 
 	// Some things are cached in LLAgent.
 	if (gAgent.mInitialized)
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 1676bb1d446..92b2768f39e 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -39,16 +39,22 @@
 #include "lldarray.h"
 #include "llnotifications.h"
 
+#include "roles_constants.h"    // for GP_MEMBER_INVITE
+
 #include "llagent.h"
 #include "llappviewer.h"		// for gLastVersionChannel
 #include "llcachename.h"
 #include "llcallingcard.h"		// for LLAvatarTracker
-#include "llgivemoney.h"		// foe LLFloaterPay
+#include "llfloatergroupinvite.h"
+#include "llfloatergroups.h"
+#include "llfloaterreg.h"
+#include "llgivemoney.h"
 #include "llinventorymodel.h"	// for gInventory.findCategoryUUIDForType
 #include "llimview.h"			// for gIMMgr
 #include "llmutelist.h"
 #include "llrecentpeople.h"
 #include "llsidetray.h"
+#include "llviewerobjectlist.h"
 #include "llviewermessage.h"	// for handle_lure
 #include "llviewerregion.h"
 
@@ -244,6 +250,17 @@ void LLAvatarActions::toggleBlock(const LLUUID& id)
 	}
 }
 
+void LLAvatarActions::inviteToGroup(const LLUUID& id)
+{
+	LLFloaterGroupPicker* widget = LLFloaterReg::showTypedInstance<LLFloaterGroupPicker>("group_picker", LLSD(id));
+	if (widget)
+	{
+		widget->center();
+		widget->setPowersMask(GP_MEMBER_INVITE);
+		widget->setSelectGroupCallback(boost::bind(callback_invite_to_group, _1, id));
+	}
+}
+
 //== private methods ========================================================================================
 
 // static
@@ -293,6 +310,16 @@ bool LLAvatarActions::handlePay(const LLSD& notification, const LLSD& response,
 	return false;
 }
 
+// static
+void LLAvatarActions::callback_invite_to_group(LLUUID group_id, LLUUID id)
+{
+	std::vector<LLUUID> agent_ids;
+	agent_ids.push_back(id);
+	
+	LLFloaterGroupInvite::showForGroup(group_id, &agent_ids);
+}
+
+
 // static
 bool LLAvatarActions::callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response)
 {
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index e911715c708..512f673b432 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -96,11 +96,17 @@ class LLAvatarActions
 	 */
 	static bool isBlocked(const LLUUID& id);
 
+	/**
+	 * Invite avatar to a group.
+	 */	
+	static void inviteToGroup(const LLUUID& id);
+	
 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);
+	static void callback_invite_to_group(LLUUID group_id, LLUUID id);
 
 	// Just request friendship, no dialog.
 	static void requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message);
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 665dffc8c6b..51545bcc07c 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -148,7 +148,7 @@ void LLAvatarListItem::setAvatarId(const LLUUID& id)
 
 void LLAvatarListItem::onInfoBtnClick()
 {
-	LLFloaterReg::showInstance("inspect_avatar", mAvatarId);
+	LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", mAvatarId));
 
 	/* TODO fix positioning of inspector
 	localPointToScreen(mXPos, mYPos, &mXPos, &mYPos);
diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp
index e568b9c5263..5c68ac8cdb8 100644
--- a/indra/newview/llavatarpropertiesprocessor.cpp
+++ b/indra/newview/llavatarpropertiesprocessor.cpp
@@ -42,12 +42,18 @@
 #include "llavatarconstants.h"	// AVATAR_TRANSACTED, etc.
 #include "lldate.h"
 #include "lltrans.h"
+#include "llui.h"				// LLUI::getLanguage()
 #include "message.h"
 
 LLAvatarPropertiesProcessor::LLAvatarPropertiesProcessor()
 {
 }
 
+LLAvatarPropertiesProcessor::~LLAvatarPropertiesProcessor()
+{
+	llinfos << "JAMESDEBUG cleanup avatar properties processor" << llendl;
+}
+
 void LLAvatarPropertiesProcessor::addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer)
 {
 	// Check if that observer is already in mObservers for that avatar_id
@@ -172,103 +178,6 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData*
 	gAgent.sendReliableMessage();
 }
 
-//static
-std::string LLAvatarPropertiesProcessor::ageFromDate(const std::string& date_string)
-{
-	// Convert string date to malleable representation
-	S32 month, day, year;
-	S32 matched = sscanf(date_string.c_str(), "%d/%d/%d", &month, &day, &year);
-	if (matched != 3) return "???";
-
-	// Create ISO-8601 date string
-	std::string iso8601_date_string =
-		llformat("%04d-%02d-%02dT00:00:00Z", year, month, day);
-	LLDate date(iso8601_date_string);
-
-	// Correct for the fact that account creation dates are in Pacific time,
-	// == UTC - 8
-	F64 date_secs_since_epoch = date.secondsSinceEpoch();
-	date_secs_since_epoch += 8.0 * 60.0 * 60.0;
-
-	// Convert seconds from epoch to seconds from now
-	F64 now_secs_since_epoch = LLDate::now().secondsSinceEpoch();
-	F64 age_secs = now_secs_since_epoch - date_secs_since_epoch;
-
-	// We don't care about sub-day times
-	const F64 SEC_PER_DAY = 24.0 * 60.0 * 60.0;
-	S32 age_days = lltrunc(age_secs / SEC_PER_DAY);
-
-	// Assume most values won't be used to fill in the format string:
-	// "[AGEYEARS][AGEMONTHS][AGEWEEKS][AGEDAYS]old"
-	LLStringUtil::format_map_t final_args;
-	final_args["[AGEYEARS]"] = "";
-	final_args["[AGEMONTHS]"] = "";
-	final_args["[AGEWEEKS]"] = "";
-	final_args["[AGEDAYS]"] = "";
-
-	// Try for age in round number of years
-	LLStringUtil::format_map_t args;
-	S32 age_years = age_days / 365;
-	age_days = age_days % 365;
-	if (age_years > 1)
-	{
-		args["[YEARS]"] = llformat("%d", age_years);
-		final_args["[AGEYEARS]"] = LLTrans::getString("AgeYears", args);
-	}
-	else if (age_years == 1)
-	{
-		final_args["[AGEYEARS]"] = LLTrans::getString("Age1Year");
-	}
-	// fall through because we show years + months for ages > 1 year
-
-	S32 age_months = age_days / 30;
-	age_days = age_days % 30;
-	if (age_months > 1)
-	{
-		args["[MONTHS]"] = llformat("%d", age_months);
-		final_args["[AGEMONTHS]"] = LLTrans::getString("AgeMonths", args);
-		// Either N years M months, or just M months,
-		// so we can exit.
-		return LLTrans::getString("YearsMonthsOld", final_args);
-	}
-	else if (age_months == 1)
-	{
-		final_args["[AGEMONTHS]"] = LLTrans::getString("Age1Month");
-		return LLTrans::getString("YearsMonthsOld", final_args);
-	}
-
-	// Now for age in weeks
-	S32 age_weeks = age_days / 7;
-	age_days = age_days % 7;
-	if (age_weeks > 1)
-	{
-		args["[WEEKS]"] = llformat("%d", age_weeks);
-		final_args["[AGEWEEKS]"] = LLTrans::getString("AgeWeeks", args);
-		return LLTrans::getString("WeeksOld", final_args);
-	}
-	else if (age_weeks == 1)
-	{
-		final_args["[AGEWEEKS]"] = LLTrans::getString("Age1Week");
-		return LLTrans::getString("WeeksOld", final_args);
-	}
-
-	// Down to days now
-	if (age_days > 1)
-	{
-		args["[DAYS]"] = llformat("%d", age_days);
-		final_args["[AGEDAYS]"] = LLTrans::getString("AgeDays", args);
-		return LLTrans::getString("DaysOld", final_args);
-	}
-	else if (age_days == 1)
-	{
-		final_args["[AGEDAYS]"] = LLTrans::getString("Age1Day");
-		return LLTrans::getString("DaysOld", final_args);
-	}
-	else
-	{
-		return LLTrans::getString("TodayOld");
-	}
-}
 
 
 //static
diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h
index 79d109f1dbb..ea80c3d4f8a 100644
--- a/indra/newview/llavatarpropertiesprocessor.h
+++ b/indra/newview/llavatarpropertiesprocessor.h
@@ -36,6 +36,7 @@
 #include "lluuid.h"
 #include "llsingleton.h"
 #include "v3dmath.h"	// LLVector3d
+#include <list>
 #include <map>
 
 /*
@@ -147,8 +148,7 @@ class LLAvatarPropertiesProcessor
 public:
 	
 	LLAvatarPropertiesProcessor();
-	virtual ~LLAvatarPropertiesProcessor()
-	{}
+	virtual ~LLAvatarPropertiesProcessor();
 
 	void addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer);
 	
@@ -174,11 +174,6 @@ class LLAvatarPropertiesProcessor
 
 	void sendPickDelete(const LLUUID& pick_id);
 
-	// Convert a date provided by the server (MM/DD/YYYY) into a localized,
-	// human-readable age (1 year, 2 months) using translation strings from 
-	// the XML file.
-	static std::string ageFromDate(const std::string& date_string);
-
 	// Returns translated, human readable string for account type, such
 	// as "Resident" or "Linden Employee".  Used for profiles, inspectors.
 	static std::string accountType(const LLAvatarData* avatar_data);
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index c2d7e0d9359..25620c2aed1 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -236,7 +236,7 @@ BOOL	LLNearbyChatToastPanel::handleMouseDown	(S32 x, S32 y, MASK mask)
 	S32 local_y = y - msg_inspector->getRect().mBottom - caption->getRect().mBottom;
 	if(msg_inspector->pointInView(local_x, local_y))
 	{
-		LLFloaterReg::showInstance("inspect_avatar", mFromID);
+		LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", mFromID));
 	}
 	else
 	{
@@ -262,7 +262,7 @@ bool	LLNearbyChatToastPanel::canAddText	()
 	LLChatMsgBox* msg_text = findChild<LLChatMsgBox>("msg_text");
 	if(!msg_text)
 		return false;
-	return msg_text->getTextLinesNum()<10;
+	return msg_text->getLineCount()<10;
 }
 
 BOOL	LLNearbyChatToastPanel::handleRightMouseDown(S32 x, S32 y, MASK mask)
diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp
index bd0c36b44a2..6eaafc90598 100644
--- a/indra/newview/llchatmsgbox.cpp
+++ b/indra/newview/llchatmsgbox.cpp
@@ -39,88 +39,60 @@
 
 static LLDefaultChildRegistry::Register<LLChatMsgBox> r("text_chat");
 
-LLChatMsgBox::Params::Params() :
-	block_spacing("block_spacing", 10)
+class ChatSeparator : public LLTextSegment
 {
-	line_spacing = 4;
-}
+public:
+	ChatSeparator(S32 start, S32 end)
+	:	LLTextSegment(start, end),
+		mEditor(NULL)
+	{}
 
-LLChatMsgBox::LLChatMsgBox(const Params& p) :
-	LLTextBox(p),
-	mBlockSpacing(p.block_spacing)
-{}
+	/*virtual*/ void linkToDocument(class LLTextBase* editor)
+	{
+		mEditor = editor;
+	}
 
-void LLChatMsgBox::addText( const LLStringExplicit& text )
-{
-	LLWString t = mText.getWString();
-	if (! t.empty())
+	/*virtual*/ void unlinkFromDocument(class LLTextBase* editor)
 	{
-		t += '\n';
+		mEditor = NULL;
 	}
-	t += getWrappedText(text);
-	LLTextBox::setText(wstring_to_utf8str(t));
-	mSeparatorOffset.push_back(getLength());
-}
 
-void LLChatMsgBox::setText(const LLStringExplicit& text)
-{
-	mSeparatorOffset.clear();
-	mText.clear();
-	addText(text);
-}
+	/*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const
+	{
+		return mEditor->getDocumentPanel()->getRect().getWidth();
+	}
 
-void LLChatMsgBox::setValue(const LLSD& value )
-{ 
-	setText(value.asString());
-}
+	/*virtual*/ F32	draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
+	{
+		gl_line_2d(draw_rect.mLeft + 5, draw_rect.getCenterY(), draw_rect.mRight - 5, draw_rect.getCenterY(), LLColor4::grey);
+		return draw_rect.getWidth();
+	}
+
+private:
+	LLTextBase* mEditor;
+};
 
-S32 LLChatMsgBox::getTextPixelHeight()
-{
-	S32 num_blocks = mSeparatorOffset.size();
-	S32 num_lines = getTextLinesNum();
-	return (S32)(num_lines * mDefaultFont->getLineHeight() + \
-				 (num_lines-1) * mLineSpacing + \
-				 (num_blocks-1) * mBlockSpacing + \
-				 2 * mLineSpacing);
-}
 
-S32 LLChatMsgBox::getTextLinesNum()
+LLChatMsgBox::Params::Params() :
+	block_spacing("block_spacing", 10)
 {
-	S32 num_lines = getLineCount();
-	if (num_lines < 1)
-	{
-		num_lines = 1;
-	}
-	
-	return num_lines;
+	line_spacing.pixels = 4;
 }
 
-void LLChatMsgBox::drawText(S32 x, S32 y, const LLWString &text, const LLColor4 &color)
-{
-	S32 start = 0;
-	S32 width = getRect().getWidth()-10;
+LLChatMsgBox::LLChatMsgBox(const Params& p) :
+	LLTextBox(p),
+	mBlockSpacing(p.block_spacing)
+{}
 
-	// iterate through each block of text that has been added
-	y -= mLineSpacing;
-	for (std::vector<S32>::iterator it = mSeparatorOffset.begin(); it != mSeparatorOffset.end() ;)
+void LLChatMsgBox::addText( const LLStringExplicit& text )
+{
+	S32 length = getLength();
+	// if there is existing text, add a separator
+	if (length > 0)
 	{
-		// display the text for this block
-		S32 num_chars = *it - start;
-		LLWString text = mDisplayText.substr(start, num_chars);
-		LLTextBox::drawText(x, y, text, color);
-		
-		// exit the loop if this is the last text block
-		start += num_chars + 1;  // skip the newline
-		if (++it == mSeparatorOffset.end())
-		{
-			break;
-		}
-
-		// output a separator line between blocks
-		S32 num_lines = std::count(text.begin(), text.end(), '\n') + 1;
-		y -= num_lines * (llfloor(mDefaultFont->getLineHeight()) + mLineSpacing);
-		S32 sep_y = y - mBlockSpacing/2 + mLineSpacing/2;
-		gl_line_2d(5, sep_y, width, sep_y, LLColor4::grey);
-		y -= mBlockSpacing;
+		// chat separator exists right before the null terminator
+		insertSegment(new ChatSeparator(length - 1, length - 1));
 	}
+	// prepend newline only if there is some existing text
+	appendText(text, length > 0);
 }
diff --git a/indra/newview/llchatmsgbox.h b/indra/newview/llchatmsgbox.h
index b81b740bdc6..df29db58c32 100644
--- a/indra/newview/llchatmsgbox.h
+++ b/indra/newview/llchatmsgbox.h
@@ -61,18 +61,10 @@ class LLChatMsgBox :
 	friend class LLUICtrlFactory;
 
 public:
-	void				setText(const LLStringExplicit &text);
 	void				addText(const LLStringExplicit &text);
 	
-	S32					getTextPixelHeight();
-	S32					getTextLinesNum();
-
-	/*virtual*/ void	setValue(const LLSD &value);
-	/*virtual*/ void	drawText(S32 x, S32 y, const LLWString &text, const LLColor4 &color);
-
 private:
 	S32					mBlockSpacing;
-	std::vector<S32>	mSeparatorOffset;
 };
 
 #endif
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 98e492cadae..23664fa6d65 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -1305,7 +1305,7 @@ void LLChicletNotificationCounterCtrl::setCounter(S32 counter)
 LLRect LLChicletNotificationCounterCtrl::getRequiredRect()
 {
 	LLRect rc;
-	S32 text_width = getFont()->getWidth(getText());
+	S32 text_width = getContentsRect().getWidth();
 
 	rc.mRight = rc.mLeft + llmax(text_width, mInitialWidth);
 	
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index 113f4c2c549..7b75c77a1e3 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -87,7 +87,7 @@ LLColorSwatchCtrl::LLColorSwatchCtrl(const Params& p)
 		tp.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ));
 	}
 	
-	tp.text(p.label);
+	tp.initial_value(p.label());
 	mCaption = LLUICtrlFactory::create<LLTextBox>(tp);
 	addChild( mCaption );
 
diff --git a/indra/newview/lldateutil.cpp b/indra/newview/lldateutil.cpp
new file mode 100644
index 00000000000..040fad3c4a2
--- /dev/null
+++ b/indra/newview/lldateutil.cpp
@@ -0,0 +1,140 @@
+/** 
+* @file lldateutil.cpp
+*
+* $LicenseInfo:firstyear=2009&license=viewergpl$
+* 
+* Copyright (c) 2009, Linden Research, Inc.
+* 
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab.  Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+* 
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+* 
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+* 
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldateutil.h"
+
+// Linden libraries
+#include "lltrans.h"
+#include "llui.h"
+
+static S32 age_days_from_date(const std::string& date_string,
+							  const LLDate& now)
+{
+	// Convert string date to malleable representation
+	S32 month, day, year;
+	S32 matched = sscanf(date_string.c_str(), "%d/%d/%d", &month, &day, &year);
+	if (matched != 3) return S32_MIN;
+
+	// Create ISO-8601 date string
+	std::string iso8601_date_string =
+		llformat("%04d-%02d-%02dT00:00:00Z", year, month, day);
+	LLDate date(iso8601_date_string);
+
+	// Correct for the fact that account creation dates are in Pacific time,
+	// == UTC - 8
+	F64 date_secs_since_epoch = date.secondsSinceEpoch();
+	date_secs_since_epoch += 8.0 * 60.0 * 60.0;
+
+	// Convert seconds from epoch to seconds from now
+	F64 now_secs_since_epoch = now.secondsSinceEpoch();
+	F64 age_secs = now_secs_since_epoch - date_secs_since_epoch;
+
+	// We don't care about sub-day times
+	const F64 SEC_PER_DAY = 24.0 * 60.0 * 60.0;
+	S32 age_days = lltrunc(age_secs / SEC_PER_DAY);
+
+	return age_days;
+}
+
+std::string LLDateUtil::ageFromDate(const std::string& date_string,
+									const LLDate& now)
+{
+	S32 age_days = age_days_from_date(date_string, now);
+	if (age_days == S32_MIN) return "???";
+
+	// Noun pluralization depends on language
+	std::string lang = LLUI::getLanguage();
+
+	// Try for age in round number of years
+	LLStringUtil::format_map_t args;
+	S32 age_years = age_days / 365;
+	age_days = age_days % 365;
+	// *NOTE: This is wrong.  Not all months have 30 days, but we don't have a library
+	// for relative date arithmetic. :-(  JC
+	S32 age_months = age_days / 30;
+	age_days = age_days % 30;
+
+	if (age_months > 0 || age_years > 0)
+	{
+		args["[AGEYEARS]"] =
+			LLTrans::getCountString(lang, "AgeYears", age_years);
+		args["[AGEMONTHS]"] =
+			LLTrans::getCountString(lang, "AgeMonths", age_months);
+
+		// We want to display times like:
+		// 2 year 2 months
+		// 2 years (implicitly 0 months)
+		// 11 months
+		if (age_years > 0)
+		{
+			if (age_months > 0)
+			{
+				return LLTrans::getString("YearsMonthsOld", args);
+			}
+			else
+			{
+				return LLTrans::getString("YearsOld", args);
+			}
+		}
+		else // age_years == 0
+		{
+			return LLTrans::getString("MonthsOld", args);
+		}
+	}
+	// you're 0 months old, display in weeks or days
+
+	// Now for age in weeks
+	S32 age_weeks = age_days / 7;
+	age_days = age_days % 7;
+	if (age_weeks > 0)
+	{
+		args["[AGEWEEKS]"] = 
+			LLTrans::getCountString(lang, "AgeWeeks", age_weeks);
+		return LLTrans::getString("WeeksOld", args);
+	}
+
+	// Down to days now
+	if (age_days > 0)
+	{
+		args["[AGEDAYS]"] =
+			LLTrans::getCountString(lang, "AgeDays", age_days);
+		return LLTrans::getString("DaysOld", args);
+	}
+
+	return LLTrans::getString("TodayOld");
+}
+
+std::string LLDateUtil::ageFromDate(const std::string& date_string)
+{
+	return ageFromDate(date_string, LLDate::now());
+}
diff --git a/indra/newview/lldateutil.h b/indra/newview/lldateutil.h
new file mode 100644
index 00000000000..041be07f120
--- /dev/null
+++ b/indra/newview/lldateutil.h
@@ -0,0 +1,49 @@
+/** 
+* @file lldateutil.h
+*
+* $LicenseInfo:firstyear=2009&license=viewergpl$
+* 
+* Copyright (c) 2009, Linden Research, Inc.
+* 
+* Second Life Viewer Source Code
+* The source code in this file ("Source Code") is provided by Linden Lab
+* to you under the terms of the GNU General Public License, version 2.0
+* ("GPL"), unless you have obtained a separate licensing agreement
+* ("Other License"), formally executed by you and Linden Lab.  Terms of
+* the GPL can be found in doc/GPL-license.txt in this distribution, or
+* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+* 
+* There are special exceptions to the terms and conditions of the GPL as
+* it is applied to this Source Code. View the full text of the exception
+* in the file doc/FLOSS-exception.txt in this software distribution, or
+* online at
+* http://secondlifegrid.net/programs/open_source/licensing/flossexception
+* 
+* By copying, modifying or distributing this software, you acknowledge
+* that you have read and understood your obligations described above,
+* and agree to abide by those obligations.
+* 
+* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+* COMPLETENESS OR PERFORMANCE.
+* $/LicenseInfo$
+*/
+
+#ifndef LLDATEUTIL_H
+#define LLDATEUTIL_H
+
+class LLDate;
+
+namespace LLDateUtil
+{
+	// Convert a date provided by the server (MM/DD/YYYY) into a localized,
+	// human-readable age (1 year, 2 months) using translation strings.
+	// Pass LLDate::now() for now.
+	// Used for avatar inspectors and profiles.
+	std::string ageFromDate(const std::string& date_string, const LLDate& now);
+
+	// Calls the above with LLDate::now()
+	std::string ageFromDate(const std::string& date_string);
+}
+
+#endif
diff --git a/indra/newview/lldebugmessagebox.cpp b/indra/newview/lldebugmessagebox.cpp
index 786473eb9bd..29e375c9faf 100644
--- a/indra/newview/lldebugmessagebox.cpp
+++ b/indra/newview/lldebugmessagebox.cpp
@@ -131,7 +131,7 @@ LLDebugVarMessageBox::LLDebugVarMessageBox(const std::string& title, EDebugVarTy
 
 	LLTextBox::Params params;
 	params.name("value");
-	params.text(params.name);
+	params.initial_value(params.name());
 	params.rect(LLRect(20,20,190,0));
 	mText = LLUICtrlFactory::create<LLTextBox> (params);
 	addChild(mText);
diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp
index 131f9ceaf01..f8f5db9d7e2 100644
--- a/indra/newview/llexpandabletextbox.cpp
+++ b/indra/newview/llexpandabletextbox.cpp
@@ -78,6 +78,9 @@ void LLExpandableTextBox::LLTextBoxEx::draw()
 	LLUICtrl::draw();
 }
 
+/* LLTextBox has been rewritten, the variables referenced in this code
+no longer exist.
+
 void LLExpandableTextBox::LLTextBoxEx::drawText( S32 x, S32 y, const LLWString &text, const LLColor4& color )
 {
 	// *NOTE:dzaporozhan:
@@ -141,6 +144,7 @@ void LLExpandableTextBox::LLTextBoxEx::drawText( S32 x, S32 y, const LLWString &
 		}
 	}
 }
+*/
 
 void LLExpandableTextBox::LLTextBoxEx::showExpandText(S32 y)
 {
@@ -161,8 +165,14 @@ S32 LLExpandableTextBox::LLTextBoxEx::getCropTextWidth()
 	return mExpandTextBox->getRect().mLeft - getHPad() * 2; 
 }
 
+/*
+// *NOTE:James:
+// LLTextBox::drawText() has been completely rewritten, as it now handles
+// arbitrarily styled segments of text.  This needs to be rebuilt.
+
 void LLExpandableTextBox::LLTextBoxEx::drawTextSegments(S32 init_x, S32 init_y, const LLWString &text)
 {
+
 	// *NOTE:dzaporozhan:
 	// Copy/paste from LLTextBox::drawTextSegments in order to modify last 
 	// line width if needed and who "More" link
@@ -270,6 +280,7 @@ void LLExpandableTextBox::LLTextBoxEx::drawTextSegments(S32 init_x, S32 init_y,
 		}
 	}
 }
+*/
 
 S32 LLExpandableTextBox::LLTextBoxEx::getVerticalTextDelta()
 {
@@ -422,8 +433,11 @@ void LLExpandableTextBox::expandTextBox()
 
 		// disable horizontal scrollbar
 		text_box_rect.mRight -= scrollbar_size;
+
 		// text box size has changed - redo text wrap
-		mTextBox->setWrappedText(mText, text_box_rect.getWidth());
+		// Should be handled automatically in reshape() below. JC
+		//mTextBox->setWrappedText(mText, text_box_rect.getWidth());
+
 		// recalculate text delta since text wrap changed text height
 		text_delta = mTextBox->getVerticalTextDelta() + mTextBox->getVPad() * 2;
 	}
@@ -460,7 +474,8 @@ void LLExpandableTextBox::collapseTextBox()
 
 	updateTextBoxRect();
 
-	mTextBox->setWrappedText(mText);
+	// Should be handled automatically in reshape above. JC
+	//mTextBox->setWrappedText(mText);
 	if(gFocusMgr.getTopCtrl() == this)
 	{
 		gFocusMgr.setTopCtrl(NULL);
diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h
index 0a5a4c8b758..0b9c3f7258c 100644
--- a/indra/newview/llexpandabletextbox.h
+++ b/indra/newview/llexpandabletextbox.h
@@ -64,17 +64,17 @@ class LLExpandableTextBox : public LLUICtrl
 		 */
 		/*virtual*/ void draw();
 
-		/**
-		 * Draws simple text(no urls) line by line, will show or hide "More" link
-		 * if needed.
-		 */
-		/*virtual*/ void drawText( S32 x, S32 y, const LLWString &text, const LLColor4& color );
-
-		/**
-		 * Draws segmented text(with urls) line by line. Will show or hide "More" link 
-		 * if needed
-		 */
-		void drawTextSegments(S32 x, S32 y, const LLWString &text);
+//		/**
+//		 * Draws simple text(no urls) line by line, will show or hide "More" link
+//		 * if needed.
+//		 */
+//		/*virtual*/ void drawText( S32 x, S32 y, const LLWString &text, const LLColor4& color );
+//
+//		/**
+//		 * Draws segmented text(with urls) line by line. Will show or hide "More" link 
+//		 * if needed
+//		 */
+//		void drawTextSegments(S32 x, S32 y, const LLWString &text);
 
 		/**
 		 * Returns difference between text box height and text height.
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 8af3a8b539d..0bd4389b50b 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -244,7 +244,7 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
 }
 
 
-BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y))
 	{
@@ -254,7 +254,7 @@ BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& stic
 			LLRect screen_rect;
 			localRectToScreen(mToolTipRect, &screen_rect);
 
-			LLToolTipMgr::instance().show(LLToolTipParams()
+			LLToolTipMgr::instance().show(LLToolTip::Params()
 				.message(mHoverTimer->getToolTip(LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex))
 				.sticky_rect(screen_rect));
 
diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h
index 97e4e94460c..2bb023ab143 100644
--- a/indra/newview/llfasttimerview.h
+++ b/indra/newview/llfasttimerview.h
@@ -57,7 +57,7 @@ class LLFastTimerView : public LLFloater
 	virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
 	virtual BOOL handleHover(S32 x, S32 y, MASK mask);
-	virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen);
+	virtual BOOL handleToolTip(S32 x, S32 y, MASK mask);
 	virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
 	virtual void draw();
 
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index ea947a55656..48fcb6b6de0 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -123,7 +123,7 @@ class LLFavoriteLandmarkButton : public LLButton
 {
 public:
 
-	BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect)
+	BOOL handleToolTip(S32 x, S32 y, MASK mask)
 	{
 		LLToolTipMgr::instance().show(mUrlGetter.getSLURL());
 		return TRUE;
@@ -201,7 +201,7 @@ class LLFavoritesToggleableMenu : public LLToggleableMenu
 class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL
 {
 public:
-	BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect)
+	BOOL handleToolTip(S32 x, S32 y, MASK mask)
 	{
 		LLToolTipMgr::instance().show(mUrlGetter.getSLURL());
 		return TRUE;
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index e28d223a101..a4c38d03aa5 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -115,9 +115,6 @@ BOOL LLFloaterAbout::postBuild()
 	getChild<LLUICtrl>("copy_btn")->setCommitCallback(
 		boost::bind(&LLFloaterAbout::onClickCopyToClipboard, this));
 
-	// make sure that we handle hyperlinks in the About text
-	support_widget->setParseHTML(TRUE);
-
 	// Version string
 	std::string version = LLTrans::getString("APP_NAME")
 		+ llformat(" %d.%d.%d (%d) %s %s (%s)\n",
@@ -241,7 +238,11 @@ BOOL LLFloaterAbout::postBuild()
 		support.append(getString ("PacketsLost", args) + "\n");
 	}
 
-	support_widget->appendColoredText(support, FALSE, FALSE, LLUIColorTable::instance().getColor("TextFgReadOnlyColor"));
+	support_widget->appendText(support, 
+								FALSE, 
+								LLStyle::Params()
+									.color(LLUIColorTable::instance().getColor("TextFgReadOnlyColor")));
+	support_widget->blockUndo();
 
 	// Fix views
 	support_widget->setCursorPos(0);
diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp
index a7aaf71ef69..473d5ce827e 100644
--- a/indra/newview/llfloaterbuy.cpp
+++ b/indra/newview/llfloaterbuy.cpp
@@ -73,6 +73,8 @@ BOOL LLFloaterBuy::postBuild()
 	// This also avoids problems where the user resizes the application window
 	// mid-session and the saved rect is off-center.
 	center();
+
+	mCloseSignal.connect(boost::bind(&LLFloaterBuy::onClose, this));
 	
 	return TRUE;
 }
@@ -307,3 +309,8 @@ void LLFloaterBuy::onClickCancel()
 {
 	closeFloater();
 }
+
+void LLFloaterBuy::onClose()
+{
+	mObjectSelection.clear();
+}
diff --git a/indra/newview/llfloaterbuy.h b/indra/newview/llfloaterbuy.h
index ee543032671..2ec66136b21 100644
--- a/indra/newview/llfloaterbuy.h
+++ b/indra/newview/llfloaterbuy.h
@@ -70,6 +70,7 @@ class LLFloaterBuy
 
 	void onClickBuy();
 	void onClickCancel();
+	void onClose();
 
 private:
 	LLSafeHandle<LLObjectSelection>	mObjectSelection;
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp
index 7075719299c..2c2a5107f53 100644
--- a/indra/newview/llfloaterbuyland.cpp
+++ b/indra/newview/llfloaterbuyland.cpp
@@ -50,6 +50,7 @@
 #include "lllineeditor.h"
 #include "llnotify.h"
 #include "llparcel.h"
+#include "llslurl.h"
 #include "llstatusbar.h"
 #include "lltextbox.h"
 #include "lltexturectrl.h"
@@ -71,7 +72,7 @@
 const F32 GROUP_LAND_BONUS_FACTOR = 1.1f;
 const F64 CURRENCY_ESTIMATE_FREQUENCY = 0.5;
 	// how long of a pause in typing a currency buy amount before an
-	// esimate is fetched from the server
+	// estimate is fetched from the server
 
 class LLFloaterBuyLandUI
 :	public LLFloater
@@ -177,6 +178,11 @@ class LLFloaterBuyLandUI
 	void sendBuyLand();
 
 	void updateNames();
+	// Name cache callback
+	void updateGroupName(const LLUUID& id,
+						 const std::string& first_name,
+						 const std::string& last_name,
+						 BOOL is_group);
 	
 	void refreshUI();
 	
@@ -201,16 +207,6 @@ class LLFloaterBuyLandUI
 	
 };
 
-static void cacheNameUpdateRefreshesBuyLand(const LLUUID&,
-	const std::string&, const std::string&, BOOL)
-{
-	LLFloaterBuyLandUI* ui = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
-	if (ui)
-	{
-		ui->updateNames();
-	}
-}
-
 // static
 void LLFloaterBuyLand::buyLand(
 	LLViewerRegion* region, LLParcelSelectionHandle parcel, bool is_for_group)
@@ -296,13 +292,6 @@ LLFloaterBuyLandUI::LLFloaterBuyLandUI(const LLSD& key)
 	mChildren(*this), mCurrency(*this), mTransaction(0),
 	mParcelBuyInfo(0)
 {
-	static bool observingCacheName = false;
-	if (!observingCacheName)
-	{
-		gCacheName->addObserver(&cacheNameUpdateRefreshesBuyLand);
-		observingCacheName = true;
-	}
-	
 	LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver);
 	
 // 	LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_buy_land.xml");
@@ -788,14 +777,30 @@ void LLFloaterBuyLandUI::updateNames()
 	}
 	else if (parcelp->getIsGroupOwned())
 	{
-		gCacheName->getGroupName(parcelp->getGroupID(), mParcelSellerName);
+		gCacheName->get(parcelp->getGroupID(), TRUE,
+			boost::bind(&LLFloaterBuyLandUI::updateGroupName, this,
+				_1, _2, _3, _4));
 	}
 	else
 	{
-		gCacheName->getFullName(parcelp->getOwnerID(), mParcelSellerName);
+		mParcelSellerName =
+			LLSLURL::buildCommand("agent", parcelp->getOwnerID(), "inspect");
 	}
 }
 
+void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id,
+						 const std::string& first_name,
+						 const std::string& last_name,
+						 BOOL is_group)
+{
+	LLParcel* parcelp = mParcel->getParcel();
+	if (parcelp
+		&& parcelp->getGroupID() == id)
+	{
+		// request is current
+		mParcelSellerName = first_name;
+	}
+}
 
 void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params)
 {
@@ -1036,9 +1041,7 @@ void LLFloaterBuyLandUI::refreshUI()
 		if (message)
 		{
 			message->setVisible(true);
-			message->setWrappedText(
-				!mCanBuy ? mCannotBuyReason : "(waiting for data)"
-				);
+			message->setValue(LLSD(!mCanBuy ? mCannotBuyReason : "(waiting for data)"));
 		}
 
 		childSetVisible("error_web", 
@@ -1148,7 +1151,7 @@ void LLFloaterBuyLandUI::refreshUI()
 			}
 		}
 
-		childSetWrappedText("land_use_reason", message);
+		childSetValue("land_use_reason", message);
 
 		childShow("step_2");
 		childShow("land_use_action");
diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp
index ca43f41d05b..6d2e9593520 100644
--- a/indra/newview/llfloaterchat.cpp
+++ b/indra/newview/llfloaterchat.cpp
@@ -56,6 +56,7 @@
 #include "llchatbar.h"
 #include "llrecentpeople.h"
 #include "llpanelblockedlist.h"
+#include "llslurl.h"
 #include "llstatusbar.h"
 #include "llviewertexteditor.h"
 #include "llviewergesture.h"			// for triggering gestures
@@ -162,7 +163,7 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4&
 	if (chat.mSourceType == CHAT_SOURCE_AGENT &&
 		chat.mFromID != LLUUID::null)
 	{
-		chat.mURL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str());
+		chat.mURL = LLSLURL::buildCommand("agent", chat.mFromID, "inspect");
 	}
 
 	// If the chat line has an associated url, link it up to the name.
@@ -171,10 +172,12 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4&
 	{
 		std::string start_line = line.substr(0, chat.mFromName.length() + 1);
 		line = line.substr(chat.mFromName.length() + 1);
-		edit->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,chat.mURL));
+		edit->appendText(start_line, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,chat.mURL));
+		edit->blockUndo();
 		prepend_newline = false;
 	}
-	edit->appendColoredText(line, false, prepend_newline, color);
+	edit->appendText(line, prepend_newline, LLStyle::Params().color(color));
+	edit->blockUndo();
 }
 
 void log_chat_text(const LLChat& chat)
@@ -216,12 +219,6 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file)
 	LLViewerTextEditor*	history_editor = chat_floater->getChild<LLViewerTextEditor>("Chat History Editor");
 	LLViewerTextEditor*	history_editor_with_mute = chat_floater->getChild<LLViewerTextEditor>("Chat History Editor with mute");
 
-	history_editor->setParseHTML(TRUE);
-	history_editor_with_mute->setParseHTML(TRUE);
-	
-	history_editor->setParseHighlights(TRUE);
-	history_editor_with_mute->setParseHighlights(TRUE);
-	
 	if (!chat.mMuted)
 	{
 		add_timestamped_line(history_editor, chat, color);
diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp
index 0c77d88efb9..2c66ab502d9 100644
--- a/indra/newview/llfloaterfriends.cpp
+++ b/indra/newview/llfloaterfriends.cpp
@@ -237,7 +237,7 @@ BOOL LLPanelFriends::addFriend(const LLUUID& agent_id)
 	LLSD& friend_column = element["columns"][LIST_FRIEND_NAME];
 	friend_column["column"] = "friend_name";
 	friend_column["value"] = fullname;
-	friend_column["font"] = "SANSSERIF";
+	friend_column["font"]["name"] = "SANSSERIF";
 	friend_column["font"]["style"] = "NORMAL";	
 
 	LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS];
@@ -614,7 +614,7 @@ void LLPanelFriends::onClickPay(void* user_data)
 	std::vector<LLUUID> ids = panelp->getSelectedIDs();
 	if(ids.size() == 1)
 	{	
-		handle_pay_by_id(ids[0]);
+		LLAvatarActions::pay(ids[0]);
 	}
 }
 
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index 431bc09d86b..e0fe87f9aed 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -205,7 +205,7 @@ void LLFloaterGesture::buildGestureList()
 
 			element["columns"][0]["column"] = "trigger";
 			element["columns"][0]["value"] = gesture->mTrigger;
-			element["columns"][0]["font"] = "SANSSERIF";
+			element["columns"][0]["font"]["name"] = "SANSSERIF";
 			element["columns"][0]["font"]["style"] = font_style;
 
 			std::string key_string = LLKeyboard::stringFromKey(gesture->mKey);
@@ -232,13 +232,13 @@ void LLFloaterGesture::buildGestureList()
 			}
 			element["columns"][1]["column"] = "shortcut";
 			element["columns"][1]["value"] = buffer;
-			element["columns"][1]["font"] = "SANSSERIF";
+			element["columns"][1]["font"]["name"] = "SANSSERIF";
 			element["columns"][1]["font"]["style"] = font_style;
 
 			// hidden column for sorting
 			element["columns"][2]["column"] = "key";
 			element["columns"][2]["value"] = key_string;
-			element["columns"][2]["font"] = "SANSSERIF";
+			element["columns"][2]["font"]["name"] = "SANSSERIF";
 			element["columns"][2]["font"]["style"] = font_style;
 
 			// Only add "playing" if we've got the name, less confusing. JC
@@ -248,26 +248,26 @@ void LLFloaterGesture::buildGestureList()
 			}
 			element["columns"][3]["column"] = "name";
 			element["columns"][3]["value"] = item_name;
-			element["columns"][3]["font"] = "SANSSERIF";
+			element["columns"][3]["font"]["name"] = "SANSSERIF";
 			element["columns"][3]["font"]["style"] = font_style;
 		}
 		else
 		{
 			element["columns"][0]["column"] = "trigger";
 			element["columns"][0]["value"] = "";
-			element["columns"][0]["font"] = "SANSSERIF";
+			element["columns"][0]["font"]["name"] = "SANSSERIF";
 			element["columns"][0]["font"]["style"] = font_style;
 			element["columns"][0]["column"] = "trigger";
 			element["columns"][0]["value"] = "---";
-			element["columns"][0]["font"] = "SANSSERIF";
+			element["columns"][0]["font"]["name"] = "SANSSERIF";
 			element["columns"][0]["font"]["style"] = font_style;
 			element["columns"][2]["column"] = "key";
 			element["columns"][2]["value"] = "~~~";
-			element["columns"][2]["font"] = "SANSSERIF";
+			element["columns"][2]["font"]["name"] = "SANSSERIF";
 			element["columns"][2]["font"]["style"] = font_style;
 			element["columns"][3]["column"] = "name";
 			element["columns"][3]["value"] = item_name;
-			element["columns"][3]["font"] = "SANSSERIF";
+			element["columns"][3]["font"]["name"] = "SANSSERIF";
 			element["columns"][3]["font"]["style"] = font_style;
 		}
 		list->addElement(element, ADD_BOTTOM);
diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp
index b1f40d9d1d9..3648898f280 100644
--- a/indra/newview/llfloatergroups.cpp
+++ b/indra/newview/llfloatergroups.cpp
@@ -372,7 +372,7 @@ void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 pow
 			element["id"] = id;
 			element["columns"][0]["column"] = "name";
 			element["columns"][0]["value"] = group_datap->mName;
-			element["columns"][0]["font"] = "SANSSERIF";
+			element["columns"][0]["font"]["name"] = "SANSSERIF";
 			element["columns"][0]["font"]["style"] = style;
 
 			group_list->addElement(element, ADD_SORTED);
@@ -390,7 +390,7 @@ void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 pow
 		element["id"] = LLUUID::null;
 		element["columns"][0]["column"] = "name";
 		element["columns"][0]["value"] = LLTrans::getString("GroupsNone");
-		element["columns"][0]["font"] = "SANSSERIF";
+		element["columns"][0]["font"]["name"] = "SANSSERIF";
 		element["columns"][0]["font"]["style"] = style;
 
 		group_list->addElement(element, ADD_TOP);
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 3fe7d8d9da2..a378a511b51 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -62,6 +62,7 @@
 #include "llscrolllistitem.h"
 #include "llscrolllistcell.h"
 #include "llselectmgr.h"
+#include "llslurl.h"
 #include "llspinctrl.h"
 #include "lltabcontainer.h"
 #include "lltextbox.h"
@@ -754,7 +755,7 @@ void LLPanelLandGeneral::refreshNames()
 	else
 	{
 		// Figure out the owner's name
-		gCacheName->getFullName(parcel->getOwnerID(), owner);
+		owner = LLSLURL::buildCommand("agent", parcel->getOwnerID(), "inspect");
 	}
 
 	if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus())
@@ -763,18 +764,11 @@ void LLPanelLandGeneral::refreshNames()
 	}
 	mTextOwner->setText(owner);
 
-	std::string group;
-	if(!parcel->getGroupID().isNull())
-	{
-		gCacheName->getGroupName(parcel->getGroupID(), group);
-	}
-	mTextGroup->setText(group);
-
 	const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();
 	if(auth_buyer_id.notNull())
 	{
 		std::string name;
-		gCacheName->getFullName(auth_buyer_id, name);
+		name = LLSLURL::buildCommand("agent", auth_buyer_id, "inspect");
 		mSaleInfoForSale2->setTextArg("[BUYER]", name);
 	}
 	else
@@ -787,7 +781,20 @@ void LLPanelLandGeneral::refreshNames()
 // virtual
 void LLPanelLandGeneral::draw()
 {
-	refreshNames();
+	LLParcel *parcel = mParcel->getParcel();
+	if (parcel)
+	{
+		std::string group;
+		if (!parcel->getGroupID().isNull())
+		{
+			// *TODO: Change to "inspect" when we have group inspectors and
+			// move into refreshNames() above
+			// group = LLSLURL::buildCommand("group", parcel->getGroupID(), "inspect");
+			gCacheName->getGroupName(parcel->getGroupID(), group);
+		}
+		mTextGroup->setText(group);
+	}
+
 	LLPanel::draw();
 }
 
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 10276ba36da..0330a8c6921 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -37,7 +37,6 @@
 #include <algorithm>
 #include <functional>
 
-#include "llcachename.h"
 #include "lldir.h"
 #include "lldispatcher.h"
 #include "llglheaders.h"
@@ -67,6 +66,7 @@
 #include "llnamelistctrl.h"
 #include "llscrolllistitem.h"
 #include "llsliderctrl.h"
+#include "llslurl.h"
 #include "llspinctrl.h"
 #include "lltabcontainer.h"
 #include "lltextbox.h"
@@ -2560,30 +2560,6 @@ void LLPanelEstateInfo::setAccessAllowedEnabled(bool enable_agent,
 	}
 }
 
-// static
-void LLPanelEstateInfo::callbackCacheName(
-	const LLUUID& id,
-	const std::string& first,
-	const std::string& last,
-	BOOL is_group)
-{
-	LLPanelEstateInfo* self = LLFloaterRegionInfo::getPanelEstate();
-	if (!self) return;
-
-	std::string name;
-	
-	if (id.isNull())
-	{
-		name = "(none)";
-	}
-	else
-	{
-		name = first + " " + last;
-	}
-
-	self->setOwnerName(name);
-}
-
 void LLPanelEstateInfo::clearAccessLists() 
 {
 	LLNameListCtrl* name_list = getChild<LLNameListCtrl>("allowed_avatar_name_list");
@@ -2960,7 +2936,7 @@ BOOL LLPanelEstateCovenant::sendUpdate()
 	return TRUE;
 }
 
-const std::string& LLPanelEstateCovenant::getEstateName() const
+std::string LLPanelEstateCovenant::getEstateName() const
 {
 	return mEstateNameText->getText();
 }
@@ -3011,7 +2987,7 @@ void LLPanelEstateCovenant::updateEstateOwnerName(const std::string& name)
 	}
 }
 
-const std::string& LLPanelEstateCovenant::getOwnerName() const
+std::string LLPanelEstateCovenant::getOwnerName() const
 {
 	return mEstateOwnerText->getText();
 }
@@ -3069,8 +3045,9 @@ bool LLDispatchEstateUpdateInfo::operator()(
 	LLUUID owner_id(strings[1]);
 	regionp->setOwner(owner_id);
 	// Update estate owner name in UI
-	const BOOL is_group = FALSE;
-	gCacheName->get(owner_id, is_group, &LLPanelEstateInfo::callbackCacheName);
+	std::string owner_name =
+		LLSLURL::buildCommand("agent", owner_id, "inspect");
+	panel->setOwnerName(owner_name);
 
 	U32 estate_id = strtoul(strings[2].c_str(), NULL, 10);
 	panel->setEstateID(estate_id);
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index be4becf7e77..68ed4e0c897 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -338,14 +338,6 @@ class LLPanelEstateInfo : public LLPanelRegionInfo
 	// are ignored, so must disable UI.
 	void setAccessAllowedEnabled(bool enable_agent, bool enable_group, bool enable_ban);
 
-	// this must have the same function signature as
-	// llmessage/llcachename.h:LLCacheNameCallback
-	static void callbackCacheName(
-		const LLUUID& id,
-		const std::string& first,
-		const std::string& last,
-		BOOL is_group);
-
 protected:
 	virtual BOOL sendUpdate();
 	// confirmation dialog callback
@@ -400,9 +392,9 @@ class LLPanelEstateCovenant : public LLPanelRegionInfo
 
 	const LLUUID& getCovenantID() const { return mCovenantID; }
 	void setCovenantID(const LLUUID& id) { mCovenantID = id; }
-	const std::string& getEstateName() const;
+	std::string getEstateName() const;
 	void setEstateName(const std::string& name);
-	const std::string& getOwnerName() const;
+	std::string getOwnerName() const;
 	void setOwnerName(const std::string& name);
 	void setCovenantTextEditor(const std::string& text);
 
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 3dcdc2f56ef..1ec869da738 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -32,14 +32,13 @@
 
 #include "llviewerprecompiledheaders.h"
 
-#include <sstream>
-
 // self include
 #include "llfloaterreporter.h"
 
+#include <sstream>
+
 // linden library includes
 #include "llassetstorage.h"
-#include "llcachename.h"
 #include "llfontgl.h"
 #include "llgl.h"			// for renderer
 #include "llinventory.h"
@@ -48,18 +47,14 @@
 #include "llversionviewer.h"
 #include "message.h"
 #include "v3math.h"
-#include "lltexteditor.h"
 
 // viewer project includes
 #include "llagent.h"
 #include "llbutton.h"
-#include "llcheckboxctrl.h"
 #include "llfloaterreg.h"
-#include "lllineeditor.h"
 #include "lltexturectrl.h"
 #include "llscrolllistctrl.h"
 #include "llimview.h"
-#include "lltextbox.h"
 #include "lldispatcher.h"
 #include "llviewerobject.h"
 #include "llviewerregion.h"
@@ -72,6 +67,7 @@
 #include "lltoolobjpicker.h"
 #include "lltoolmgr.h"
 #include "llresourcedata.h"		// for LLResourceData
+#include "llslurl.h"
 #include "llviewerwindow.h"
 #include "llviewertexturelist.h"
 #include "llworldmap.h"
@@ -103,6 +99,7 @@ LLFloaterReporter::LLFloaterReporter(const LLSD& key)
 	mObjectID(),
 	mScreenID(),
 	mAbuserID(),
+	mOwnerName(),
 	mDeselectOnClose( FALSE ),
 	mPicking( FALSE), 
 	mPosition(),
@@ -158,6 +155,7 @@ BOOL LLFloaterReporter::postBuild()
 	// Default text to be blank
 	childSetText("object_name", LLStringUtil::null);
 	childSetText("owner_name", LLStringUtil::null);
+	mOwnerName = LLStringUtil::null;
 
 	childSetFocus("summary_edit");
 
@@ -174,8 +172,8 @@ BOOL LLFloaterReporter::postBuild()
 	
 	
 	// abuser name is selected from a list
-	LLLineEditor* le = getChild<LLLineEditor>("abuser_name_edit");
-	le->setEnabled( FALSE );
+	LLUICtrl* le = getChild<LLUICtrl>("abuser_name_edit");
+	le->setEnabled( false );
 
 	setPosBox((LLVector3d)mPosition.getValue());
 	LLButton* pick_btn = getChild<LLButton>("pick_btn");
@@ -299,9 +297,12 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
 					object_owner.append("Unknown");
 				}
 				childSetText("object_name", object_owner);
-				childSetText("owner_name", object_owner);
+				std::string owner_link =
+					LLSLURL::buildCommand("agent", mObjectID, "inspect");
+				childSetText("owner_name", owner_link);
 				childSetText("abuser_name_edit", object_owner);
 				mAbuserID = object_id;
+				mOwnerName = object_owner;
 			}
 			else
 			{
@@ -445,6 +446,7 @@ void LLFloaterReporter::onClickObjPicker(void *userdata)
 	self->mPicking = TRUE;
 	self->childSetText("object_name", LLStringUtil::null);
 	self->childSetText("owner_name", LLStringUtil::null);
+	self->mOwnerName = LLStringUtil::null;
 	LLButton* pick_btn = self->getChild<LLButton>("pick_btn");
 	if (pick_btn) pick_btn->setToggleState(TRUE);
 }
@@ -505,9 +507,12 @@ void LLFloaterReporter::showFromObject(const LLUUID& object_id)
 void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id)
 {
 	childSetText("object_name", object_name);
-	childSetText("owner_name", owner_name);
+	std::string owner_link =
+		LLSLURL::buildCommand("agent", owner_id, "inspect");
+	childSetText("owner_name", owner_link);
 	childSetText("abuser_name_edit", owner_name);
 	mAbuserID = owner_id;
+	mOwnerName = owner_name;
 }
 
 
@@ -608,11 +613,10 @@ LLSD LLFloaterReporter::gatherReport()
 		<< LL_VIEWER_BUILD << std::endl << std::endl;
 
 	std::string object_name = childGetText("object_name");
-	std::string owner_name = childGetText("owner_name");
-	if (!object_name.empty() && !owner_name.empty())
+	if (!object_name.empty() && !mOwnerName.empty())
 	{
 		details << "Object: " << object_name << "\n";
-		details << "Owner: " << owner_name << "\n";
+		details << "Owner: " << mOwnerName << "\n";
 	}
 
 
diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h
index 7e8f05e3fc6..917f5136417 100644
--- a/indra/newview/llfloaterreporter.h
+++ b/indra/newview/llfloaterreporter.h
@@ -128,6 +128,8 @@ class LLFloaterReporter
 	LLUUID 			mObjectID;
 	LLUUID			mScreenID;
 	LLUUID			mAbuserID;
+	// Store the real name, not the link, for upstream reporting
+	std::string		mOwnerName;
 	BOOL			mDeselectOnClose;
 	BOOL 			mPicking;
 	LLVector3		mPosition;
diff --git a/indra/newview/llfloaterscriptdebug.cpp b/indra/newview/llfloaterscriptdebug.cpp
index 328fb6450e6..3bf1848efb7 100644
--- a/indra/newview/llfloaterscriptdebug.cpp
+++ b/indra/newview/llfloaterscriptdebug.cpp
@@ -167,6 +167,7 @@ void LLFloaterScriptDebugOutput::addLine(const std::string &utf8mesg, const std:
 		setShortTitle(user_name);
 	}
 
-	mHistoryEditor->appendColoredText(utf8mesg, false, true, color);
+	mHistoryEditor->appendText(utf8mesg, true, LLStyle::Params().color(color));
+	mHistoryEditor->blockUndo();
 }
 
diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp
index fe98c84301c..9e203c42694 100644
--- a/indra/newview/llfloatersellland.cpp
+++ b/indra/newview/llfloatersellland.cpp
@@ -131,7 +131,6 @@ LLFloaterSellLandUI::LLFloaterSellLandUI(const LLSD& key)
 	mRegion(0)
 {
 	LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver);
-// 	LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_sell_land.xml");
 	mCloseSignal.connect(boost::bind(&LLFloaterSellLandUI::onClose, this));
 }
 
@@ -153,7 +152,7 @@ void LLFloaterSellLandUI::SelectionObserver::changed()
 	{
 		mFloater->closeFloater();
 	}
-	else
+	else if (mFloater->getVisible()) // only update selection if sell land ui in use
 	{
 		mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(),
 							LLViewerParcelMgr::getInstance()->getParcelSelection());
@@ -176,7 +175,7 @@ BOOL LLFloaterSellLandUI::postBuild()
 
 bool LLFloaterSellLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel)
 {
-	if (!parcel->getParcel()) // || !can_agent_modify_parcel(parcel)) // can_agent_modify_parcel was deprecated by GROUPS
+	if (!parcel->getParcel())
 	{
 		return false;
 	}
diff --git a/indra/newview/llfloatertestinspectors.cpp b/indra/newview/llfloatertestinspectors.cpp
index c56586cb954..8af011c17a9 100644
--- a/indra/newview/llfloatertestinspectors.cpp
+++ b/indra/newview/llfloatertestinspectors.cpp
@@ -44,6 +44,8 @@ LLFloaterTestInspectors::LLFloaterTestInspectors(const LLSD& seed)
 {
 	mCommitCallbackRegistrar.add("ShowAvatarInspector",
 		boost::bind(&LLFloaterTestInspectors::showAvatarInspector, this, _1, _2));
+	mCommitCallbackRegistrar.add("ShowObjectInspector",
+		boost::bind(&LLFloaterTestInspectors::showObjectInspector, this, _1, _2));
 }
 
 LLFloaterTestInspectors::~LLFloaterTestInspectors()
@@ -77,7 +79,12 @@ void LLFloaterTestInspectors::showAvatarInspector(LLUICtrl*, const LLSD& avatar_
 		id = avatar_id.asUUID();
 	}
 	// spawns off mouse position automatically
-	LLFloaterReg::showInstance("inspect_avatar", id);
+	LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", id));
+}
+
+void LLFloaterTestInspectors::showObjectInspector(LLUICtrl*, const LLSD& object_id)
+{
+	LLFloaterReg::showInstance("inspect_object", LLSD().insert("object_id", object_id));
 }
 
 void LLFloaterTestInspectors::onClickAvatar2D()
diff --git a/indra/newview/llfloatertestinspectors.h b/indra/newview/llfloatertestinspectors.h
index d2dc2248bb4..6555aad4e82 100644
--- a/indra/newview/llfloatertestinspectors.h
+++ b/indra/newview/llfloatertestinspectors.h
@@ -50,6 +50,7 @@ class LLFloaterTestInspectors : public LLFloater
 
 	// Button callback to show
 	void showAvatarInspector(LLUICtrl*, const LLSD& avatar_id);
+	void showObjectInspector(LLUICtrl*, const LLSD& avatar_id);
 	
 	// Debug function hookups for buttons
 	void onClickAvatar2D();
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 7dc29379e4d..c08996cc265 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -36,7 +36,7 @@
 
 #include "llfontgl.h"
 #include "llcoord.h"
-#include "llgl.h"
+//#include "llgl.h"
 
 #include "llagent.h"
 #include "llbutton.h"
diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp
index 2eb4e7580ee..266252efeaa 100644
--- a/indra/newview/llfloateruipreview.cpp
+++ b/indra/newview/llfloateruipreview.cpp
@@ -500,6 +500,14 @@ void LLFloaterUIPreview::refreshList()
 		}
 	}
 	found = TRUE;
+	while(found)				// for every inspector file that matches the pattern
+	{
+		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name, FALSE)))	// get next file matching pattern
+		{
+			addFloaterEntry(name.c_str());	// and add it to the list (file name only; localization code takes care of rest of path)
+		}
+	}
+	found = TRUE;
 	while(found)				// for every menu file that matches the pattern
 	{
 		if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name, FALSE)))	// get next file matching pattern
@@ -596,20 +604,12 @@ void LLFloaterUIPreview::addFloaterEntry(const std::string& path)
 void LLFloaterUIPreview::onClickDisplayFloater(S32 caller_id)
 {
 	displayFloater(TRUE, caller_id);
-	if(caller_id == PRIMARY_FLOATER)
-	{
-		mDisplayedFloater->center();	// move displayed floater to the center of the screen
-	}
 }
 
 // Saves the current floater/panel
 void LLFloaterUIPreview::onClickSaveFloater(S32 caller_id)
 {
 	displayFloater(TRUE, caller_id, true);
-	if(caller_id == PRIMARY_FLOATER)
-	{
-		mDisplayedFloater->center();	// move displayed floater to the center of the screen
-	}
 }
 
 // Saves all floater/panels
@@ -672,7 +672,8 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save)
 
 	*floaterp = new LLPreviewedFloater(this);
 
-	if(!strncmp(path.c_str(),"floater_",8))								// if it's a floater
+	if(!strncmp(path.c_str(),"floater_",8)
+		|| !strncmp(path.c_str(), "inspect_", 8))		// if it's a floater
 	{
 		if (save)
 		{
@@ -774,13 +775,6 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save)
 		mCloseOtherButton_2->setEnabled(TRUE);
 	}
 
-	// *TODO: Make the secondary floater pop up next to the primary one.  Doesn't seem to always work if secondary was up first...
-	if((mDisplayedFloater && ID == 2) || (mDisplayedFloater_2 && ID == 1))
-	{
-		mDisplayedFloater_2->setSnapTarget(mDisplayedFloater->getHandle());
-		mDisplayedFloater->addDependentFloater(mDisplayedFloater_2);
-	}
-
 	// Add localization to title so user knows whether it's localized or defaulted to en
 	std::string full_path = getLocalizedDirectory() + path;
 	std::string floater_lang = "EN";
@@ -793,6 +787,9 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save)
 						(ID == 1 ? " - Primary" : " - Secondary") + std::string("]");
 	(*floaterp)->setTitle(new_title);
 
+	(*floaterp)->center();
+	addDependentFloater(*floaterp);
+
 	if(click && ID == 1 && !save)
 	{
 		// set up live file to track it
diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index 490929e5a66..ef54ee7d4a1 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -563,7 +563,7 @@ const std::string& LLFolderViewItem::getSearchableLabel() const
 	return mSearchableLabel;
 }
 
-const std::string& LLFolderViewItem::getName( void ) const
+std::string LLFolderViewItem::getName( void ) const
 {
 	if(mListener)
 	{
@@ -947,18 +947,6 @@ void LLFolderViewItem::draw()
 			}
 		}
 	}
-
-	if( sDebugRects )
-	{
-		drawDebugRect();
-	}
-
-	//// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview)
-	//std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);
-	//if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights))
-	//{
-	//	drawDebugRect();
-	//}
 }
 
 
diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h
index eec885fd291..32134670c83 100644
--- a/indra/newview/llfolderviewitem.h
+++ b/indra/newview/llfolderviewitem.h
@@ -255,7 +255,7 @@ class LLFolderViewItem : public LLView
 
 	// This method returns the actual name of the thing being
 	// viewed. This method will ask the viewed object itself.
-	const std::string& getName( void ) const;
+	std::string getName( void ) const;
 
 	const std::string& getSearchableLabel( void ) const;
 
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 905857f393d..4caef8e0001 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -301,13 +301,22 @@ void LLGroupListItem::setGroupIconVisible(bool visible)
 void LLGroupListItem::setActive(bool active)
 {
 	// Active group should be bold.
-	LLFontDescriptor new_desc(mGroupNameBox->getFont()->getFontDesc());
+	LLFontDescriptor new_desc(mGroupNameBox->getDefaultFont()->getFontDesc());
 
 	// *NOTE dzaporozhan
 	// On Windows LLFontGL::NORMAL will not remove LLFontGL::BOLD if font 
 	// is predefined as bold (SansSerifSmallBold, for example)
 	new_desc.setStyle(active ? LLFontGL::BOLD : LLFontGL::NORMAL);
-	mGroupNameBox->setFont(LLFontGL::getFont(new_desc));
+	LLFontGL* new_font = LLFontGL::getFont(new_desc);
+	LLStyle::Params style_params;
+	style_params.font = new_font;
+
+	// *NOTE: You cannot set the style on a text box anymore, you must
+	// rebuild the text.  This will cause problems if the text contains
+	// hyperlinks, as their styles will be wrong.
+	std::string text = mGroupNameBox->getText();
+	mGroupNameBox->clear();
+	mGroupNameBox->appendText(text, false, style_params);
 }
 
 void LLGroupListItem::onInfoBtnClick()
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index d0be581f6df..dde36ac25b9 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -200,7 +200,6 @@ BOOL LLIMFloater::postBuild()
 	childSetCommitCallback("chat_editor", onSendMsg, this);
 	
 	mHistoryEditor = getChild<LLViewerTextEditor>("im_text");
-	mHistoryEditor->setParseHTML(TRUE);
 		
 	setTitle(LLIMModel::instance().getName(mSessionID));
 	setDocked(true);
@@ -361,19 +360,21 @@ void LLIMFloater::updateMessages()
 			if (mLastFromName != from)
 			{
 				message << from << " ----- " << msg["time"].asString();
-				mHistoryEditor->appendColoredText(message.str(), false,
-					prepend_newline, divider_color);
+				mHistoryEditor->appendText(message.str(),
+					prepend_newline, LLStyle::Params().color(divider_color) );
 				message.str("");
 				mLastFromName = from;
 			}
 
 			message << msg["message"].asString(); 
-			mHistoryEditor->appendColoredText(message.str(), false,
-				prepend_newline, chat_color);
+			mHistoryEditor->appendText(message.str(),
+				prepend_newline, 
+				LLStyle::Params().color(chat_color) );
 			message.str("");
 
 			mLastMessageIndex = msg["index"].asInteger();
 		}
+		mHistoryEditor->blockUndo();
 
 		mHistoryEditor->setCursorAndScrollToEnd();
 	}
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index abd3cd4def2..89a885090cf 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -1078,8 +1078,6 @@ BOOL LLFloaterIMPanel::postBuild()
 	//close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this);
 
 	mHistoryEditor = getChild<LLViewerTextEditor>("im_history");
-	mHistoryEditor->setParseHTML(TRUE);
-	mHistoryEditor->setParseHighlights(TRUE);
 
 	if ( IM_SESSION_GROUP_START == mDialog )
 	{
@@ -1334,16 +1332,18 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4
 		// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
 		if (name == SYSTEM_FROM)
 		{
-			mHistoryEditor->appendColoredText(name + separator_string, false, prepend_newline, color);
+			mHistoryEditor->appendText(name + separator_string, prepend_newline, LLStyle::Params().color(color));
 		}
 		else
 		{
 			// Convert the name to a hotlink and add to message.
-			mHistoryEditor->appendStyledText(name + separator_string, false, prepend_newline, LLStyleMap::instance().lookupAgent(source));
+			mHistoryEditor->appendText(name + separator_string, prepend_newline, LLStyleMap::instance().lookupAgent(source));
 		}
 		prepend_newline = false;
 	}
-	mHistoryEditor->appendColoredText(utf8msg, false, prepend_newline, color);
+	mHistoryEditor->appendText(utf8msg, prepend_newline, LLStyle::Params().color(color));
+	mHistoryEditor->blockUndo();
+
 	S32 im_log_option =  gSavedPerAccountSettings.getS32("IMLogOptions");
 	if (log_to_file && (im_log_option!=LOG_CHAT))
 	{
@@ -1859,7 +1859,8 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string
 	}
 
 	//self->addHistoryLine(line, LLColor4::grey, FALSE);
-	self->mHistoryEditor->appendColoredText(message, false, true, LLUIColorTable::instance().getColor("ChatHistoryTextColor"));
+	self->mHistoryEditor->appendText(message, true, LLStyle::Params().color(LLUIColorTable::instance().getColor("ChatHistoryTextColor")));
+	self->mHistoryEditor->blockUndo();
 }
 
 void LLFloaterIMPanel::showSessionStartError(
@@ -1934,4 +1935,3 @@ bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const
 	}
 	return false;
 }
-
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 72f89d2e721..a08d9e11632 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -34,15 +34,106 @@
 #include "llinspectavatar.h"
 
 // viewer files
+#include "llagent.h"
 #include "llagentdata.h"
 #include "llavataractions.h"
 #include "llavatarpropertiesprocessor.h"
 #include "llcallingcard.h"
-
-// linden libraries
+#include "lldateutil.h"		// ageFromDate()
+#include "llfloaterreporter.h"
+#include "llfloaterworldmap.h"
+#include "llmutelist.h"
+#include "llpanelblockedlist.h"
+#include "llviewermenu.h"
+#include "llvoiceclient.h"
+
+// Linden libraries
+#include "llcontrol.h"	// LLCachedControl
+#include "llfloater.h"
+#include "llfloaterreg.h"
 #include "lltooltip.h"	// positionViewNearMouse()
 #include "lluictrl.h"
 
+class LLFetchAvatarData;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectAvatar
+//////////////////////////////////////////////////////////////////////////////
+
+// Avatar Inspector, a small information window used when clicking
+// on avatar names in the 2D UI and in the ambient inspector widget for
+// the 3D world.
+class LLInspectAvatar : public LLFloater
+{
+	friend class LLFloaterReg;
+	
+public:
+	// avatar_id - Avatar ID for which to show information
+	// Inspector will be positioned relative to current mouse position
+	LLInspectAvatar(const LLSD& avatar_id);
+	virtual ~LLInspectAvatar();
+	
+	/*virtual*/ BOOL postBuild(void);
+	/*virtual*/ void draw();
+	
+	// Because floater is single instance, need to re-parse data on each spawn
+	// (for example, inspector about same avatar but in different position)
+	/*virtual*/ void onOpen(const LLSD& avatar_id);
+	
+	// Inspectors close themselves when they lose focus
+	/*virtual*/ void onFocusLost();
+	
+	// Update view based on information from avatar properties processor
+	void processAvatarData(LLAvatarData* data);
+	
+private:
+	// Make network requests for all the data to display in this view.
+	// Used on construction and if avatar id changes.
+	void requestUpdate();
+	
+	// Set the volume slider to this user's current client-side volume setting,
+	// hiding/disabling if the user is not nearby.
+	void updateVolumeSlider();
+	
+	// Button callbacks
+	void onClickAddFriend();
+	void onClickViewProfile();
+	void onClickIM();
+	void onClickTeleport();
+	void onClickInviteToGroup();
+	void onClickPay();
+	void onClickBlock();
+	void onClickReport();
+	bool onVisibleFindOnMap();
+	bool onVisibleGodMode();
+	void onClickMuteVolume();
+	void onFindOnMap();
+	void onVolumeChange(const LLSD& data);
+	
+	// Callback for gCacheName to look up avatar name
+	void nameUpdatedCallback(
+							 const LLUUID& id,
+							 const std::string& first,
+							 const std::string& last,
+							 BOOL is_group);
+	
+private:
+	LLUUID				mAvatarID;
+	// Need avatar name information to spawn friend add request
+	std::string			mAvatarName;
+	LLUUID				mPartnerID;
+	// an in-flight request for avatar properties from LLAvatarPropertiesProcessor
+	// is represented by this object
+	LLFetchAvatarData*	mPropertiesRequest;
+	LLFrameTimer		mCloseTimer;
+	LLFrameTimer		mOpenTimer;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// LLFetchAvatarData
+//////////////////////////////////////////////////////////////////////////////
+
 // This object represents a pending request for avatar properties information
 class LLFetchAvatarData : public LLAvatarPropertiesObserver
 {
@@ -50,8 +141,8 @@ class LLFetchAvatarData : public LLAvatarPropertiesObserver
 	// If the inspector closes it will delete the pending request object, so the
 	// inspector pointer will be valid for the lifetime of this object
 	LLFetchAvatarData(const LLUUID& avatar_id, LLInspectAvatar* inspector)
-		:	mAvatarID(avatar_id),
-			mInspector(inspector)
+	:	mAvatarID(avatar_id),
+		mInspector(inspector)
 	{
 		LLAvatarPropertiesProcessor* processor = 
 			LLAvatarPropertiesProcessor::getInstance();
@@ -61,14 +152,14 @@ class LLFetchAvatarData : public LLAvatarPropertiesObserver
 		// properties processor)
 		processor->sendAvatarPropertiesRequest(mAvatarID);
 	}
-
+	
 	~LLFetchAvatarData()
 	{
 		// remove ourselves as an observer
 		LLAvatarPropertiesProcessor::getInstance()->
-			removeObserver(mAvatarID, this);
+		removeObserver(mAvatarID, this);
 	}
-
+	
 	void processProperties(void* data, EAvatarProcessorType type)
 	{
 		// route the data to the inspector
@@ -79,7 +170,7 @@ class LLFetchAvatarData : public LLAvatarPropertiesObserver
 			mInspector->processAvatarData(avatar_data);
 		}
 	}
-
+	
 	// Store avatar ID so we can un-register the observer on destruction
 	LLUUID mAvatarID;
 	LLInspectAvatar* mInspector;
@@ -88,10 +179,24 @@ class LLFetchAvatarData : public LLAvatarPropertiesObserver
 LLInspectAvatar::LLInspectAvatar(const LLSD& sd)
 :	LLFloater( LLSD() ),	// single_instance, doesn't really need key
 	mAvatarID(),			// set in onOpen()
-	mFirstName(),
-	mLastName(),
-	mPropertiesRequest(NULL)
+	mPartnerID(),
+	mAvatarName(),
+	mPropertiesRequest(NULL),
+	mCloseTimer()
 {
+	mCommitCallbackRegistrar.add("InspectAvatar.ViewProfile",	boost::bind(&LLInspectAvatar::onClickViewProfile, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.AddFriend",	boost::bind(&LLInspectAvatar::onClickAddFriend, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.IM",	boost::bind(&LLInspectAvatar::onClickIM, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.Teleport",	boost::bind(&LLInspectAvatar::onClickTeleport, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.InviteToGroup",	boost::bind(&LLInspectAvatar::onClickInviteToGroup, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.Pay",	boost::bind(&LLInspectAvatar::onClickPay, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.Block",	boost::bind(&LLInspectAvatar::onClickBlock, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.Report",	boost::bind(&LLInspectAvatar::onClickReport, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.FindOnMap",	boost::bind(&LLInspectAvatar::onFindOnMap, this));	
+	mVisibleCallbackRegistrar.add("InspectAvatar.VisibleFindOnMap",	boost::bind(&LLInspectAvatar::onVisibleFindOnMap, this));	
+	mVisibleCallbackRegistrar.add("InspectAvatar.VisibleGodMode",	boost::bind(&LLInspectAvatar::onVisibleGodMode, this));	
+
+
 	// can't make the properties request until the widgets are constructed
 	// as it might return immediately, so do it in postBuild.
 }
@@ -100,6 +205,7 @@ LLInspectAvatar::~LLInspectAvatar()
 {
 	// clean up any pending requests so they don't call back into a deleted
 	// view
+	llinfos << "JAMESDEBUG cleanup inspect avatar" << llendl;
 	delete mPropertiesRequest;
 	mPropertiesRequest = NULL;
 }
@@ -113,18 +219,35 @@ BOOL LLInspectAvatar::postBuild(void)
 	getChild<LLUICtrl>("view_profile_btn")->setCommitCallback(
 		boost::bind(&LLInspectAvatar::onClickViewProfile, this) );
 
+	getChild<LLUICtrl>("mute_btn")->setCommitCallback(
+		boost::bind(&LLInspectAvatar::onClickMuteVolume, this) );
+
+	getChild<LLUICtrl>("volume_slider")->setCommitCallback(
+		boost::bind(&LLInspectAvatar::onVolumeChange, this, _2));
+
 	return TRUE;
 }
 
 void LLInspectAvatar::draw()
 {
-	static LLCachedControl<F32> FADE_OUT_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
-	if (mCloseTimer.getStarted())
+	static LLCachedControl<F32> FADE_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
+	if (mOpenTimer.getStarted())
 	{
-		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_OUT_TIME, 1.f, 0.f);
+		F32 alpha = clamp_rescale(mOpenTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 0.f, 1.f);
 		LLViewDrawContext context(alpha);
 		LLFloater::draw();
-		if (mCloseTimer.getElapsedTimeF32() > FADE_OUT_TIME)
+		if (alpha == 1.f)
+		{
+			mOpenTimer.stop();
+		}
+
+	}
+	else if (mCloseTimer.getStarted())
+	{
+		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
+		LLViewDrawContext context(alpha);
+		LLFloater::draw();
+		if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)
 		{
 			closeFloater(false);
 		}
@@ -142,9 +265,11 @@ void LLInspectAvatar::draw()
 void LLInspectAvatar::onOpen(const LLSD& data)
 {
 	mCloseTimer.stop();
+	mOpenTimer.start();
 
 	// Extract appropriate avatar id
-	mAvatarID = data.isUUID() ? data : data["avatar_id"];
+	mAvatarID = data["avatar_id"];
+	mPartnerID = LLUUID::null;
 
 	// Position the inspector relative to the mouse cursor
 	// Similar to how tooltips are positioned
@@ -160,6 +285,8 @@ void LLInspectAvatar::onOpen(const LLSD& data)
 
 	// can't call from constructor as widgets are not built yet
 	requestUpdate();
+
+	updateVolumeSlider();
 }
 
 //virtual
@@ -167,6 +294,7 @@ void LLInspectAvatar::onFocusLost()
 {
 	// Start closing when we lose focus
 	mCloseTimer.start();
+	mOpenTimer.stop();
 }
 
 void LLInspectAvatar::requestUpdate()
@@ -178,7 +306,9 @@ void LLInspectAvatar::requestUpdate()
 		getChild<LLUICtrl>("user_subtitle")->
 			setValue("Test subtitle");
 		getChild<LLUICtrl>("user_details")->
-			setValue("Test details\nTest line 2");
+			setValue("Test details");
+		getChild<LLUICtrl>("user_partner")->
+			setValue("Test partner");
 		return;
 	}
 
@@ -186,6 +316,7 @@ void LLInspectAvatar::requestUpdate()
 	getChild<LLUICtrl>("user_name")->setValue("");
 	getChild<LLUICtrl>("user_subtitle")->setValue("");
 	getChild<LLUICtrl>("user_details")->setValue("");
+	getChild<LLUICtrl>("user_partner")->setValue("");
 	
 	// Make a new request for properties
 	delete mPropertiesRequest;
@@ -212,49 +343,187 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data)
 {
 	LLStringUtil::format_map_t args;
 	args["[BORN_ON]"] = data->born_on;
-	args["[AGE]"] = LLAvatarPropertiesProcessor::ageFromDate(data->born_on);
+	args["[AGE]"] = LLDateUtil::ageFromDate(data->born_on);
 	args["[SL_PROFILE]"] = data->about_text;
 	args["[RW_PROFILE"] = data->fl_about_text;
 	args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(data);
-	args["[PAYMENTINFO]"] = LLAvatarPropertiesProcessor::paymentInfo(data);
+	std::string payment_info = LLAvatarPropertiesProcessor::paymentInfo(data);
+	args["[PAYMENTINFO]"] = payment_info;
+	args["[COMMA]"] = (payment_info.empty() ? "" : ",");
 
 	std::string subtitle = getString("Subtitle", args);
 	getChild<LLUICtrl>("user_subtitle")->setValue( LLSD(subtitle) );
 	std::string details = getString("Details", args);
 	getChild<LLUICtrl>("user_details")->setValue( LLSD(details) );
 
+	// Look up partner name, if there is one
+	mPartnerID = data->partner_id;
+	if (mPartnerID.notNull())
+	{
+		gCacheName->get(mPartnerID, FALSE,
+			boost::bind(&LLInspectAvatar::nameUpdatedCallback,
+			this, _1, _2, _3, _4));
+	}
+
 	// Delete the request object as it has been satisfied
 	delete mPropertiesRequest;
 	mPropertiesRequest = NULL;
 }
 
+void LLInspectAvatar::updateVolumeSlider()
+{
+	// By convention, we only display and toggle voice mutes, not all mutes
+	bool is_muted = LLMuteList::getInstance()->
+						isMuted(mAvatarID, LLMute::flagVoiceChat);
+	bool voice_enabled = gVoiceClient->getVoiceEnabled(mAvatarID);
+
+	LLUICtrl* mute_btn = getChild<LLUICtrl>("mute_btn");
+	mute_btn->setEnabled( voice_enabled );
+	mute_btn->setValue( is_muted );
+
+	LLUICtrl* volume_slider = getChild<LLUICtrl>("volume_slider");
+	volume_slider->setEnabled( voice_enabled && !is_muted );
+	const F32 DEFAULT_VOLUME = 0.5f;
+	F32 volume;
+	if (is_muted)
+	{
+		// it's clearer to display their volume as zero
+		volume = 0.f;
+	}
+	else if (!voice_enabled)
+	{
+		// use nominal value rather than 0
+		volume = DEFAULT_VOLUME;
+	}
+	else
+	{
+		// actual volume
+		volume = gVoiceClient->getUserVolume(mAvatarID);
+
+		// *HACK: Voice client doesn't have any data until user actually
+		// says something.
+		if (volume == 0.f)
+		{
+			volume = DEFAULT_VOLUME;
+		}
+	}
+	volume_slider->setValue( (F64)volume );
+}
+
+void LLInspectAvatar::onClickMuteVolume()
+{
+	// By convention, we only display and toggle voice mutes, not all mutes
+	LLMuteList* mute_list = LLMuteList::getInstance();
+	bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat);
+
+	LLMute mute(mAvatarID, mAvatarName, LLMute::AGENT);
+	if (!is_muted)
+	{
+		mute_list->add(mute, LLMute::flagVoiceChat);
+	}
+	else
+	{
+		mute_list->remove(mute, LLMute::flagVoiceChat);
+	}
+
+	updateVolumeSlider();
+}
+
+void LLInspectAvatar::onVolumeChange(const LLSD& data)
+{
+	F32 volume = (F32)data.asReal();
+	gVoiceClient->setUserVolume(mAvatarID, volume);
+}
+
 void LLInspectAvatar::nameUpdatedCallback(
 	const LLUUID& id,
 	const std::string& first,
 	const std::string& last,
 	BOOL is_group)
 {
-	// Possibly a request for an older inspector
-	if (id != mAvatarID) return;
-
-	mFirstName = first;
-	mLastName = last;
-	std::string name = first + " " + last;
-
-	childSetValue("user_name", LLSD(name) );
+	if (id == mAvatarID)
+	{
+		mAvatarName = first + " " + last;
+		childSetValue("user_name", LLSD(mAvatarName) );
+	}
+	
+	if (id == mPartnerID)
+	{
+		LLStringUtil::format_map_t args;
+		args["[PARTNER]"] = first + " " + last;
+		std::string partner = getString("Partner", args);
+		getChild<LLUICtrl>("user_partner")->setValue(partner);
+	}
+	// Otherwise possibly a request for an older inspector, ignore it
 }
 
 void LLInspectAvatar::onClickAddFriend()
 {
-	std::string name;
-	name.assign(mFirstName);
-	name.append(" ");
-	name.append(mLastName);
-
-	LLAvatarActions::requestFriendshipDialog(mAvatarID, name);
+	LLAvatarActions::requestFriendshipDialog(mAvatarID, mAvatarName);
 }
 
 void LLInspectAvatar::onClickViewProfile()
 {
+	// hide inspector when showing profile
+	setFocus(FALSE);
 	LLAvatarActions::showProfile(mAvatarID);
+
+}
+
+bool LLInspectAvatar::onVisibleFindOnMap()
+{
+	return gAgent.isGodlike() || is_agent_mappable(mAvatarID);
+}
+
+bool LLInspectAvatar::onVisibleGodMode()
+{
+	return gAgent.isGodlike();
+}
+
+void LLInspectAvatar::onClickIM()
+{ 
+	LLAvatarActions::startIM(mAvatarID);
+}
+
+void LLInspectAvatar::onClickTeleport()
+{
+	LLAvatarActions::offerTeleport(mAvatarID);
+}
+
+void LLInspectAvatar::onClickInviteToGroup()
+{
+	LLAvatarActions::inviteToGroup(mAvatarID);
+}
+
+void LLInspectAvatar::onClickPay()
+{
+	LLAvatarActions::pay(mAvatarID);
+}
+
+void LLInspectAvatar::onClickBlock()
+{
+	LLMute mute(mAvatarID, mAvatarName, LLMute::AGENT);
+	LLMuteList::getInstance()->add(mute);
+	LLPanelBlockedList::showPanelAndSelect(mute.mID);
+}
+
+void LLInspectAvatar::onClickReport()
+{
+	LLFloaterReporter::showFromObject(mAvatarID);
+}
+
+
+void LLInspectAvatar::onFindOnMap()
+{
+	gFloaterWorldMap->trackAvatar(mAvatarID, mAvatarName);
+	LLFloaterReg::showInstance("world_map");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectAvatarUtil
+//////////////////////////////////////////////////////////////////////////////
+void LLInspectAvatarUtil::registerFloater()
+{
+	LLFloaterReg::add("inspect_avatar", "inspect_avatar.xml",
+					  &LLFloaterReg::build<LLInspectAvatar>);
 }
diff --git a/indra/newview/llinspectavatar.h b/indra/newview/llinspectavatar.h
index 8d490382d20..179ad1ffe15 100644
--- a/indra/newview/llinspectavatar.h
+++ b/indra/newview/llinspectavatar.h
@@ -32,63 +32,10 @@
 #ifndef LLINSPECTAVATAR_H
 #define LLINSPECTAVATAR_H
 
-#include "llfloater.h"
-
-struct LLAvatarData;
-class LLFetchAvatarData;
-
-// Avatar Inspector, a small information window used when clicking
-// on avatar names in the 2D UI and in the ambient inspector widget for
-// the 3D world.
-class LLInspectAvatar : public LLFloater
+namespace LLInspectAvatarUtil
 {
-	friend class LLFloaterReg;
-
-public:
-	// avatar_id - Avatar ID for which to show information
-	// Inspector will be positioned relative to current mouse position
-	LLInspectAvatar(const LLSD& avatar_id);
-	virtual ~LLInspectAvatar();
-
-	/*virtual*/ BOOL postBuild(void);
-	/*virtual*/ void draw();
-
-	// Because floater is single instance, need to re-parse data on each spawn
-	// (for example, inspector about same avatar but in different position)
-	/*virtual*/ void onOpen(const LLSD& avatar_id);
-
-	// Inspectors close themselves when they lose focus
-	/*virtual*/ void onFocusLost();
-
-	// Update view based on information from avatar properties processor
-	void processAvatarData(LLAvatarData* data);
-
-private:
-	// Make network requests for all the data to display in this view.
-	// Used on construction and if avatar id changes.
-	void requestUpdate();
-
-	// Button callbacks
-	void onClickAddFriend();
-	void onClickViewProfile();
-
-	// Callback for gCacheName to look up avatar name
-	void nameUpdatedCallback(
-		const LLUUID& id,
-		const std::string& first,
-		const std::string& last,
-		BOOL is_group);
-
-private:
-	LLUUID				mAvatarID;
-	// Need avatar name information to spawn friend add request
-	std::string			mFirstName;
-	std::string			mLastName;
-	// an in-flight request for avatar properties from LLAvatarPropertiesProcessor
-	// is represented by this object
-	LLFetchAvatarData*	mPropertiesRequest;
-	LLFrameTimer		mCloseTimer;
-};
-
+	// Register with LLFloaterReg
+	void registerFloater();
+}
 
 #endif
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
new file mode 100644
index 00000000000..b0e6273c416
--- /dev/null
+++ b/indra/newview/llinspectobject.cpp
@@ -0,0 +1,563 @@
+/** 
+ * @file llinspectobject.cpp
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinspectobject.h"
+
+// Viewer
+#include "llnotifications.h"	// *TODO: Eliminate, add LLNotificationsUtil wrapper
+#include "llselectmgr.h"
+#include "llslurl.h"
+#include "llviewermenu.h"		// handle_object_touch(), handle_buy()
+#include "llviewerobjectlist.h"	// to select the requested object
+
+// Linden libraries
+#include "llbutton.h"			// setLabel(), not virtual!
+#include "llclickaction.h"
+#include "llcontrol.h"			// LLCachedControl
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "llresmgr.h"			// getMonetaryString
+#include "llsafehandle.h"
+#include "lltextbox.h"			// for description truncation
+#include "lltrans.h"
+#include "llui.h"				// positionViewNearMouse()
+#include "lluictrl.h"
+
+class LLViewerObject;
+
+// *TODO: Abstract out base class for LLInspectObject and LLInspectObject
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectObject
+//////////////////////////////////////////////////////////////////////////////
+
+// Object Inspector, a small information window used when clicking
+// in the ambient inspector widget for objects in the 3D world.
+class LLInspectObject : public LLFloater
+{
+	friend class LLFloaterReg;
+	
+public:
+	// object_id - Root object ID for which to show information
+	// Inspector will be positioned relative to current mouse position
+	LLInspectObject(const LLSD& object_id);
+	virtual ~LLInspectObject();
+	
+	/*virtual*/ BOOL postBuild(void);
+	/*virtual*/ void draw();
+	
+	// Because floater is single instance, need to re-parse data on each spawn
+	// (for example, inspector about same avatar but in different position)
+	/*virtual*/ void onOpen(const LLSD& avatar_id);
+	
+	// Release the selection and do other cleanup
+	void onClose();
+	
+	// Inspectors close themselves when they lose focus
+	/*virtual*/ void onFocusLost();
+	
+private:
+	// Refresh displayed data with information from selection manager
+	void update();
+
+	void hideButtons();
+	void updateButtons(LLSelectNode* nodep);
+	void updateSitLabel(LLSelectNode* nodep);
+	void updateTouchLabel(LLSelectNode* nodep);
+
+	void updateName(LLSelectNode* nodep);
+	void updateDescription(LLSelectNode* nodep);
+	void updatePrice(LLSelectNode* nodep);
+	
+	void updateCreator(LLSelectNode* nodep);
+		
+	void onClickBuy();
+	void onClickPay();
+	void onClickTakeFreeCopy();
+	void onClickTouch();
+	void onClickSit();
+	void onClickOpen();
+	void onClickMoreInfo();
+	
+private:
+	LLUUID				mObjectID;
+	LLFrameTimer		mOpenTimer;
+	LLFrameTimer		mCloseTimer;
+	LLSafeHandle<LLObjectSelection> mObjectSelection;
+};
+
+LLInspectObject::LLInspectObject(const LLSD& sd)
+:	LLFloater( LLSD() ),	// single_instance, doesn't really need key
+	mObjectID(),			// set in onOpen()
+	mCloseTimer(),
+	mOpenTimer()
+{
+	// can't make the properties request until the widgets are constructed
+	// as it might return immediately, so do it in postBuild.
+	mCommitCallbackRegistrar.add("InspectObject.Buy",	boost::bind(&LLInspectObject::onClickBuy, this));	
+	mCommitCallbackRegistrar.add("InspectObject.Pay",	boost::bind(&LLInspectObject::onClickPay, this));	
+	mCommitCallbackRegistrar.add("InspectObject.TakeFreeCopy",	boost::bind(&LLInspectObject::onClickTakeFreeCopy, this));	
+	mCommitCallbackRegistrar.add("InspectObject.Touch",	boost::bind(&LLInspectObject::onClickTouch, this));	
+	mCommitCallbackRegistrar.add("InspectObject.Sit",	boost::bind(&LLInspectObject::onClickSit, this));	
+	mCommitCallbackRegistrar.add("InspectObject.Open",	boost::bind(&LLInspectObject::onClickOpen, this));	
+	mCommitCallbackRegistrar.add("InspectObject.MoreInfo",	boost::bind(&LLInspectObject::onClickMoreInfo, this));	
+}
+
+
+LLInspectObject::~LLInspectObject()
+{
+}
+
+/*virtual*/
+BOOL LLInspectObject::postBuild(void)
+{
+	// The XML file has sample data in it.  Clear that out so we don't
+	// flicker when data arrives off network.
+	getChild<LLUICtrl>("object_name")->setValue("");
+	getChild<LLUICtrl>("object_creator")->setValue("");
+	getChild<LLUICtrl>("object_description")->setValue("");
+
+	// Set buttons invisible until we know what this object can do
+	hideButtons();
+
+	// Hide floater when name links clicked
+	LLTextBox* textbox = getChild<LLTextBox>("object_creator");
+	textbox->mURLClickSignal.connect(
+		boost::bind(&LLInspectObject::closeFloater, this, false) );
+
+	// Hook up functionality
+	getChild<LLUICtrl>("buy_btn")->setCommitCallback(
+		boost::bind(&LLInspectObject::onClickBuy, this));
+	getChild<LLUICtrl>("pay_btn")->setCommitCallback(
+		boost::bind(&LLInspectObject::onClickPay, this));
+	getChild<LLUICtrl>("take_free_copy_btn")->setCommitCallback(
+		boost::bind(&LLInspectObject::onClickTakeFreeCopy, this));
+	getChild<LLUICtrl>("touch_btn")->setCommitCallback(
+		boost::bind(&LLInspectObject::onClickTouch, this));
+	getChild<LLUICtrl>("sit_btn")->setCommitCallback(
+		boost::bind(&LLInspectObject::onClickSit, this));
+	getChild<LLUICtrl>("open_btn")->setCommitCallback(
+		boost::bind(&LLInspectObject::onClickOpen, this));
+	getChild<LLUICtrl>("more_info_btn")->setCommitCallback(
+		boost::bind(&LLInspectObject::onClickMoreInfo, this));
+
+	// Watch for updates to selection properties off the network
+	LLSelectMgr::getInstance()->mUpdateSignal.connect(
+		boost::bind(&LLInspectObject::update, this) );
+
+	mCloseSignal.connect( boost::bind(&LLInspectObject::onClose, this) );
+
+	return TRUE;
+}
+
+void LLInspectObject::draw()
+{
+	static LLCachedControl<F32> FADE_OUT_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
+	if (mOpenTimer.getStarted())
+	{
+		F32 alpha = clamp_rescale(mOpenTimer.getElapsedTimeF32(), 0.f, FADE_OUT_TIME, 0.f, 1.f);
+		LLViewDrawContext context(alpha);
+		LLFloater::draw();
+	}
+	else if (mCloseTimer.getStarted())
+	{
+		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_OUT_TIME, 1.f, 0.f);
+		LLViewDrawContext context(alpha);
+		LLFloater::draw();
+		if (mCloseTimer.getElapsedTimeF32() > FADE_OUT_TIME)
+		{
+			closeFloater(false);
+		}
+	}
+	else
+	{
+		LLFloater::draw();
+	}
+}
+
+
+// Multiple calls to showInstance("inspect_avatar", foo) will provide different
+// LLSD for foo, which we will catch here.
+//virtual
+void LLInspectObject::onOpen(const LLSD& data)
+{
+	mCloseTimer.stop();
+	mOpenTimer.start();
+
+	// Extract appropriate avatar id
+	mObjectID = data["object_id"];
+
+	// Position the inspector relative to the mouse cursor
+	// Similar to how tooltips are positioned
+	// See LLToolTipMgr::createToolTip
+	if (data.has("pos"))
+	{
+		LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
+	}
+	else
+	{
+		LLUI::positionViewNearMouse(this);
+	}
+
+	// Promote hovered object to a complete selection, which will also force
+	// a request for selected object data off the network
+	LLViewerObject* obj = gObjectList.findObject( mObjectID );
+	if (obj)
+	{
+		LLSelectMgr::instance().deselectAll();
+		mObjectSelection = LLSelectMgr::instance().selectObjectAndFamily(obj);
+
+		// Mark this as a transient selection
+		struct SetTransient : public LLSelectedNodeFunctor
+		{
+			bool apply(LLSelectNode* node)
+			{
+				node->setTransient(TRUE);
+				return true;
+			}
+		} functor;
+		mObjectSelection->applyToNodes(&functor);
+	}
+}
+
+void LLInspectObject::onClose()
+{
+	// Release selection to deselect
+	mObjectSelection = NULL;
+}
+
+//virtual
+void LLInspectObject::onFocusLost()
+{
+	// Start closing when we lose focus
+	mCloseTimer.start();
+	mOpenTimer.stop();
+}
+
+
+void LLInspectObject::update()
+{
+	// Performance optimization, because we listen to updates from select mgr
+	// but we're never destroyed.
+	if (!getVisible()) return;
+
+	LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection();
+	if (!selection) return;
+
+	LLSelectNode* nodep = selection->getFirstRootNode();
+	if (!nodep) return;
+
+	updateButtons(nodep);
+	updateName(nodep);
+	updateDescription(nodep);
+	updateCreator(nodep);
+	updatePrice(nodep);
+}
+
+void LLInspectObject::hideButtons()
+{
+	getChild<LLUICtrl>("buy_btn")->setVisible(false);
+	getChild<LLUICtrl>("pay_btn")->setVisible(false);
+	getChild<LLUICtrl>("take_free_copy_btn")->setVisible(false);
+	getChild<LLUICtrl>("touch_btn")->setVisible(false);
+	getChild<LLUICtrl>("sit_btn")->setVisible(false);
+	getChild<LLUICtrl>("open_btn")->setVisible(false);
+}
+
+// *TODO: Extract this method from lltoolpie.cpp and put somewhere shared
+extern U8 final_click_action(LLViewerObject*);
+
+// Choose the "most relevant" operation for this object, and show a button for
+// that operation as the left-most button in the inspector.
+void LLInspectObject::updateButtons(LLSelectNode* nodep)
+{
+	// We'll start with everyone hidden and show the ones we need
+	hideButtons();
+	
+	LLViewerObject* object = nodep->getObject();
+	LLViewerObject *parent = (LLViewerObject*)object->getParent();
+	bool for_copy = anyone_copy_selection(nodep);
+	bool for_sale = enable_buy_object();
+	S32 price = nodep->mSaleInfo.getSalePrice();
+	U8 click_action = final_click_action(object);
+
+	if (for_copy
+		|| (for_sale && price == 0))
+	{
+		// Free copies have priority over other operations
+		getChild<LLUICtrl>("take_free_copy_btn")->setVisible(true);
+	}
+	else if (for_sale)
+	{
+		getChild<LLUICtrl>("buy_btn")->setVisible(true);
+	}
+	else if ( enable_pay_object() )
+	{
+		getChild<LLUICtrl>("pay_btn")->setVisible(true);
+	}
+	else if (click_action == CLICK_ACTION_SIT)
+	{
+		// Click-action sit must come before "open" because many objects on
+		// which you can sit have scripts, and hence can be opened
+		getChild<LLUICtrl>("sit_btn")->setVisible(true);
+		updateSitLabel(nodep);
+	}
+	else if (object->flagHandleTouch()
+		|| (parent && parent->flagHandleTouch()))
+	{
+		getChild<LLUICtrl>("touch_btn")->setVisible(true);
+		updateTouchLabel(nodep);
+	}
+	else if ( enable_object_open() )
+	{
+		// Open is last because anything with a script in it can be opened
+		getChild<LLUICtrl>("open_btn")->setVisible(true);
+	}
+	else
+	{
+		// By default, we can sit on anything
+		getChild<LLUICtrl>("sit_btn")->setVisible(true);
+		updateSitLabel(nodep);
+	}
+
+	// No flash
+	focusFirstItem(FALSE, FALSE);
+}
+
+void LLInspectObject::updateSitLabel(LLSelectNode* nodep)
+{
+	LLButton* sit_btn = getChild<LLButton>("sit_btn");
+	if (!nodep->mSitName.empty())
+	{
+		sit_btn->setLabel( nodep->mSitName );
+	}
+	else
+	{
+		sit_btn->setLabel( getString("Sit") );
+	}
+}
+
+void LLInspectObject::updateTouchLabel(LLSelectNode* nodep)
+{
+	LLButton* sit_btn = getChild<LLButton>("touch_btn");
+	if (!nodep->mTouchName.empty())
+	{
+		sit_btn->setLabel( nodep->mTouchName );
+	}
+	else
+	{
+		sit_btn->setLabel( getString("Touch") );
+	}
+}
+
+void LLInspectObject::updateName(LLSelectNode* nodep)
+{
+	std::string name;
+	if (!nodep->mName.empty())
+	{
+		name = nodep->mName;
+	}
+	else
+	{
+		name = LLTrans::getString("TooltipNoName");
+	}
+	getChild<LLUICtrl>("object_name")->setValue(name);
+}
+
+void LLInspectObject::updateDescription(LLSelectNode* nodep)
+{
+	const char* const DEFAULT_DESC = "(No Description)";
+	std::string desc;
+	if (!nodep->mDescription.empty()
+		&& nodep->mDescription != DEFAULT_DESC)
+	{
+		desc = nodep->mDescription;
+	}
+
+	LLTextBox* textbox = getChild<LLTextBox>("object_description");
+	textbox->setValue(desc);
+
+	// Truncate description text to fit in widget
+	// *HACK: OMG, use lower-left corner to truncate text
+	// Don't round the position, we want the left of the character
+	S32 corner_index = textbox->getDocIndexFromLocalCoord( 0, 0, FALSE);
+	LLWString desc_wide = textbox->getWText();
+	// index == length if position is past last character
+	if (corner_index < (S32)desc_wide.length())
+	{
+		desc_wide = desc_wide.substr(0, corner_index);
+		textbox->setWText(desc_wide);
+	}
+}
+
+void LLInspectObject::updateCreator(LLSelectNode* nodep)
+{
+	// final information for display
+	LLStringUtil::format_map_t args;
+	std::string text;
+	
+	// Leave text blank until data loaded
+	if (nodep->mValid)
+	{
+		// Utilize automatic translation of SLURL into name to display 
+		// a clickable link		
+		// Objects cannot be created by a group, so use agent URL format
+		LLUUID creator_id = nodep->mPermissions->getCreator();
+		std::string creator_url =
+			LLSLURL::buildCommand("agent", creator_id, "about");
+		args["[CREATOR]"] = creator_url;
+				
+		// created by one user but owned by another
+		std::string owner_url;
+		LLUUID owner_id;
+		bool group_owned = nodep->mPermissions->isGroupOwned();
+		if (group_owned)
+		{
+			owner_id = nodep->mPermissions->getGroup();
+			owner_url =	LLSLURL::buildCommand("group", owner_id, "about");
+		}
+		else
+		{
+			owner_id = nodep->mPermissions->getOwner();
+			owner_url =	LLSLURL::buildCommand("agent", owner_id, "about");
+		}
+		args["[OWNER]"] = owner_url;
+		
+		if (creator_id == owner_id)
+		{
+			// common case, created and owned by one user
+			text = getString("Creator", args);
+		}
+		else
+		{
+			text = getString("CreatorAndOwner", args);
+		}
+	}
+	getChild<LLUICtrl>("object_creator")->setValue(text);
+}
+
+void LLInspectObject::updatePrice(LLSelectNode* nodep)
+{
+	// *TODO: Only look these up once and use for both updateButtons and here
+	bool for_copy = anyone_copy_selection(nodep);
+	bool for_sale = enable_buy_object();
+	S32 price = nodep->mSaleInfo.getSalePrice();
+	
+	bool show_price_icon = false;
+	std::string line;
+	if (for_copy
+		|| (for_sale && price == 0))
+	{
+		line = getString("PriceFree");
+		show_price_icon = true;
+	}
+	else if (for_sale)
+	{
+		LLStringUtil::format_map_t args;
+		args["[AMOUNT]"] = LLResMgr::getInstance()->getMonetaryString(price);
+		line = getString("Price", args);
+		show_price_icon = true;
+	}
+	getChild<LLUICtrl>("price_text")->setValue(line);
+	getChild<LLUICtrl>("price_icon")->setVisible(show_price_icon);
+}
+
+void LLInspectObject::onClickBuy()
+{
+	handle_buy();
+	closeFloater();
+}
+
+void LLInspectObject::onClickPay()
+{
+	handle_give_money_dialog();
+	closeFloater();
+}
+
+void LLInspectObject::onClickTakeFreeCopy()
+{
+	LLObjectSelection* selection = LLSelectMgr::getInstance()->getSelection();
+	if (!selection) return;
+
+	LLSelectNode* nodep = selection->getFirstRootNode();
+	if (!nodep) return;
+
+	// Figure out if this is a "free buy" or a "take copy"
+	bool for_copy = anyone_copy_selection(nodep);
+	// Prefer to just take a free copy
+	if (for_copy)
+	{
+		handle_take_copy();
+	}
+	else
+	{
+		// Buy for free (confusing, but that's how it is)
+		handle_buy();
+	}
+	closeFloater();
+}
+
+void LLInspectObject::onClickTouch()
+{
+	handle_object_touch();
+	closeFloater();
+}
+
+void LLInspectObject::onClickSit()
+{
+	handle_object_sit_or_stand();
+	closeFloater();
+}
+
+void LLInspectObject::onClickOpen()
+{
+	LLFloaterReg::showInstance("openobject");
+	closeFloater();
+}
+
+void LLInspectObject::onClickMoreInfo()
+{
+	// *TODO: Show object info side panel, once that is implemented.
+	LLNotifications::instance().add("ClickUnimplemented");
+	closeFloater();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectObjectUtil
+//////////////////////////////////////////////////////////////////////////////
+void LLInspectObjectUtil::registerFloater()
+{
+	LLFloaterReg::add("inspect_object", "inspect_object.xml",
+					  &LLFloaterReg::build<LLInspectObject>);
+}
+
diff --git a/indra/newview/llinspectobject.h b/indra/newview/llinspectobject.h
new file mode 100644
index 00000000000..aa45f401c00
--- /dev/null
+++ b/indra/newview/llinspectobject.h
@@ -0,0 +1,40 @@
+/** 
+ * @file llinspectobject.h
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLINSPECTOBJECT_H
+#define LLINSPECTOBJECT_H
+
+namespace LLInspectObjectUtil
+{
+	void registerFloater();
+}
+
+#endif
diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp
index efc03b3d88f..4fd3b7bddc8 100644
--- a/indra/newview/lljoystickbutton.cpp
+++ b/indra/newview/lljoystickbutton.cpp
@@ -537,18 +537,6 @@ void LLJoystickCameraRotate::draw()
 	{
 		drawRotatedImage( getImageSelected()->getImage(), 3 );
 	}
-
-	if (sDebugRects)
-	{
-		drawDebugRect();
-	}
-
-	//// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview)
-	//std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);
-	//if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights))
-	//{
-	//	drawDebugRect();
-	//}
 }
 
 // Draws image rotated by multiples of 90 degrees
@@ -723,18 +711,6 @@ void LLJoystickCameraZoom::draw()
 	{
 		getImageUnselected()->draw( 0, 0 );
 	}
-
-	if (sDebugRects)
-	{
-		drawDebugRect();
-	}
-
-	//// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview)
-	//std::set<LLView*>::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this);
-	//if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights))
-	//{
-	//	drawDebugRect();
-	//}
 }
 
 void LLJoystickCameraZoom::updateSlop()
diff --git a/indra/newview/lllistview.cpp b/indra/newview/lllistview.cpp
index 3019d5d3d58..f4f3b1df78d 100644
--- a/indra/newview/lllistview.cpp
+++ b/indra/newview/lllistview.cpp
@@ -57,7 +57,7 @@ LLListView::LLListView(const Params& p)
 	LLRect label_rect(0, 20, 300, 0);
 	LLTextBox::Params text_box_params;
 	text_box_params.rect(label_rect);
-	text_box_params.text("This is a list-view");
+	text_box_params.initial_value("This is a list-view");
 	mLabel = LLUICtrlFactory::create<LLTextBox>(text_box_params);
 	addChild(mLabel);
 }
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 68dc3854dbf..16a10dc502a 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -290,10 +290,10 @@ void LLLocationInputCtrl::hideList()
 		focusTextEntry();
 }
 
-BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	// Let the buttons show their tooltips.
-	if (LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen) && !msg.empty())
+	if (LLUICtrl::handleToolTip(x, y, mask))
 	{
 		if (mList->getRect().pointInRect(x, y)) 
 		{
diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h
index 6edae9a9e2b..c74a294ca37 100644
--- a/indra/newview/lllocationinputctrl.h
+++ b/indra/newview/lllocationinputctrl.h
@@ -71,7 +71,7 @@ class LLLocationInputCtrl
 
 	// LLView interface
 	/*virtual*/ void		setEnabled(BOOL enabled);
-	/*virtual*/ BOOL		handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect);
+	/*virtual*/ BOOL		handleToolTip(S32 x, S32 y, MASK mask);
 	/*virtual*/ BOOL		handleKeyHere(KEY key, MASK mask);
 	/*virtual*/ void		onFocusReceived();
 	/*virtual*/ void		onFocusLost();
diff --git a/indra/newview/llmenucommands.cpp b/indra/newview/llmenucommands.cpp
index 1666ec1336b..f61177d5810 100644
--- a/indra/newview/llmenucommands.cpp
+++ b/indra/newview/llmenucommands.cpp
@@ -49,7 +49,6 @@
 #include "llfloaterchat.h"
 #include "llfloaterdirectory.h"
 #include "llfloaterworldmap.h"
-#include "llgivemoney.h"
 #include "lllineeditor.h"
 #include "llnotify.h"
 #include "llstatusbar.h"
@@ -68,11 +67,6 @@
 #include "llfocusmgr.h"
 #include "llnearbychatbar.h"
 
-void handle_pay_by_id(const LLUUID& agent_id)
-{
-	const BOOL is_group = FALSE;
-	LLFloaterPay::payDirectly(&give_money, agent_id, is_group);
-}
 
 void handle_mouselook(void*)
 {
diff --git a/indra/newview/llmenucommands.h b/indra/newview/llmenucommands.h
index 368c6fe7527..a3611ef6d16 100644
--- a/indra/newview/llmenucommands.h
+++ b/indra/newview/llmenucommands.h
@@ -35,7 +35,6 @@
 
 class LLUUID;
 
-void handle_pay_by_id(const LLUUID& agent_id);
 void handle_mouselook(void*);
 void handle_chat(void*);
 void handle_return_key(void*);
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 8ef6b25c509..541db0ca6e1 100644
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -32,16 +32,18 @@
 
 #include "llviewerprecompiledheaders.h"
 
-#include <boost/tokenizer.hpp>
-
 #include "llnamelistctrl.h"
 
+#include <boost/tokenizer.hpp>
+
 #include "llcachename.h"
+#include "llfloaterreg.h"
 #include "llinventory.h"
 #include "llscrolllistitem.h"
 #include "llscrolllistcell.h"
 #include "llscrolllistcolumn.h"
 #include "llsdparam.h"
+#include "lltooltip.h"
 
 static LLDefaultChildRegistry::Register<LLNameListCtrl> r("name_list");
 
@@ -128,6 +130,60 @@ BOOL LLNameListCtrl::handleDragAndDrop(
 	return handled;
 }
 
+void LLNameListCtrl::showAvatarInspector(const LLUUID& avatar_id)
+{
+	LLSD key;
+	key["avatar_id"] = avatar_id;
+	LLFloaterReg::showInstance("inspect_avatar", key);
+}
+
+//virtual
+BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
+{
+	BOOL handled = FALSE;
+	S32 column_index = getColumnIndexFromOffset(x);
+	LLScrollListItem* hit_item = hitItem(x, y);
+	if (hit_item)
+	{
+		if (column_index == mNameColumnIndex)
+		{
+			// ...this is the column with the avatar name
+			LLScrollListCell* hit_cell = hit_item->getColumn(column_index);
+			if (hit_cell)
+			{
+				S32 row_index = getItemIndex(hit_item);
+				LLRect cell_rect = getCellRect(row_index, column_index);
+				// Convert rect local to screen coordinates
+				LLRect sticky_rect;
+				localRectToScreen(cell_rect, &sticky_rect);
+
+				// Spawn at right side of cell
+				LLCoordGL pos( sticky_rect.mRight - 16, sticky_rect.mTop );
+				LLPointer<LLUIImage> icon = LLUI::getUIImage("Info_Small");
+				LLUUID avatar_id = hit_item->getValue().asUUID();
+
+				LLToolTip::Params params;
+				params.background_visible( false );
+				params.click_callback( boost::bind(&LLNameListCtrl::showAvatarInspector, this, avatar_id) );
+				params.delay_time(0.0f);		// spawn instantly on hover
+				params.image( icon );
+				params.message("");
+				params.padding(0);
+				params.pos(pos);
+				params.sticky_rect(sticky_rect);
+
+				LLToolTipMgr::getInstance()->show(params);
+				handled = TRUE;
+			}
+		}
+	}
+	if (!handled)
+	{
+		handled = LLScrollListCtrl::handleToolTip(x, y, mask);
+	}
+	return handled;
+}
+
 // public
 void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos,
 									  BOOL enabled)
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 070b6c4f4f8..d0f0ec4d218 100644
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -110,14 +110,19 @@ class LLNameListCtrl
 	static void refreshAll(const LLUUID& id, const std::string& firstname,
 						   const std::string& lastname, BOOL is_group);
 
-	virtual BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask,
+	// LLView interface
+	/*virtual*/ BOOL	handleDragAndDrop(S32 x, S32 y, MASK mask,
 									  BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
 									  EAcceptance *accept,
 									  std::string& tooltip_msg);
+	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
 
 	void setAllowCallingCardDrop(BOOL b) { mAllowCallingCardDrop = b; }
 
 	/*virtual*/ void updateColumns();
+private:
+	void showAvatarInspector(const LLUUID& avatar_id);
+
 private:
 	S32    			mNameColumnIndex;
 	std::string		mNameColumn;
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index 84309379336..cc5f37b9034 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -51,6 +51,7 @@
 //for LLViewerTextEditor support
 #include "llagent.h" 			// gAgent
 #include "llfloaterscriptdebug.h"
+#include "llslurl.h"
 #include "llviewertexteditor.h"
 #include "llstylemap.h"
 
@@ -207,7 +208,7 @@ void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& colo
 	if (chat.mSourceType == CHAT_SOURCE_AGENT &&
 		chat.mFromID != LLUUID::null)
 	{
-		str_URL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str());
+		str_URL = LLSLURL::buildCommand("agent", chat.mFromID, "inspect");
 	}
 
 	// If the chat line has an associated url, link it up to the name.
@@ -216,20 +217,31 @@ void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& colo
 	{
 		std::string start_line = line.substr(0, chat.mFromName.length() + 1);
 		line = line.substr(chat.mFromName.length() + 1);
-		mChatHistoryEditor->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,str_URL));
+		mChatHistoryEditor->appendText(start_line, prepend_newline, 
+			LLStyleMap::instance().lookup(chat.mFromID,str_URL));
+		mChatHistoryEditor->blockUndo();
 		prepend_newline = false;
 	}
 
 	S32 font_size = gSavedSettings.getS32("ChatFontSize");
 
-	std::string font_name = "";
-
-	if (0 == font_size)
-		font_name = "small";
-	else if (2 == font_size)
-		font_name = "sansserifbig";
+	const LLFontGL* fontp = NULL;
+	switch(font_size)
+	{
+	case 0:
+		fontp = LLFontGL::getFontSansSerifSmall();
+		break;
+	default:
+	case 1:
+		fontp = LLFontGL::getFontSansSerif();
+		break;
+	case 2:
+		fontp = LLFontGL::getFontSansSerifBig();
+		break;
+	}
 
-	mChatHistoryEditor->appendColoredText(line, false, prepend_newline, color, font_name);
+	mChatHistoryEditor->appendText(line, prepend_newline, LLStyle::Params().color(color).font(fontp));
+	mChatHistoryEditor->blockUndo();
 }
 
 void	LLNearbyChat::addMessage(const LLChat& chat)
@@ -250,11 +262,6 @@ void	LLNearbyChat::addMessage(const LLChat& chat)
 	}
 	
 	// could flash the chat button in the status bar here. JC
-
-
-	mChatHistoryEditor->setParseHTML(TRUE);
-	mChatHistoryEditor->setParseHighlights(TRUE);
-	
 	if (!chat.mMuted)
 		add_timestamped_line(chat, color);
 }
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 5e65f2244d9..bd6e6cd0cba 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -500,7 +500,7 @@ BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return TRUE;
 }
 
-BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen )
+BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
 {
 	if (gDisconnected)
 	{
@@ -530,7 +530,7 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& msg, LLRect& sticky_rec
 		args["[REGION]"] = "";
 	}
 	
-	msg = mToolTipMsg;
+	std::string msg = mToolTipMsg;
 	LLStringUtil::format(msg, args);
 	
 	LLRect sticky_rect;
@@ -545,7 +545,7 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& msg, LLRect& sticky_rec
 		sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP;
 	}
 
-	LLToolTipMgr::instance().show(LLToolTipParams()
+	LLToolTipMgr::instance().show(LLToolTip::Params()
 		.message(msg)
 		.sticky_rect(sticky_rect));
 		
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index 7598154480d..821c348835b 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -67,7 +67,7 @@ class LLNetMap : public LLUICtrl
 
 	/*virtual*/ void	draw();
 	/*virtual*/ BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks);
-	/*virtual*/ BOOL	handleToolTip( S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen );
+	/*virtual*/ BOOL	handleToolTip( S32 x, S32 y, MASK mask);
 	
 	void			setScale( F32 scale );
 	void			setRotateMap( BOOL b ) { mRotateMap = b; }
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 7ccff730804..c543f85f224 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -38,6 +38,7 @@
 #include "llavatarconstants.h"	// AVATAR_ONLINE
 #include "llcallingcard.h"
 #include "llcombobox.h"
+#include "lldateutil.h"
 #include "llimview.h"
 #include "lltexteditor.h"
 #include "lltexturectrl.h"
@@ -447,7 +448,7 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g
 
 void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
 {
-	childSetValue("register_date", LLAvatarPropertiesProcessor::ageFromDate(avatar_data->born_on));
+	childSetValue("register_date", LLDateUtil::ageFromDate(avatar_data->born_on));
 	childSetValue("sl_description_edit", avatar_data->about_text);
 	childSetValue("fl_description_edit",avatar_data->fl_about_text);
 	childSetValue("2nd_life_pic", avatar_data->image_id);
diff --git a/indra/newview/llpanelavatartag.cpp b/indra/newview/llpanelavatartag.cpp
index e66c36287b3..03ad19f9118 100644
--- a/indra/newview/llpanelavatartag.cpp
+++ b/indra/newview/llpanelavatartag.cpp
@@ -64,29 +64,7 @@ BOOL LLPanelAvatarTag::postBuild()
 
 void LLPanelAvatarTag::draw()
 {
-	
-	///TODO: ANGELA do something similar to fade the panel out
-/*	// HACK: assuming tooltip background is in ToolTipBGColor, perform fade out
-	LLColor4 bg_color = LLUIColorTable::instance().getColor( "ToolTipBgColor" );
-	if (tooltip_vis)
-	{
-		mToolTipFadeTimer.stop();
-		mToolTip->setBackgroundColor(bg_color);
-	}
-	else 
-	{
-		if (!mToolTipFadeTimer.getStarted())
-		{
-			mToolTipFadeTimer.start();
-		}
-		F32 tool_tip_fade_time = gSavedSettings.getF32("ToolTipFadeTime");
-		bg_color.mV[VALPHA] = clamp_rescale(mToolTipFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, bg_color.mV[VALPHA], 0.f);
-		mToolTip->setBackgroundColor(bg_color);
-	}
-	
-	// above interpolation of bg_color alpha is guaranteed to reach 0.f exactly
-	mToolTip->setVisible( bg_color.mV[VALPHA] != 0.f );
- */
+
 }
 void LLPanelAvatarTag::setName(const std::string& name)
 {
diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h
index 52b74a184b5..0993f46f799 100644
--- a/indra/newview/llpanelblockedlist.h
+++ b/indra/newview/llpanelblockedlist.h
@@ -35,6 +35,7 @@
 
 #include "llpanel.h"
 #include "llmutelist.h"
+#include "llfloater.h"
 // #include <vector>
 
 // class LLButton;
diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp
index 2e1d9719953..0331fad60c0 100644
--- a/indra/newview/llpanelgroupgeneral.cpp
+++ b/indra/newview/llpanelgroupgeneral.cpp
@@ -721,15 +721,18 @@ void LLPanelGroupGeneral::updateMembers()
 		row["id"] = member->getID();
 
 		row["columns"][0]["column"] = "name";
+		row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL";
 		row["columns"][0]["font"]["style"] = style;
 		// value is filled in by name list control
 
 		row["columns"][1]["column"] = "title";
 		row["columns"][1]["value"] = member->getTitle();
+		row["columns"][1]["font"]["name"] = "SANSSERIF_SMALL";
 		row["columns"][1]["font"]["style"] = style;
 		
 		row["columns"][2]["column"] = "online";
 		row["columns"][2]["value"] = member->getOnlineStatus();
+		row["columns"][2]["font"]["name"] = "SANSSERIF_SMALL";
 		row["columns"][2]["font"]["style"] = style;
 
 		sSDTime += sd_timer.getElapsedTimeF32();
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 99bb760b619..1521c1113ae 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -634,6 +634,7 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl,
 
 		row["columns"][1]["column"] = "action";
 		row["columns"][1]["value"] = action_set->mActionSetData->mName;
+		row["columns"][1]["font"]["name"] = "SANSSERIF_SMALL";
 		row["columns"][1]["font"]["style"] = "BOLD";
 
 		LLScrollListItem* title_row = ctrl->addElement(row, ADD_BOTTOM, action_set->mActionSetData);
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index a7f66f32938..24e76e2c6e0 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -178,10 +178,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	if (LLPanelLogin::sInstance)
 	{
 		llwarns << "Duplicate instance of login view deleted" << llendl;
-		delete LLPanelLogin::sInstance;
-
 		// Don't leave bad pointer in gFocusMgr
 		gFocusMgr.setDefaultKeyboardFocus(NULL);
+
+		delete LLPanelLogin::sInstance;
 	}
 
 	LLPanelLogin::sInstance = this;
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index b2a0a01005a..c94c38983d9 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -621,7 +621,7 @@ void LLPanelPeople::updateButtons()
 	buttonSetEnabled("chat_btn",			item_selected);
 }
 
-const std::string& LLPanelPeople::getActiveTabName() const
+std::string LLPanelPeople::getActiveTabName() const
 {
 	return mTabContainer->getCurrentPanel()->getName();
 }
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index de27814388b..03802015ceb 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -63,7 +63,7 @@ class LLPanelPeople : public LLPanel
 	void					updateRecentList();
 
 	void					updateButtons();
-	const std::string&		getActiveTabName() const;
+	std::string				getActiveTabName() const;
 	LLUUID					getCurrentItemID() const;
 	void					buttonSetVisible(std::string btn_name, BOOL visible);
 	void					buttonSetEnabled(const std::string& btn_name, bool enabled);
diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp
index 42f99064094..2d3f9013709 100644
--- a/indra/newview/llpanelpermissions.cpp
+++ b/indra/newview/llpanelpermissions.cpp
@@ -85,9 +85,6 @@ BOOL LLPanelPermissions::postBuild()
 	childSetPrevalidate("Object Description",LLLineEditor::prevalidatePrintableNotPipe);
 
 	
-	childSetAction("button owner profile",LLPanelPermissions::onClickOwner,this);
-	childSetAction("button creator profile",LLPanelPermissions::onClickCreator,this);
-
 	getChild<LLUICtrl>("button set group")->setCommitCallback(boost::bind(&LLPanelPermissions::onClickGroup,this));
 
 	childSetCommitCallback("checkbox share with group",LLPanelPermissions::onCommitGroupShare,this);
@@ -162,12 +159,10 @@ void LLPanelPermissions::refresh()
 		childSetEnabled("Creator:",false);
 		childSetText("Creator Name",LLStringUtil::null);
 		childSetEnabled("Creator Name",false);
-		childSetEnabled("button creator profile",false);
 
 		childSetEnabled("Owner:",false);
 		childSetText("Owner Name",LLStringUtil::null);
 		childSetEnabled("Owner Name",false);
-		childSetEnabled("button owner profile",false);
 
 		childSetEnabled("Group:",false);
 		childSetText("Group Name",LLStringUtil::null);
@@ -275,7 +270,6 @@ void LLPanelPermissions::refresh()
 
 	childSetText("Creator Name",creator_name);
 	childSetEnabled("Creator Name",TRUE);
-	childSetEnabled("button creator profile", creators_identical && mCreatorID.notNull() );
 
 	// Update owner text field
 	childSetEnabled("Owner:",true);
@@ -310,7 +304,6 @@ void LLPanelPermissions::refresh()
 
 	childSetText("Owner Name",owner_name);
 	childSetEnabled("Owner Name",TRUE);
-	childSetEnabled("button owner profile",owners_identical && (mOwnerID.notNull() || LLSelectMgr::getInstance()->selectIsGroupOwned()));
 
 	// update group text field
 	childSetEnabled("Group:",true);
@@ -803,31 +796,6 @@ void LLPanelPermissions::onClickRelease(void*)
 	LLSelectMgr::getInstance()->sendOwner(LLUUID::null, LLUUID::null);
 }
 
-// static
-void LLPanelPermissions::onClickCreator(void *data)
-{
-	LLPanelPermissions *self = (LLPanelPermissions *)data;
-
-	LLAvatarActions::showProfile(self->mCreatorID);
-}
-
-// static
-void LLPanelPermissions::onClickOwner(void *data)
-{
-	LLPanelPermissions *self = (LLPanelPermissions *)data;
-
-	if (LLSelectMgr::getInstance()->selectIsGroupOwned())
-	{
-		LLUUID group_id;
-		LLSelectMgr::getInstance()->selectGetGroup(group_id);
-		LLGroupActions::show(group_id);
-	}
-	else
-	{
-		LLAvatarActions::showProfile(self->mOwnerID);
-	}
-}
-
 void LLPanelPermissions::onClickGroup()
 {
 	LLUUID owner_id;
diff --git a/indra/newview/llpanelpermissions.h b/indra/newview/llpanelpermissions.h
index 481efe178e0..805a4dbe97d 100644
--- a/indra/newview/llpanelpermissions.h
+++ b/indra/newview/llpanelpermissions.h
@@ -42,12 +42,6 @@
 // Panel for permissions of an object.
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-class LLCheckBoxCtrl;
-class LLTextBox;
-class LLButton;
-class LLLineEditor;
-class LLRadioGroup;
-class LLComboBox;
 class LLNameBox;
 
 class LLPanelPermissions : public LLPanel
@@ -56,31 +50,24 @@ class LLPanelPermissions : public LLPanel
 	LLPanelPermissions();
 	virtual ~LLPanelPermissions();
 
-	virtual	BOOL	postBuild();
+	/*virtual*/	BOOL	postBuild();
 
-	// MANIPULATORS
 	void refresh();							// refresh all labels as needed
 
 protected:
 	// statics
 	static void onClickClaim(void*);
 	static void onClickRelease(void*);
-	static void onClickCreator(void*);
-	static void onClickOwner(void*);
 		   void onClickGroup();
 		   void cbGroupID(LLUUID group_id);
 	static void onClickDeedToGroup(void*);
 
 	static void onCommitPerm(LLUICtrl *ctrl, void *data, U8 field, U32 perm);
 
-//	static void onCommitGroupMove(LLUICtrl *ctrl, void *data);
-//	static void onCommitGroupCopy(LLUICtrl *ctrl, void *data);
-//	static void onCommitGroupModify(LLUICtrl *ctrl, void *data);
 	static void onCommitGroupShare(LLUICtrl *ctrl, void *data);
 
 	static void onCommitEveryoneMove(LLUICtrl *ctrl, void *data);
 	static void onCommitEveryoneCopy(LLUICtrl *ctrl, void *data);
-	//static void onCommitEveryoneModify(LLUICtrl *ctrl, void *data);
 
 	static void onCommitNextOwnerModify(LLUICtrl* ctrl, void* data);
 	static void onCommitNextOwnerCopy(LLUICtrl* ctrl, void* data);
diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp
index 5df3d4f1d63..424e453a2fc 100644
--- a/indra/newview/llpanelpick.cpp
+++ b/indra/newview/llpanelpick.cpp
@@ -356,14 +356,7 @@ std::string LLPanelPick::createLocationText(const std::string& owner_name, const
 
 void LLPanelPick::setPickName(std::string name)
 {
-	if (mEditMode)
-	{
-		childSetValue(XML_NAME, name);
-	}
-	else
-	{
-		childSetWrappedText(XML_NAME, name);
-	}
+	childSetValue(XML_NAME, name);
 	
 	//preserving non-wrapped text for info/edit modes switching
 	mName = name;
@@ -371,14 +364,7 @@ void LLPanelPick::setPickName(std::string name)
 
 void LLPanelPick::setPickDesc(std::string desc)
 {
-	if (mEditMode)
-	{
-		childSetValue(XML_DESC, desc);
-	}
-	else
-	{
-		childSetWrappedText(XML_DESC, desc);
-	}
+	childSetValue(XML_DESC, desc);
 
 	//preserving non-wrapped text for info/edit modes switching
 	mDesc = desc;
@@ -386,7 +372,7 @@ void LLPanelPick::setPickDesc(std::string desc)
 
 void LLPanelPick::setPickLocation(const std::string& location)
 {
-	childSetWrappedText(XML_LOCATION, location);
+	childSetValue(XML_LOCATION, location);
 
 	//preserving non-wrapped text for info/edit modes switching
 	mLocation = location;
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index be281294519..3bd2645be34 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -35,6 +35,7 @@
 
 #include "llagent.h"
 #include "llavataractions.h"
+#include "llfloaterreg.h"
 #include "llcommandhandler.h"
 #include "llpanelpicks.h"
 #include "lltabcontainer.h"
@@ -52,15 +53,21 @@ class LLAgentHandler : public LLCommandHandler
 		LLMediaCtrl* web)
 	{
 		if (params.size() < 2) return false;
-		LLUUID agent_id;
-		if (!agent_id.set(params[0], FALSE))
+		LLUUID avatar_id;
+		if (!avatar_id.set(params[0], FALSE))
 		{
 			return false;
 		}
 
 		if (params[1].asString() == "about")
 		{
-			LLAvatarActions::showProfile(agent_id);
+			LLAvatarActions::showProfile(avatar_id);
+			return true;
+		}
+
+		if (params[1].asString() == "inspect")
+		{
+			LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", avatar_id));
 			return true;
 		}
 		return false;
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index 04827e3a787..faca950963e 100644
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -421,9 +421,7 @@ BOOL LLPreviewGesture::postBuild()
 	mStepList = list;
 
 	// Options
-	text = getChild<LLTextBox>("options_text");
-	text->setBorderVisible(TRUE);
-	mOptionsText = text;
+	mOptionsText = getChild<LLTextBox>("options_text");
 
 	combo = getChild<LLComboBox>( "animation_list");
 	combo->setVisible(FALSE);
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp
index 29320522d92..ab9cfbf8506 100644
--- a/indra/newview/llpreviewnotecard.cpp
+++ b/indra/newview/llpreviewnotecard.cpp
@@ -85,12 +85,8 @@ LLPreviewNotecard::~LLPreviewNotecard()
 BOOL LLPreviewNotecard::postBuild()
 {
 	LLViewerTextEditor *ed = getChild<LLViewerTextEditor>("Notecard Editor");
-	if (ed)
-	{
-		ed->setParseHTML(TRUE);
-		ed->setNotecardInfo(mItemUUID, mObjectID, getKey());
-		ed->makePristine();
-	}
+	ed->setNotecardInfo(mItemUUID, mObjectID, getKey());
+	ed->makePristine();
 
 	childSetAction("Save", onClickSave, this);
 	childSetVisible("lock", FALSE);	
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index 3c6645f1169..5f6b210767d 100644
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -196,7 +196,7 @@ void LLProgressView::draw()
 
 void LLProgressView::setText(const std::string& text)
 {
-	getChild<LLTextBox>("progress_text")->setWrappedText(LLStringExplicit(text));
+	getChild<LLUICtrl>("progress_text")->setValue(text);
 }
 
 void LLProgressView::setPercent(const F32 percent)
@@ -207,7 +207,7 @@ void LLProgressView::setPercent(const F32 percent)
 void LLProgressView::setMessage(const std::string& msg)
 {
 	mMessage = msg;
-	getChild<LLTextBox>("message_text")->setWrappedText(LLStringExplicit(mMessage));
+	getChild<LLUICtrl>("message_text")->setValue(mMessage);
 }
 
 void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label)
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index ae8c9f770b9..d163ceb30e2 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -43,6 +43,7 @@
 #include "llrender.h"
 #include "llpermissions.h"
 #include "llpermissionsflags.h"
+#include "lltrans.h"
 #include "llundo.h"
 #include "lluuid.h"
 #include "llvolume.h"
@@ -66,6 +67,7 @@
 #include "llinventorymodel.h"
 #include "llmenugl.h"
 #include "llmutelist.h"
+#include "llslurl.h"
 #include "llstatusbar.h"
 #include "llsurface.h"
 #include "lltool.h"
@@ -805,11 +807,13 @@ LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32
 	// NOTE: there is only ever one linked set in mHoverObjects
 	if (mHoverObjects->getFirstRootObject() != objectp) 
 	{
+
 		// Collect all of the objects
 		std::vector<LLViewerObject*> objects;
 		objectp = objectp->getRootEdit();
 		objectp->addThisAndNonJointChildren(objects);
 
+		mHoverObjects->deleteAllNodes();
 		for (std::vector<LLViewerObject*>::iterator iter = objects.begin();
 			 iter != objects.end(); ++iter)
 		{
@@ -818,7 +822,7 @@ LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32
 			nodep->selectTE(face, TRUE);
 			mHoverObjects->addNodeAtEnd(nodep);
 		}
-		
+
 		requestObjectPropertiesFamily(objectp);
 	}
 
@@ -2389,6 +2393,7 @@ BOOL LLSelectMgr::selectGetCreator(LLUUID& result_id, std::string& name)
 	}
 	if (first_id.isNull())
 	{
+		name = LLTrans::getString("AvatarNameNobody");
 		return FALSE;
 	}
 	
@@ -2396,11 +2401,11 @@ BOOL LLSelectMgr::selectGetCreator(LLUUID& result_id, std::string& name)
 	
 	if (identical)
 	{
-		gCacheName->getFullName(first_id, name);
+		name = LLSLURL::buildCommand("agent", first_id, "inspect");
 	}
 	else
 	{
-		name.assign( "(multiple)" );
+		name = LLTrans::getString("AvatarNameMultiple");
 	}
 
 	return identical;
@@ -2455,20 +2460,21 @@ BOOL LLSelectMgr::selectGetOwner(LLUUID& result_id, std::string& name)
 		BOOL public_owner = (first_id.isNull() && !first_group_owned);
 		if (first_group_owned)
 		{
-			name.assign( "(Group Owned)");
+			// *TODO: We don't have group inspectors yet
+			name = LLSLURL::buildCommand("group", first_id, "about");
 		}
 		else if(!public_owner)
 		{
-			gCacheName->getFullName(first_id, name);
+			name = LLSLURL::buildCommand("agent", first_id, "inspect");
 		}
 		else
 		{
-			name.assign("Public");
+			name = LLTrans::getString("AvatarNameNobody");
 		}
 	}
 	else
 	{
-		name.assign( "(multiple)" );
+		name = LLTrans::getString("AvatarNameMultiple");
 	}
 
 	return identical;
@@ -2519,7 +2525,7 @@ BOOL LLSelectMgr::selectGetLastOwner(LLUUID& result_id, std::string& name)
 		BOOL public_owner = (first_id.isNull());
 		if(!public_owner)
 		{
-			gCacheName->getFullName(first_id, name);
+			name = LLSLURL::buildCommand("agent", first_id, "inspect");
 		}
 		else
 		{
@@ -5449,15 +5455,17 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 // Utility Functions
 //
 
-// Update everyone who cares about the selection list
+// *DEPRECATED: See header comment.
 void dialog_refresh_all()
 {
-	if (gNoRender)
-	{
-		return;
-	}
+	// This is the easiest place to fire the update signal, as it will
+	// make cleaning up the functions below easier.  Also, sometimes entities
+	// outside the selection manager change properties of selected objects
+	// and call into this function.  Yuck.
+	LLSelectMgr::getInstance()->mUpdateSignal();
 
-	//could refresh selected object info in toolbar here
+	// *TODO: Eliminate all calls into outside classes below, make those
+	// objects register with the update signal.
 
 	gFloaterTools->dirty();
 
@@ -5853,6 +5861,27 @@ void LLSelectMgr::setAgentHUDZoom(F32 target_zoom, F32 current_zoom)
 	gAgent.mHUDCurZoom = current_zoom;
 }
 
+/////////////////////////////////////////////////////////////////////////////
+// Object selection iterator helpers
+/////////////////////////////////////////////////////////////////////////////
+bool LLObjectSelection::is_root::operator()(LLSelectNode *node)
+{
+	LLViewerObject* object = node->getObject();
+	return (object != NULL) && !node->mIndividualSelection && (object->isRootEdit() || object->isJointChild());
+}
+
+bool LLObjectSelection::is_valid_root::operator()(LLSelectNode *node)
+{
+	LLViewerObject* object = node->getObject();
+	return (object != NULL) && node->mValid && !node->mIndividualSelection && (object->isRootEdit() || object->isJointChild());
+}
+
+bool LLObjectSelection::is_root_object::operator()(LLSelectNode *node)
+{
+	LLViewerObject* object = node->getObject();
+	return (object != NULL) && (object->isRootEdit() || object->isJointChild());
+}
+
 LLObjectSelection::LLObjectSelection() : 
 	LLRefCount(),
 	mSelectType(SELECT_TYPE_WORLD)
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 9e02170d74a..26ac95060f1 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -35,7 +35,6 @@
 
 #include "llcharacter.h"
 #include "lleditmenuhandler.h"
-#include "llstring.h"
 #include "llundo.h"
 #include "lluuid.h"
 #include "llpointer.h"
@@ -48,14 +47,15 @@
 #include "llframetimer.h"
 #include "llbbox.h"
 #include "llpermissions.h"
-#include "llviewerobject.h"
 #include "llcontrol.h"
+#include "llviewerobject.h"	// LLObjectSelection::getSelectedTEValue template
+
 #include <deque>
-#include "boost/iterator/filter_iterator.hpp"
+#include <boost/iterator/filter_iterator.hpp>
+#include <boost/signals2.hpp>
 
 class LLMessageSystem;
 class LLViewerTexture;
-class LLViewerObject;
 class LLColor4;
 class LLVector3;
 class LLSelectNode;
@@ -203,13 +203,9 @@ class LLObjectSelection : public LLRefCount
 protected:
 	~LLObjectSelection();
 
-	// List
 public:
 	typedef std::list<LLSelectNode*> list_t;
-private:
-	list_t mList;
 
-public:
 	// Iterators
 	struct is_non_null
 	{
@@ -235,11 +231,7 @@ class LLObjectSelection : public LLRefCount
 
 	struct is_root
 	{
-		bool operator()(LLSelectNode* node)
-		{
-			LLViewerObject* object = node->getObject();
-			return (object != NULL) && !node->mIndividualSelection && (object->isRootEdit() || object->isJointChild());
-		}
+		bool operator()(LLSelectNode* node);
 	};
 	typedef boost::filter_iterator<is_root, list_t::iterator > root_iterator;
 	root_iterator root_begin() { return root_iterator(mList.begin(), mList.end()); }
@@ -247,11 +239,7 @@ class LLObjectSelection : public LLRefCount
 	
 	struct is_valid_root
 	{
-		bool operator()(LLSelectNode* node)
-		{
-			LLViewerObject* object = node->getObject();
-			return (object != NULL) && node->mValid && !node->mIndividualSelection && (object->isRootEdit() || object->isJointChild());
-		}
+		bool operator()(LLSelectNode* node);
 	};
 	typedef boost::filter_iterator<is_root, list_t::iterator > valid_root_iterator;
 	valid_root_iterator valid_root_begin() { return valid_root_iterator(mList.begin(), mList.end()); }
@@ -259,11 +247,7 @@ class LLObjectSelection : public LLRefCount
 	
 	struct is_root_object
 	{
-		bool operator()(LLSelectNode* node)
-		{
-			LLViewerObject* object = node->getObject();
-			return (object != NULL) && (object->isRootEdit() || object->isJointChild());
-		}
+		bool operator()(LLSelectNode* node);
 	};
 	typedef boost::filter_iterator<is_root_object, list_t::iterator > root_object_iterator;
 	root_object_iterator root_object_begin() { return root_object_iterator(mList.begin(), mList.end()); }
@@ -326,6 +310,7 @@ class LLObjectSelection : public LLRefCount
 	ESelectType getSelectType() const { return mSelectType; }
 
 private:
+	list_t mList;
 	const LLObjectSelection &operator=(const LLObjectSelection &);
 
 	LLPointer<LLViewerObject> mPrimaryObject;
@@ -398,13 +383,16 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	// Add
 	////////////////////////////////////////////////////////////////
 
-	// For when you want just a child object.
-	LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES);
-
 	// This method is meant to select an object, and then select all
-	// of the ancestors and descendents. This should be the normal behavior.
+	// of the ancestors and descendants. This should be the normal behavior.
+	//
+	// *NOTE: You must hold on to the object selection handle, otherwise
+	// the objects will be automatically deselected in 1 frame.
 	LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE);
 
+	// For when you want just a child object.
+	LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES);
+
 	// Same as above, but takes a list of objects.  Used by rectangle select.
 	LLObjectSelectionHandle selectObjectAndFamily(const std::vector<LLViewerObject*>& object_list, BOOL send_to_sim = TRUE);
 
@@ -691,7 +679,13 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	static void packPermissionsHead(void* user_data);
 	static void packGodlikeHead(void* user_data);
 	static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle);
-	
+
+public:
+	// Observer/callback support for when object selection changes or
+	// properties are received/updated
+	typedef boost::signals2::signal< void ()> update_signal_t;
+	update_signal_t mUpdateSignal;
+
 private:
 	LLPointer<LLViewerTexture>				mSilhouetteImagep;
 	LLObjectSelectionHandle					mSelectedObjects;
@@ -723,8 +717,10 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	LLAnimPauseRequest		mPauseRequest;
 };
 
-// Utilities
-void dialog_refresh_all();		// Update subscribers to the selection list
+// *DEPRECATED: For callbacks or observers, use
+// LLSelectMgr::getInstance()->mUpdateSignal.connect( callback )
+// Update subscribers to the selection list
+void dialog_refresh_all();		
 
 // Templates
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 836fe9729da..37e268ad343 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -105,6 +105,14 @@ std::string LLSLURL::buildSLURL(const std::string& regionname, S32 x, S32 y, S32
 	return slurl;
 }
 
+// static
+std::string LLSLURL::buildCommand(const char* noun, const LLUUID& id, const char* verb)
+{
+	std::string slurl = llformat("secondlife:///app/%s/%s/%s",
+		noun, id.asString().c_str(), verb);
+	return slurl;
+}
+
 // static
 std::string LLSLURL::buildUnescapedSLURL(const std::string& regionname, S32 x, S32 y, S32 z)
 {
diff --git a/indra/newview/llslurl.h b/indra/newview/llslurl.h
index 8af2bdfb832..05b0143e72d 100644
--- a/indra/newview/llslurl.h
+++ b/indra/newview/llslurl.h
@@ -73,6 +73,9 @@ class LLSLURL
 	 */
 	static std::string buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z);
 
+	/// Build a SLURL like secondlife:///app/agent/<uuid>/inspect
+	static std::string buildCommand(const char* noun, const LLUUID& id, const char* verb);
+
 	/**
 	 * builds: http://slurl.com/secondlife/Region Name/x/y/z/ without escaping result url.
 	 */
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 053b863b6db..62435c62882 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -195,6 +195,10 @@
 #include "lldxhardware.h"
 #endif
 
+#if (LL_LINUX || LL_SOLARIS) && LL_GTK
+#include <glib/gspawn.h>
+#endif
+
 //
 // exported globals
 //
@@ -1824,9 +1828,9 @@ bool idle_startup()
 		{
 			gCacheName = new LLCacheName(gMessageSystem);
 			gCacheName->addObserver(&callback_cache_name);
-			gCacheName->LocalizeCacheName("waiting", LLTrans::getString("CacheWaiting"));
-			gCacheName->LocalizeCacheName("nobody", LLTrans::getString("CacheNobody"));
-			gCacheName->LocalizeCacheName("none", LLTrans::getString("CacheNone"));
+			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();
 		}
diff --git a/indra/newview/llstylemap.cpp b/indra/newview/llstylemap.cpp
index fc125dcf9ca..2485563cbc6 100644
--- a/indra/newview/llstylemap.cpp
+++ b/indra/newview/llstylemap.cpp
@@ -33,8 +33,10 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llstylemap.h"
+
 #include "llstring.h"
 #include "llui.h"
+#include "llslurl.h"
 #include "llviewercontrol.h"
 #include "llagent.h"
 
@@ -47,7 +49,8 @@ const LLStyle::Params &LLStyleMap::lookupAgent(const LLUUID &source)
 		if (source != LLUUID::null && source != gAgent.getID() )
 		{
 			style_params.color.control = "HTMLLinkColor";
-			style_params.link_href = llformat("secondlife:///app/agent/%s/about",source.asString().c_str());
+			style_params.link_href = 
+					LLSLURL::buildCommand("agent", source, "inspect");
 		}
 		else
 		{
@@ -55,7 +58,7 @@ const LLStyle::Params &LLStyleMap::lookupAgent(const LLUUID &source)
 			style_params.color = LLColor4::white;
 		}
 
-		mMap[source] = LLStyle::Params();
+		mMap[source] = style_params;
 	}
 	return mMap[source];
 }
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 1b47fa43c7d..9fc91e29712 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -882,7 +882,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
 	LLTextBox::Params params(p.caption_text);
 	params.name(p.label);
 	params.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ));
-	params.text(p.label);
+	params.initial_value(p.label());
 	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
 	mCaption = LLUICtrlFactory::create<LLTextBox> (params);
 	addChild( mCaption );
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 4309f56710f..d9be6b172cb 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -168,6 +168,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
 	params.name("Alert message");
 	params.font(font);
 	params.tab_stop(false);
+	params.wrap(true);
 	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
 
 	LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params);
@@ -178,7 +179,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
 			- LINE_HEIGHT			// title bar
 			- 3*VPAD - BTN_HEIGHT;
 	msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height );
-	msg_box->setWrappedText(msg, (F32)MAX_ALLOWED_MSG_WIDTH);
+	msg_box->setValue(msg);
 	msg_box->reshapeToFitText();
 
 	const LLRect& text_rect = msg_box->getRect();
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index 9761a45d83a..86b162247ae 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -144,10 +144,11 @@ LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : LLToas
 		params.mouse_opaque(false);
 		params.font.style("BOLD");
 		params.text_color(LLUIColorTable::instance().getColor("NotifyCautionWarnColor"));
-		params.background_color(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
+		params.bg_readonly_color(LLUIColorTable::instance().getColor("NotifyCautionBoxColor"));
 		params.border_visible(false);
+		params.wrap(true);
 		caution_box = LLUICtrlFactory::create<LLTextBox> (params);
-		caution_box->setWrappedText(notification->getMessage());
+		caution_box->setValue(notification->getMessage());
 
 		addChild(caution_box);
 
@@ -175,13 +176,13 @@ LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : LLToas
 		params.default_text(mMessage);
 		params.font(sFont);
 		params.embedded_items(false);
-		params.word_wrap(true);
+		params.wrap(true);
 		params.tab_stop(false);
 		params.mouse_opaque(false);
 		params.bg_readonly_color(LLColor4::transparent);
 		params.text_readonly_color(LLUIColorTable::instance().getColor("NotifyTextColor"));
 		params.enabled(false);
-		params.hide_border(true);
+		params.border_visible(false);
 		text = LLUICtrlFactory::create<LLTextEditor> (params);
 		addChild(text);
 	}
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index e884d89ce4b..68ad043129a 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -56,7 +56,7 @@ void LLToastPanel::snapToMessageHeight(LLTextBox* message, S32 maxLineCount)
 	if (message->getVisible())
 	{
 		S32 heightDelta = 0;
-		S32 maxTextHeight = (S32)(message->getFont()->getLineHeight() * maxLineCount);
+		S32 maxTextHeight = (S32)(message->getDefaultFont()->getLineHeight() * maxLineCount);
 
 		LLRect messageRect = message->getRect();
 		S32 oldTextHeight = messageRect.getHeight();
diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp
index 880d5d5e122..669a62a238a 100644
--- a/indra/newview/lltool.cpp
+++ b/indra/newview/lltool.cpp
@@ -155,7 +155,7 @@ BOOL LLTool::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
 	return FALSE;
 }
 
-BOOL LLTool::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+BOOL LLTool::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	// by default, didn't handle it
 	// llinfos << "LLTool::handleToolTip" << llendl;
diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h
index bef4a2e1fd8..c3573cd38cf 100644
--- a/indra/newview/lltool.h
+++ b/indra/newview/lltool.h
@@ -66,7 +66,7 @@ class LLTool
 	virtual BOOL	handleDoubleClick(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	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen);
+	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask);
 
 		// Return FALSE to allow context menu to be shown.
 	virtual void	screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const
@@ -74,7 +74,7 @@ class LLTool
 	virtual void	localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const
 							{ *screen_x = local_x; *screen_y = local_y;	}
 
-	virtual const std::string& getName() const	{ return mName; }
+	virtual std::string getName() const	{ return mName; }
 
 	// New virtual functions
 	virtual LLViewerObject*	getEditingObject()		{ return NULL; }
diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp
index c7c9f075047..0572f9a6986 100644
--- a/indra/newview/lltoolbar.cpp
+++ b/indra/newview/lltoolbar.cpp
@@ -271,6 +271,7 @@ void LLToolBar::updateCommunicateList()
 	contact_sd["columns"][0]["value"] = LLFloaterMyFriends::getInstance()->getShortTitle(); 
 	if (LLFloaterMyFriends::getInstance() == frontmost_floater)
 	{
+		contact_sd["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; 
 		contact_sd["columns"][0]["font"]["style"] = "BOLD"; 
 		// make sure current tab is selected in list
 		if (selected.isUndefined())
@@ -286,6 +287,7 @@ void LLToolBar::updateCommunicateList()
 
 	if (LLFloaterChat::getInstance() == frontmost_floater)
 	{
+		communicate_sd["columns"][0]["font"]["name"] = "SANSSERIF_SMALL";
 		communicate_sd["columns"][0]["font"]["style"] = "BOLD";
 		if (selected.isUndefined())
 		{
@@ -318,6 +320,7 @@ void LLToolBar::updateCommunicateList()
 			im_sd["columns"][0]["value"] = floater_title;
 			if (im_floaterp  == frontmost_floater)
 			{
+				im_sd["columns"][0]["font"]["name"] = "SANSSERIF_SMALL";
 				im_sd["columns"][0]["font"]["style"] = "BOLD";
 				if (selected.isUndefined())
 				{
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index c3064ffa434..bc0a654eb96 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -762,11 +762,11 @@ BOOL LLToolDragAndDrop::handleKey(KEY key, MASK mask)
 	return FALSE;
 }
 
-BOOL LLToolDragAndDrop::handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen)
+BOOL LLToolDragAndDrop::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	if (!mToolTipMsg.empty())
 	{
-		LLToolTipMgr::instance().show(LLToolTipParams()
+		LLToolTipMgr::instance().show(LLToolTip::Params()
 			.message(mToolTipMsg)
 			.delay_time(gSavedSettings.getF32( "DragAndDropToolTipDelay" )));
 		return TRUE;
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index acf01869e78..e1536acf751 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -59,7 +59,7 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleKey(KEY key, MASK mask);
-	virtual BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen);
+	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask);
 	virtual void	onMouseCaptureLost();
 	virtual void	handleDeselect();
 
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index d5db2241432..5525c359fc4 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -70,9 +70,6 @@
 #include "llworld.h"
 #include "llui.h"
 #include "llweb.h"
-#include "llinspectavatar.h"
-
-extern void handle_buy(void*);
 
 extern BOOL gDebugClicks;
 
@@ -212,7 +209,7 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
 		case CLICK_ACTION_SIT:
 			if ((gAgent.getAvatarObject() != NULL) && (!gAgent.getAvatarObject()->isSitting())) // agent not already sitting
 			{
-				handle_sit_or_stand();
+				handle_object_sit_or_stand();
 				// put focus in world when sitting on an object
 				gFocusMgr.setKeyboardFocus(NULL);
 				return TRUE;
@@ -456,7 +453,7 @@ void LLToolPie::selectionPropertiesReceived()
 			switch (click_action)
 			{
 			case CLICK_ACTION_BUY:
-				handle_buy(NULL);
+				handle_buy();
 				break;
 			case CLICK_ACTION_PAY:
 				handle_give_money_dialog();
@@ -586,10 +583,39 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)
 	return FALSE;
 }
 
-//FIXME - RN: get this in LLToolSelectLand too or share some other way?
-const char* DEFAULT_DESC = "(No Description)";
+static bool needs_tooltip(LLSelectNode* nodep)
+{
+	LLViewerObject* object = nodep->getObject();
+	LLViewerObject *parent = (LLViewerObject *)object->getParent();
+	if (object->flagHandleTouch()
+		|| (parent && parent->flagHandleTouch())
+		|| object->flagTakesMoney()
+		|| (parent && parent->flagTakesMoney())
+		|| object->flagAllowInventoryAdd()
+		)
+	{
+		return true;
+	}
+
+	U8 click_action = final_click_action(object);
+	if (click_action != 0)
+	{
+		return true;
+	}
+
+	if (nodep->mValid)
+	{
+		bool anyone_copy = anyone_copy_selection(nodep);
+		bool for_sale = for_sale_selection(nodep);
+		if (anyone_copy || for_sale)
+		{
+			return true;
+		}
+	}
+	return false;
+}
 
-BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, std::string& msg, LLRect& sticky_rect_screen)
+BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask)
 {
 	if (!LLUI::sSettingGroups["config"]->getBOOL("ShowHoverTips")) return TRUE;
 	if (!mHoverPick.isValid()) return TRUE;
@@ -636,8 +662,11 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, std::string& msg, LLRect
 		line.clear();
 		if (hover_object->isAvatar())
 		{
-			// only show tooltip if inspector not already open
-			if (!LLFloaterReg::instanceVisible("inspect_avatar"))
+			// only show tooltip if same inspector not already open
+			LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
+			if (!existing_inspector 
+				|| !existing_inspector->getVisible()
+				|| existing_inspector->getKey()["avatar_id"].asUUID() != hover_object->getID())
 			{
 				std::string avatar_name;
 				LLNameValue* firstname = hover_object->getNVPair("FirstName");
@@ -650,12 +679,15 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, std::string& msg, LLRect
 				{
 					avatar_name = LLTrans::getString("TooltipPerson");
 				}
-				LLToolTipParams params;
-				params.message(avatar_name);
-				params.image.name("Info");
-				params.sticky_rect(gViewerWindow->getVirtualWorldViewRect());
-				params.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
-				LLToolTipMgr::instance().show(params);
+
+				// *HACK: We may select this object, so pretend it was clicked
+				mPick = mHoverPick;
+				LLToolTipMgr::instance().show(LLToolTip::Params()
+					.message(avatar_name)
+					.image(LLUI::getUIImage("Info"))
+					.click_callback(boost::bind(showAvatarInspector, hover_object->getID()))
+					.visible_time_near(6.f)
+					.visible_time_far(3.f));
 			}
 		}
 		else
@@ -667,177 +699,38 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, std::string& msg, LLRect
 			//
 			//  Default prefs will suppress display unless the object is interactive
 			//
-			BOOL suppressObjectHoverDisplay = !gSavedSettings.getBOOL("ShowAllObjectHoverTip");			
-			
+			bool show_all_object_tips =
+				(bool)gSavedSettings.getBOOL("ShowAllObjectHoverTip");			
 			LLSelectNode *nodep = LLSelectMgr::getInstance()->getHoverNode();
-			if (nodep)
+			
+			// only show tooltip if same inspector not already open
+			LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_object");
+			if (nodep &&
+				(!existing_inspector 
+					|| !existing_inspector->getVisible()
+					|| existing_inspector->getKey()["object_id"].asUUID() != hover_object->getID()))
 			{
-				line.clear();
 				if (nodep->mName.empty())
 				{
-					line.append(LLTrans::getString("TooltipNoName"));
-				}
-				else
-				{
-					line.append( nodep->mName );
-				}
-				tooltip_msg.append(line);
-				tooltip_msg.push_back('\n');
-
-				if (!nodep->mDescription.empty()
-					&& nodep->mDescription != DEFAULT_DESC)
-				{
-					tooltip_msg.append( nodep->mDescription );
-					tooltip_msg.push_back('\n');
-				}
-
-				// Line: "Owner: James Linden"
-				line.clear();
-				line.append(LLTrans::getString("TooltipOwner") + " ");
-
-				if (nodep->mValid)
-				{
-					LLUUID owner;
-					std::string name;
-					if (!nodep->mPermissions->isGroupOwned())
-					{
-						owner = nodep->mPermissions->getOwner();
-						if (LLUUID::null == owner)
-						{
-							line.append(LLTrans::getString("TooltipPublic"));
-						}
-						else if(gCacheName->getFullName(owner, name))
-						{
-							line.append(name);
-						}
-						else
-						{
-							line.append(LLTrans::getString("RetrievingData"));
-						}
-					}
-					else
-					{
-						std::string name;
-						owner = nodep->mPermissions->getGroup();
-						if (gCacheName->getGroupName(owner, name))
-						{
-							line.append(name);
-							line.append(LLTrans::getString("TooltipIsGroup"));
-						}
-						else
-						{
-							line.append(LLTrans::getString("RetrievingData"));
-						}
-					}
+					tooltip_msg.append(LLTrans::getString("TooltipNoName"));
 				}
 				else
 				{
-					line.append(LLTrans::getString("RetrievingData"));
+					tooltip_msg.append( nodep->mName );
 				}
-				tooltip_msg.append(line);
-				tooltip_msg.push_back('\n');
 
-				// Build a line describing any special properties of this object.
-				LLViewerObject *object = hover_object;
-				LLViewerObject *parent = (LLViewerObject *)object->getParent();
-
-				if (object &&
-					(object->usePhysics() ||
-					 object->flagScripted() || 
-					 object->flagHandleTouch() || (parent && parent->flagHandleTouch()) ||
-					 object->flagTakesMoney() || (parent && parent->flagTakesMoney()) ||
-					 object->flagAllowInventoryAdd() ||
-					 object->flagTemporary() ||
-					 object->flagPhantom()) )
-				{
-					line.clear();
-					if (object->flagScripted())
-					{
-						line.append(LLTrans::getString("TooltipFlagScript") + " ");
-					}
-
-					if (object->usePhysics())
-					{
-						line.append(LLTrans::getString("TooltipFlagPhysics") + " ");
-					}
-
-					if (object->flagHandleTouch() || (parent && parent->flagHandleTouch()) )
-					{
-						line.append(LLTrans::getString("TooltipFlagTouch") + " ");
-						suppressObjectHoverDisplay = FALSE;		//  Show tip
-					}
-
-					if (object->flagTakesMoney() || (parent && parent->flagTakesMoney()) )
-					{
-						line.append(LLTrans::getString("TooltipFlagL$") + " ");
-						suppressObjectHoverDisplay = FALSE;		//  Show tip
-					}
-
-					if (object->flagAllowInventoryAdd())
-					{
-						line.append(LLTrans::getString("TooltipFlagDropInventory") + " ");
-						suppressObjectHoverDisplay = FALSE;		//  Show tip
-					}
-
-					if (object->flagPhantom())
-					{
-						line.append(LLTrans::getString("TooltipFlagPhantom") + " ");
-					}
-
-					if (object->flagTemporary())
-					{
-						line.append(LLTrans::getString("TooltipFlagTemporary") + " ");
-					}
-
-					if (object->usePhysics() || 
-						object->flagHandleTouch() ||
-						(parent && parent->flagHandleTouch()) )
-					{
-						line.append(LLTrans::getString("TooltipFlagRightClickMenu") + " ");
-					}
-					tooltip_msg.append(line);
-					tooltip_msg.push_back('\n');
-				}
-
-				// Free to copy / For Sale: L$
-				line.clear();
-				if (nodep->mValid)
-				{
-					BOOL for_copy = nodep->mPermissions->getMaskEveryone() & PERM_COPY && object->permCopy();
-					BOOL for_sale = nodep->mSaleInfo.isForSale() &&
-									nodep->mPermissions->getMaskOwner() & PERM_TRANSFER &&
-									(nodep->mPermissions->getMaskOwner() & PERM_COPY ||
-									 nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY);
-					if (for_copy)
-					{
-						line.append(LLTrans::getString("TooltipFreeToCopy"));
-						suppressObjectHoverDisplay = FALSE;		//  Show tip
-					}
-					else if (for_sale)
-					{
-						LLStringUtil::format_map_t args;
-						args["[AMOUNT]"] = llformat("%d", nodep->mSaleInfo.getSalePrice());
-						line.append(LLTrans::getString("TooltipForSaleL$", args));
-						suppressObjectHoverDisplay = FALSE;		//  Show tip
-					}
-					else
-					{
-						// Nothing if not for sale
-						// line.append("Not for sale");
-					}
-				}
-				else
-				{
-					LLStringUtil::format_map_t args;
-					args["[MESSAGE]"] = LLTrans::getString("RetrievingData");
-					line.append(LLTrans::getString("TooltipForSaleMsg", args));
-				}
-				tooltip_msg.append(line);
-				tooltip_msg.push_back('\n');
+				bool needs_tip = needs_tooltip(nodep);
 
-				if (!suppressObjectHoverDisplay)
+				if (show_all_object_tips || needs_tip)
 				{
-					LLToolTipMgr::instance().show(tooltip_msg);
+					// We may select this object, so pretend it was clicked
+					mPick = mHoverPick;
+					LLToolTipMgr::instance().show(LLToolTip::Params()
+						.message(tooltip_msg)
+						.image(LLUI::getUIImage("Info"))
+						.click_callback(boost::bind(showObjectInspector, hover_object->getID()))
+						.visible_time_near(6.f)
+						.visible_time_far(3.f));
 				}
 			}
 		}
@@ -990,18 +883,23 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, std::string& msg, LLRect
 			tooltip_msg.append(line);
 			tooltip_msg.push_back('\n');
 		}
-		LLToolTipMgr::instance().show(tooltip_msg);
+
+		// trim last newlines
+		if (!tooltip_msg.empty())
+		{
+			tooltip_msg.erase(tooltip_msg.size() - 1);
+			LLToolTipMgr::instance().show(tooltip_msg);
+		}
 	}
 
 
 	return TRUE;
 }
 
-// static
-void LLToolPie::showAvatarInspector(const LLUUID& avatar_id)
+static void show_inspector(const char* inspector, const char* param, const LLUUID& source_id)
 {
 	LLSD params;
-	params["avatar_id"] = avatar_id;
+	params[param] = source_id;
 	if (LLToolTipMgr::instance().toolTipVisible())
 	{
 		LLRect rect = LLToolTipMgr::instance().getToolTipRect();
@@ -1009,7 +907,19 @@ void LLToolPie::showAvatarInspector(const LLUUID& avatar_id)
 		params["pos"]["y"] = rect.mTop;
 	}
 
-	LLFloaterReg::showInstance("inspect_avatar", params);
+	LLFloaterReg::showInstance(inspector, params);
+}
+
+// static
+void LLToolPie::showAvatarInspector(const LLUUID& avatar_id)
+{
+	show_inspector("inspect_avatar", "avatar_id", avatar_id);
+}
+
+// static
+void LLToolPie::showObjectInspector(const LLUUID& object_id)
+{
+	show_inspector("inspect_object", "object_id", object_id);
 }
 
 void LLToolPie::handleDeselect()
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index f6a67c13b17..5faedbec5aa 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -55,7 +55,7 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 	virtual BOOL		handleHover(S32 x, S32 y, MASK mask);
 	virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask);
 	virtual BOOL		handleScrollWheel(S32 x, S32 y, S32 clicks);
-	virtual BOOL		handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen);
+	virtual BOOL		handleToolTip(S32 x, S32 y, MASK mask);
 
 	virtual void		render();
 
@@ -76,7 +76,8 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 
 	static void			selectionPropertiesReceived();
 
-	static void			showAvatarInspector(const LLUUID& id);
+	static void			showAvatarInspector(const LLUUID& avatar_id);
+	static void			showObjectInspector(const LLUUID& object_id);
 private:
 	BOOL outsideSlop		(S32 x, S32 y, S32 start_x, S32 start_y);
 	BOOL pickLeftMouseDownCallback();
diff --git a/indra/newview/lltoolpipette.cpp b/indra/newview/lltoolpipette.cpp
index 9a92f2ae3fb..beebb475378 100644
--- a/indra/newview/lltoolpipette.cpp
+++ b/indra/newview/lltoolpipette.cpp
@@ -93,7 +93,7 @@ BOOL LLToolPipette::handleHover(S32 x, S32 y, MASK mask)
 	return FALSE;
 }
 
-BOOL LLToolPipette::handleToolTip(S32 x, S32 y, std::string& msg, LLRect &sticky_rect_screen)
+BOOL LLToolPipette::handleToolTip(S32 x, S32 y, MASK mask)
 {
 	if (mTooltipMsg.empty())
 	{
@@ -102,7 +102,7 @@ BOOL LLToolPipette::handleToolTip(S32 x, S32 y, std::string& msg, LLRect &sticky
 
 	LLRect sticky_rect;
 	sticky_rect.setCenterAndSize(x, y, 20, 20);
-	LLToolTipMgr::instance().show(LLToolTipParams()
+	LLToolTipMgr::instance().show(LLToolTip::Params()
 		.message(mTooltipMsg)
 		.sticky_rect(sticky_rect));
 
diff --git a/indra/newview/lltoolpipette.h b/indra/newview/lltoolpipette.h
index cce5b6ce543..f86939cfebd 100644
--- a/indra/newview/lltoolpipette.h
+++ b/indra/newview/lltoolpipette.h
@@ -56,7 +56,7 @@ class LLToolPipette
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen);
+	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask);
 
 	// Note: Don't return connection; use boost::bind + boost::signals2::trackable to disconnect slots
 	typedef boost::signals2::signal<void (const LLTextureEntry& te)> signal_t;
diff --git a/indra/newview/lluploaddialog.cpp b/indra/newview/lluploaddialog.cpp
index 153e3e73821..577b5952e5c 100644
--- a/indra/newview/lluploaddialog.cpp
+++ b/indra/newview/lluploaddialog.cpp
@@ -82,7 +82,7 @@ LLUploadDialog::LLUploadDialog( const std::string& msg)
 		LLTextBox::Params params;
 		params.name("Filename");
 		params.rect(msg_rect);
-		params.text("Filename");
+		params.initial_value("Filename");
 		params.font(font);
 		mLabelBox[line_num] = LLUICtrlFactory::create<LLTextBox> (params);
 		addChild(mLabelBox[line_num]);
diff --git a/indra/newview/llviewchildren.cpp b/indra/newview/llviewchildren.cpp
index 842ffc7f9a3..41eafa871d0 100644
--- a/indra/newview/llviewchildren.cpp
+++ b/indra/newview/llviewchildren.cpp
@@ -74,17 +74,6 @@ void LLViewChildren::setText(
 	}
 }
 
-void LLViewChildren::setWrappedText(
-	const std::string& id, const std::string& text, bool visible)
-{
-	LLTextBox* child = mParent.getChild<LLTextBox>(id);
-	if (child)
-	{
-		child->setVisible(visible);
-		child->setWrappedText(text);
-	}
-}
-
 void LLViewChildren::setBadge(const std::string& id, Badge badge, bool visible)
 {
 	LLIconCtrl* child = mParent.getChild<LLIconCtrl>(id);
diff --git a/indra/newview/llviewchildren.h b/indra/newview/llviewchildren.h
index 9263d77bdc5..6cfa535a947 100644
--- a/indra/newview/llviewchildren.h
+++ b/indra/newview/llviewchildren.h
@@ -53,8 +53,6 @@ class LLViewChildren
 	// LLTextBox
 	void setText(const std::string& id,
 		const std::string& text, bool visible = true);
-	void setWrappedText(const std::string& id,
-		const std::string& text, bool visible = true);
 
 	// LLIconCtrl
 	enum Badge { BADGE_OK, BADGE_NOTE, BADGE_WARN, BADGE_ERROR };
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 2f656479f6a..0b21f3565da 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -110,6 +110,7 @@
 #include "llfloaterwindlight.h"
 #include "llfloaterworldmap.h"
 #include "llinspectavatar.h"
+#include "llinspectobject.h"
 #include "llmediaremotectrl.h"
 #include "llmoveview.h"
 #include "llnearbychat.h"
@@ -172,8 +173,8 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>);
 	LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>);
 	LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>);
-	LLFloaterReg::add("inspect_avatar", "inspect_avatar.xml",
-		&LLFloaterReg::build<LLInspectAvatar>);
+	LLInspectAvatarUtil::registerFloater();
+	LLInspectObjectUtil::registerFloater();
 	
 	LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>);
 	LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>);
diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp
index 9f7e4d338b5..b919e3d1c18 100644
--- a/indra/newview/llviewerjoystick.cpp
+++ b/indra/newview/llviewerjoystick.cpp
@@ -282,7 +282,7 @@ void LLViewerJoystick::terminate()
 
 	ndof_libcleanup();
 	llinfos << "Terminated connection with NDOF device." << llendl;
-
+	mDriverState = JDS_UNINITIALIZED;
 #endif
 }
 
diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h
index 6be9db3313b..b565ed5696c 100644
--- a/indra/newview/llviewerjoystick.h
+++ b/indra/newview/llviewerjoystick.h
@@ -56,6 +56,8 @@ class LLViewerJoystick : public LLSingleton<LLViewerJoystick>
 	virtual ~LLViewerJoystick();
 	
 	void init(bool autoenable);
+	void terminate();
+
 	void updateStatus();
 	void scanJoystick();
 	void moveObjects(bool reset = false);
@@ -76,7 +78,6 @@ class LLViewerJoystick : public LLSingleton<LLViewerJoystick>
 	
 protected:
 	void updateEnabled(bool autoenable);
-	void terminate();
 	void handleRun(F32 inc);
 	void agentSlide(F32 inc);
 	void agentPush(F32 inc);
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 775f72d56f5..c9ba5841e93 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -193,12 +193,11 @@ class LLViewerMediaImpl
 	/*virtual*/ BOOL	handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; };
 	/*virtual*/ BOOL	handleRightMouseDown(S32 x, S32 y, MASK mask) { return FALSE; };
 	/*virtual*/ BOOL	handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; };
-	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen) { return FALSE; };
+	/*virtual*/ BOOL	handleToolTip(S32 x, S32 y, MASK mask) { return FALSE; };
 	/*virtual*/ BOOL	handleMiddleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; };
 	/*virtual*/ BOOL	handleMiddleMouseUp(S32 x, S32 y, MASK mask) {return FALSE; };
-	/*virtual*/ const std::string& getName() const { return LLStringUtil::null; };
+	/*virtual*/ std::string getName() const { return LLStringUtil::null; };
 
-	/*virtual*/ BOOL isView() const { return FALSE; };
 	/*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() { return gFocusMgr.getMouseCapture() == this; };
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 12253455a39..d95992412f5 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -80,6 +80,7 @@
 #include "lldrawpoolalpha.h"
 #include "lldrawpooltree.h"
 #include "llface.h"
+#include "llfilepicker.h"
 #include "llfirstuse.h"
 #include "llfirsttimetipmanager.h"
 #include "llfloater.h"
@@ -295,8 +296,7 @@ S32 selection_price();
 BOOL enable_take();
 void handle_take();
 bool confirm_take(const LLSD& notification, const LLSD& response);
-BOOL enable_buy(void*); 
-void handle_buy(void *);
+
 void handle_buy_object(LLSaleInfo sale_info);
 void handle_buy_contents(LLSaleInfo sale_info);
 
@@ -2490,12 +2490,10 @@ class LLObjectEnableReportAbuse : public view_listener_t
 	}
 };
 
-class LLObjectTouch : public view_listener_t
+void handle_object_touch()
 {
-	bool handleEvent(const LLSD& userdata)
-	{
 		LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-		if (!object) return true;
+		if (!object) return;
 
 		LLPickInfo pick = LLToolPie::getInstance()->getPick();
 
@@ -2534,19 +2532,20 @@ class LLObjectTouch : public view_listener_t
 		msg->addVector3("Normal", pick.mNormal);
 		msg->addVector3("Binormal", pick.mBinormal);
 		msg->sendMessage(object->getRegion()->getHost());
+}
 
-		return true;
-	}
-};
-
+bool enable_object_touch()
+{
+	LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+	return obj && obj->flagHandleTouch();
+}
 
 // One object must have touch sensor
 class LLObjectEnableTouch : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-		bool new_value = obj && obj->flagHandleTouch();
+		bool new_value = enable_object_touch();
 
 		// Update label based on the node touch name if available.
 		std::string touch_text;
@@ -2596,23 +2595,18 @@ class LLObjectOpen : public view_listener_t
 	}
 };
 */
-class LLObjectEnableOpen : public view_listener_t
+bool enable_object_open()
 {
-	bool handleEvent(const LLSD& userdata)
-	{
-		// Look for contents in root object, which is all the LLFloaterOpenObject
-		// understands.
-		LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-		bool new_value = (obj != NULL);
-		if (new_value)
-		{
-			LLViewerObject* root = obj->getRootEdit();
-			if (!root) new_value = false;
-			else new_value = root->allowOpen();
-		}
-		return new_value;
-	}
-};
+	// Look for contents in root object, which is all the LLFloaterOpenObject
+	// understands.
+	LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+	if (!obj) return false;
+
+	LLViewerObject* root = obj->getRootEdit();
+	if (!root) return false;
+
+	return root->allowOpen();
+}
 
 
 class LLViewJoystickFlycam : public view_listener_t
@@ -2666,52 +2660,50 @@ class LLObjectBuild : public view_listener_t
 	}
 };
 
-class LLObjectEdit : public view_listener_t
+
+void handle_object_edit()
 {
-	bool handleEvent(const LLSD& userdata)
+	LLViewerParcelMgr::getInstance()->deselectLand();
+
+	if (gAgent.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit())
 	{
-		LLViewerParcelMgr::getInstance()->deselectLand();
+		LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 
-		if (gAgent.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit())
+		if (selection->getSelectType() == SELECT_TYPE_HUD || !gSavedSettings.getBOOL("EditCameraMovement"))
 		{
-			LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
-
-			if (selection->getSelectType() == SELECT_TYPE_HUD || !gSavedSettings.getBOOL("EditCameraMovement"))
-			{
-				// always freeze camera in space, even if camera doesn't move
-				// so, for example, follow cam scripts can't affect you when in build mode
-				gAgent.setFocusGlobal(gAgent.calcFocusPositionTargetGlobal(), LLUUID::null);
-				gAgent.setFocusOnAvatar(FALSE, ANIMATE);
-			}
-			else
+			// always freeze camera in space, even if camera doesn't move
+			// so, for example, follow cam scripts can't affect you when in build mode
+			gAgent.setFocusGlobal(gAgent.calcFocusPositionTargetGlobal(), LLUUID::null);
+			gAgent.setFocusOnAvatar(FALSE, ANIMATE);
+		}
+		else
+		{
+			gAgent.setFocusOnAvatar(FALSE, ANIMATE);
+			LLViewerObject* selected_objectp = selection->getFirstRootObject();
+			if (selected_objectp)
 			{
-				gAgent.setFocusOnAvatar(FALSE, ANIMATE);
-				LLViewerObject* selected_objectp = selection->getFirstRootObject();
-				if (selected_objectp)
-				{
-				// zoom in on object center instead of where we clicked, as we need to see the manipulator handles
-					gAgent.setFocusGlobal(selected_objectp->getPositionGlobal(), selected_objectp->getID());
-				gAgent.cameraZoomIn(0.666f);
-				gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD );
-				gViewerWindow->moveCursorToCenter();
+			  // zoom in on object center instead of where we clicked, as we need to see the manipulator handles
+			  gAgent.setFocusGlobal(selected_objectp->getPositionGlobal(), selected_objectp->getID());
+			  gAgent.cameraZoomIn(0.666f);
+			  gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD );
+			  gViewerWindow->moveCursorToCenter();
 			}
 		}
-		}
-
-		LLFloaterReg::showInstance("build");
-	
-		LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
-		gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() );
-
-		LLViewerJoystick::getInstance()->moveObjects(true);
-		LLViewerJoystick::getInstance()->setNeedsReset(true);
-
-		// Could be first use
-		LLFirstUse::useBuild();
-		return true;
 	}
-};
-
+	
+	LLFloaterReg::showInstance("build");
+	
+	LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+	gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() );
+	
+	LLViewerJoystick::getInstance()->moveObjects(true);
+	LLViewerJoystick::getInstance()->setNeedsReset(true);
+	
+	// Could be first use
+	LLFirstUse::useBuild();
+	return;
+	
+}
 //---------------------------------------------------------------------------
 // Land pie menu
 //---------------------------------------------------------------------------
@@ -2795,24 +2787,21 @@ BOOL enable_object_build(void*)
 	return can_build;
 }
 
-class LLEnableEdit : public view_listener_t
+bool enable_object_edit()
 {
-	bool handleEvent(const LLSD& userdata)
+	// *HACK:  The new "prelude" Help Islands have a build sandbox area,
+	// so users need the Edit and Create pie menu options when they are
+	// there.  Eventually this needs to be replaced with code that only 
+	// lets you edit objects if you have permission to do so (edit perms,
+	// group edit, god).  See also lltoolbar.cpp.  JC
+	bool enable = true;
+	if (gAgent.inPrelude())
 	{
-		// *HACK:  The new "prelude" Help Islands have a build sandbox area,
-		// so users need the Edit and Create pie menu options when they are
-		// there.  Eventually this needs to be replaced with code that only 
-		// lets you edit objects if you have permission to do so (edit perms,
-		// group edit, god).  See also lltoolbar.cpp.  JC
-		bool enable = true;
-		if (gAgent.inPrelude())
-		{
-			enable = LLViewerParcelMgr::getInstance()->agentCanBuild()
-				|| LLSelectMgr::getInstance()->getSelection()->isAttachment();
-		}
-		return enable;
+		enable = LLViewerParcelMgr::getInstance()->agentCanBuild()
+			|| LLSelectMgr::getInstance()->getSelection()->isAttachment();
 	}
-};
+	return enable;
+}
 
 class LLSelfRemoveAllAttachments : public view_listener_t
 {
@@ -2866,27 +2855,24 @@ BOOL enable_has_attachments(void*)
 //	}
 //}
 
-class LLObjectEnableMute : public view_listener_t
+bool enable_object_mute()
 {
-	bool handleEvent(const LLSD& userdata)
+	LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+	bool new_value = (object != NULL);
+	if (new_value)
 	{
-		LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-		bool new_value = (object != NULL);
-		if (new_value)
+		LLVOAvatar* avatar = find_avatar_from_object(object); 
+		if (avatar)
 		{
-			LLVOAvatar* avatar = find_avatar_from_object(object); 
-			if (avatar)
-			{
-				// It's an avatar
-				LLNameValue *lastname = avatar->getNVPair("LastName");
-				BOOL is_linden = lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden");
-				BOOL is_self = avatar->isSelf();
-				new_value = !is_linden && !is_self;
-			}
+			// It's an avatar
+			LLNameValue *lastname = avatar->getNVPair("LastName");
+			BOOL is_linden = lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden");
+			BOOL is_self = avatar->isSelf();
+			new_value = !is_linden && !is_self;
 		}
-		return new_value;
 	}
-};
+	return new_value;
+}
 
 class LLObjectMute : public view_listener_t
 {
@@ -3345,36 +3331,29 @@ void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm
 	string.append(buffer);
 }
 
-BOOL enable_buy(void*)
+bool enable_buy_object()
 {
     // In order to buy, there must only be 1 purchaseable object in
     // the selection manger.
-	if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return FALSE;
+	if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false;
     LLViewerObject* obj = NULL;
     LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
 	if(node)
     {
         obj = node->getObject();
-        if(!obj) return FALSE;
+        if(!obj) return false;
 
-		if(node->mSaleInfo.isForSale() && node->mPermissions->getMaskOwner() & PERM_TRANSFER &&
-			(node->mPermissions->getMaskOwner() & PERM_COPY || node->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY))
+		if( for_sale_selection(node) )
 		{
-			if(obj->permAnyOwner()) return TRUE;
+			// *NOTE: Is this needed?  This checks to see if anyone owns the
+			// object, dating back to when we had "public" objects owned by
+			// no one.  JC
+			if(obj->permAnyOwner()) return true;
 		}
     }
-	return FALSE;
+	return false;
 }
 
-class LLObjectEnableBuy : public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		bool new_value = enable_buy(NULL);
-		return new_value;
-	}
-};
-
 // Note: This will only work if the selected object's data has been
 // received by the viewer and cached in the selection manager.
 void handle_buy_object(LLSaleInfo sale_info)
@@ -3717,20 +3696,35 @@ class LLEditEnableCustomizeAvatar : public view_listener_t
 	}
 };
 
+bool enable_sit_object()
+{
+	LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+	if (object && object->getPCode() == LL_PCODE_VOLUME)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+
 // only works on pie menu
-bool handle_sit_or_stand()
+void handle_object_sit_or_stand()
 {
 	LLPickInfo pick = LLToolPie::getInstance()->getPick();
 	LLViewerObject *object = pick.getObject();;
 	if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
 	{
-		return true;
+		return;
 	}
 
 	if (sitting_on_selection())
 	{
 		gAgent.standUp();
-		return true;
+		return;
 	}
 
 	// get object selection offset 
@@ -3748,17 +3742,8 @@ bool handle_sit_or_stand()
 
 		object->getRegion()->sendReliableMessage();
 	}
-	return true;
 }
 
-class LLObjectSitOrStand : public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		return handle_sit_or_stand();
-	}
-};
-
 void near_sit_down_point(BOOL success, void *)
 {
 	if (success)
@@ -4228,18 +4213,14 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
 	}
 }
 
-class LLToolsTakeCopy : public view_listener_t
+void handle_take_copy()
 {
-	bool handleEvent(const LLSD& userdata)
-	{
-		if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
-
-		const LLUUID& category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_OBJECT);
-		derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
+	if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
 
-		return true;
-	}
-};
+	LLUUID category_id =
+		gInventory.findCategoryUUIDForType(LLAssetType::AT_OBJECT);
+	derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
+}
 
 
 // You can return an object to its owner if it is on your land.
@@ -4485,43 +4466,50 @@ BOOL enable_take()
 	return FALSE;
 }
 
-class LLToolsBuyOrTake : public view_listener_t
+
+void handle_buy_or_take()
 {
-	bool handleEvent(const LLSD& userdata)
+	if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
 	{
-		if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
-		{
-			return true;
-		}
+		return;
+	}
 
-		if (is_selection_buy_not_take())
-		{
-			S32 total_price = selection_price();
+	if (is_selection_buy_not_take())
+	{
+		S32 total_price = selection_price();
 
-			if (total_price <= gStatusBar->getBalance() || total_price == 0)
-			{
-				handle_buy(NULL);
-			}
-			else
-			{
-				LLFloaterBuyCurrency::buyCurrency(
-					"Buying this costs", total_price);
-			}
+		if (total_price <= gStatusBar->getBalance() || total_price == 0)
+		{
+			handle_buy();
 		}
 		else
 		{
-			handle_take();
+			LLFloaterBuyCurrency::buyCurrency(
+				"Buying this costs", total_price);
 		}
-		return true;
 	}
-};
+	else
+	{
+		handle_take();
+	}
+}
+
+bool visible_buy_object()
+{
+	return is_selection_buy_not_take() && enable_buy_object();
+}
+
+bool visible_take_object()
+{
+	return !is_selection_buy_not_take() && enable_take();
+}
 
 class LLToolsEnableBuyOrTake : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
 		bool is_buy = is_selection_buy_not_take();
-		bool new_value = is_buy ? enable_buy(NULL) : enable_take();
+		bool new_value = is_buy ? enable_buy_object() : enable_take();
 
 		// Update label
 		std::string label;
@@ -4632,7 +4620,7 @@ void show_buy_currency(const char* extra)
 	LLNotifications::instance().add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency);
 }
 
-void handle_buy(void*)
+void handle_buy()
 {
 	if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
 
@@ -4650,14 +4638,20 @@ void handle_buy(void*)
 	}
 }
 
-class LLObjectBuy : public view_listener_t
+bool anyone_copy_selection(LLSelectNode* nodep)
 {
-	bool handleEvent(const LLSD& userdata)
-	{
-		handle_buy(NULL);
-		return true;
-	}
-};
+	bool perm_copy = (bool)(nodep->getObject()->permCopy());
+	bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY);
+	return perm_copy && all_copy;
+}
+
+bool for_sale_selection(LLSelectNode* nodep)
+{
+	return nodep->mSaleInfo.isForSale()
+		&& nodep->mPermissions->getMaskOwner() & PERM_TRANSFER
+		&& (nodep->mPermissions->getMaskOwner() & PERM_COPY
+			|| nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY);
+}
 
 BOOL sitting_on_selection()
 {
@@ -4985,28 +4979,24 @@ class LLEditDelete : public view_listener_t
 	}
 };
 
-class LLObjectEnableDelete : public view_listener_t
+bool enable_object_delete()
 {
-	bool handleEvent(const LLSD& userdata)
-	{
-		bool new_value = 
+	bool new_value = 
 #ifdef HACKED_GODLIKE_VIEWER
-			TRUE;
+	TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-			(!LLViewerLogin::getInstance()->isInProductionGrid()
-             && gAgent.isGodlike()) ||
+	(!LLViewerLogin::getInstance()->isInProductionGrid()
+     && gAgent.isGodlike()) ||
 # endif
-			LLSelectMgr::getInstance()->canDoDelete();
+	LLSelectMgr::getInstance()->canDoDelete();
 #endif
-		return new_value;
-	}
-};
+	return new_value;
+}
 
-class LLObjectDelete : public view_listener_t
+void handle_object_delete()
 {
-	bool handleEvent(const LLSD& userdata)
-	{
+
 		if (LLSelectMgr::getInstance())
 		{
 			LLSelectMgr::getInstance()->doDelete();
@@ -5018,9 +5008,8 @@ class LLObjectDelete : public view_listener_t
 		// When deleting an object we may not actually be done
 		// Keep selection so we know what to delete when confirmation is needed about the delete
 		gPieObject->hide();
-		return true;
-	}
-};
+		return;
+}
 
 void handle_force_delete(void*)
 {
@@ -5377,29 +5366,6 @@ class LLToolsLookAtSelection : public view_listener_t
 	}
 };
 
-void callback_invite_to_group(LLUUID group_id, LLUUID dest_id)
-{
-	std::vector<LLUUID> agent_ids;
-	agent_ids.push_back(dest_id);
-	
-	LLFloaterGroupInvite::showForGroup(group_id, &agent_ids);
-}
-
-void invite_to_group(const LLUUID& dest_id)
-{
-	LLViewerObject* dest = gObjectList.findObject(dest_id);
-	if(dest && dest->isAvatar())
-	{
-		LLFloaterGroupPicker* widget = LLFloaterReg::showTypedInstance<LLFloaterGroupPicker>("group_picker", LLSD(gAgent.getID()));
-		if (widget)
-		{
-			widget->center();
-			widget->setPowersMask(GP_MEMBER_INVITE);
-			widget->setSelectGroupCallback(boost::bind(callback_invite_to_group, _1, dest_id));
-		}
-	}
-}
-
 class LLAvatarInviteToGroup : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -5407,7 +5373,7 @@ class LLAvatarInviteToGroup : public view_listener_t
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
 		if(avatar)
 		{
-			invite_to_group(avatar->getID());
+			LLAvatarActions::inviteToGroup(avatar->getID());
 		}
 		return true;
 	}
@@ -5475,7 +5441,7 @@ bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjec
 	return false;
 }
 
-bool handle_give_money_dialog()
+void handle_give_money_dialog()
 {
 	LLNotification::Params params("BusyModePay");
 	params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection()));
@@ -5489,38 +5455,28 @@ bool handle_give_money_dialog()
 	{
 		LLNotifications::instance().forceResponse(params, 1);
 	}
-	return true;
 }
 
-class LLPayObject : public view_listener_t
+bool enable_pay_avatar()
 {
-	bool handleEvent(const LLSD& userdata)
-	{
-		return handle_give_money_dialog();
-	}
-};
+	LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+	LLVOAvatar* avatar = find_avatar_from_object(obj);
+	return (avatar != NULL);
+}
 
-class LLEnablePayObject : public view_listener_t
+bool enable_pay_object()
 {
-	bool handleEvent(const LLSD& userdata)
+	LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+	if( object )
 	{
-		LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
-		bool new_value = (avatar != NULL);
-		if (!new_value)
+		LLViewerObject *parent = (LLViewerObject *)object->getParent();
+		if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney()))
 		{
-			LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-			if( object )
-			{
-				LLViewerObject *parent = (LLViewerObject *)object->getParent();
-				if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney()))
-				{
-					new_value = true;
-				}
-			}
+			return true;
 		}
-		return new_value;
 	}
-};
+	return false;
+}
 
 class LLObjectEnableSitOrStand : public view_listener_t
 {
@@ -6157,7 +6113,7 @@ class LLAttachmentEnableDetach : public view_listener_t
 };
 
 // Used to tell if the selected object can be attached to your avatar.
-BOOL object_selected_and_point_valid(const LLSD&)
+BOOL object_selected_and_point_valid()
 {
 	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 	for (LLObjectSelection::root_iterator iter = selection->root_begin();
@@ -6187,7 +6143,7 @@ BOOL object_selected_and_point_valid(const LLSD&)
 
 BOOL object_is_wearable()
 {
-	if (!object_selected_and_point_valid(LLSD()))
+	if (!object_selected_and_point_valid())
 	{
 		return FALSE;
 	}
@@ -6209,15 +6165,6 @@ BOOL object_is_wearable()
 }
 
 
-// Also for seeing if object can be attached.  See above.
-class LLObjectEnableWear : public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		return object_selected_and_point_valid(LLSD());
-	}
-};
-
 class LLAttachmentPointFilled : public view_listener_t
 {
 	bool handleEvent(const LLSD& user_data)
@@ -6564,40 +6511,37 @@ class LLEditableSelectedMono : public view_listener_t
 	}
 };
 
-class LLToolsEnableTakeCopy : public view_listener_t
+bool enable_object_take_copy()
 {
-	bool handleEvent(const LLSD& userdata)
+	bool all_valid = false;
+	if (LLSelectMgr::getInstance())
 	{
-		bool all_valid = false;
-		if (LLSelectMgr::getInstance())
+		if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
 		{
-			if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
-			{
-			all_valid = true;
+		all_valid = true;
 #ifndef HACKED_GODLIKE_VIEWER
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-			if (LLViewerLogin::getInstance()->isInProductionGrid()
-                || !gAgent.isGodlike())
+		if (LLViewerLogin::getInstance()->isInProductionGrid()
+            || !gAgent.isGodlike())
 # endif
+		{
+			struct f : public LLSelectedObjectFunctor
 			{
-				struct f : public LLSelectedObjectFunctor
+				virtual bool apply(LLViewerObject* obj)
 				{
-					virtual bool apply(LLViewerObject* obj)
-					{
-						return (!obj->permCopy() || obj->isAttachment());
-					}
-				} func;
-				const bool firstonly = true;
-				bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
-				all_valid = !any_invalid;
-			}
-#endif // HACKED_GODLIKE_VIEWER
+					return (!obj->permCopy() || obj->isAttachment());
+				}
+			} func;
+			const bool firstonly = true;
+			bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
+			all_valid = !any_invalid;
 		}
+#endif // HACKED_GODLIKE_VIEWER
 		}
-
-		return all_valid;
 	}
-};
+
+	return all_valid;
+}
 
 
 class LLHasAsset : public LLInventoryCollectFunctor
@@ -7701,13 +7645,14 @@ void initialize_menus()
 	
 	LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar();
 	LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar();
+	LLUICtrl::VisibleCallbackRegistry::Registrar& visible = LLUICtrl::VisibleCallbackRegistry::currentRegistrar();
 	
 	// Enable God Mode
 	view_listener_t::addMenu(new LLEnableGodCustomerService(), "EnableGodCustomerService");
 
 	// Agent
 	commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
-	enable.add("Agent.emableFlying", boost::bind(&LLAgent::enableFlying));
+	enable.add("Agent.enableFlying", boost::bind(&LLAgent::enableFlying));
 
 	// File menu
 	init_menu_file();
@@ -7801,8 +7746,8 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
 	view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys");
 	view_listener_t::addMenu(new LLToolsLookAtSelection(), "Tools.LookAtSelection");
-	view_listener_t::addMenu(new LLToolsBuyOrTake(), "Tools.BuyOrTake");
-	view_listener_t::addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy");
+	commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take));
+	commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy));
 	view_listener_t::addMenu(new LLToolsSaveToInventory(), "Tools.SaveToInventory");
 	view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory");
 	view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction");
@@ -7811,7 +7756,8 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLToolsEnableLink(), "Tools.EnableLink");
 	view_listener_t::addMenu(new LLToolsEnableUnlink(), "Tools.EnableUnlink");
 	view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake");
-	view_listener_t::addMenu(new LLToolsEnableTakeCopy(), "Tools.EnableTakeCopy");
+	visible.add("Tools.VisibleTakeCopy", boost::bind(&enable_object_take_copy));
+	enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy));
 	view_listener_t::addMenu(new LLToolsEnableSaveToInventory(), "Tools.EnableSaveToInventory");
 	view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory");
 
@@ -8012,31 +7958,51 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
 	view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
 	
-	view_listener_t::addMenu(new LLObjectEnableMute(), "Avatar.EnableMute");
 	view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
 	view_listener_t::addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject");
 
 	// Object pie menu
 	view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
-	view_listener_t::addMenu(new LLObjectTouch(), "Object.Touch");
-	view_listener_t::addMenu(new LLObjectSitOrStand(), "Object.SitOrStand");
-	view_listener_t::addMenu(new LLObjectDelete(), "Object.Delete");
+	commit.add("Object.Touch", boost::bind(&handle_object_touch));
+	commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
+	visible.add("Object.EnableSit", boost::bind(&enable_sit_object));
+	commit.add("Object.Delete", boost::bind(&handle_object_delete));
 	view_listener_t::addMenu(new LLObjectAttachToAvatar(), "Object.AttachToAvatar");
 	view_listener_t::addMenu(new LLObjectReturn(), "Object.Return");
 	view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
 	view_listener_t::addMenu(new LLObjectMute(), "Object.Mute");
-	view_listener_t::addMenu(new LLObjectBuy(), "Object.Buy");
-	view_listener_t::addMenu(new LLObjectEdit(), "Object.Edit");
 
-	view_listener_t::addMenu(new LLObjectEnableOpen(), "Object.EnableOpen");
+	visible.add("Object.VisibleTake", boost::bind(&visible_take_object));
+	visible.add("Object.VisibleBuy", boost::bind(&visible_buy_object));
+
+	commit.add("Object.Buy", boost::bind(&handle_buy));
+	commit.add("Object.Edit", boost::bind(&handle_object_edit));
+	
+	commit.add("Object.Take", boost::bind(&handle_take));
+
+	enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
+	visible.add("Object.VisibleOpen", boost::bind(&enable_object_open));
+
+	enable.add("Object.EnableTouch", boost::bind(&enable_object_touch));
+	visible.add("Object.VisibleTouch", boost::bind(&enable_object_touch));
+
 	view_listener_t::addMenu(new LLObjectEnableTouch(), "Object.EnableTouch");
 	view_listener_t::addMenu(new LLObjectEnableSitOrStand(), "Object.EnableSitOrStand");
-	view_listener_t::addMenu(new LLObjectEnableDelete(), "Object.EnableDelete");
-	view_listener_t::addMenu(new LLObjectEnableWear(), "Object.EnableWear");
+	
+	enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
+	visible.add("Object.VisibleDelete", boost::bind(&enable_object_delete));
+
+	enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+	visible.add("Object.VisibleWear", boost::bind(&object_selected_and_point_valid));
+
 	view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn");
 	view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse");
-	view_listener_t::addMenu(new LLObjectEnableMute(), "Object.EnableMute");
-	view_listener_t::addMenu(new LLObjectEnableBuy(), "Object.EnableBuy");
+
+	enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute));
+	enable.add("Object.EnableMute", boost::bind(&enable_object_mute));
+	visible.add("Object.VisibleMute", boost::bind(&enable_object_mute));
+
+	enable.add("Object.EnableBuy", boost::bind(&enable_buy_object));
 
 	/*view_listener_t::addMenu(new LLObjectVisibleTouch(), "Object.VisibleTouch");
 	view_listener_t::addMenu(new LLObjectVisibleCustomTouch(), "Object.VisibleCustomTouch");
@@ -8068,10 +8034,13 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLToggleControl(), "ToggleControl");
 	view_listener_t::addMenu(new LLCheckControl(), "CheckControl");
 	view_listener_t::addMenu(new LLGoToObject(), "GoToObject");
-	view_listener_t::addMenu(new LLPayObject(), "PayObject");
+	commit.add("PayObject", boost::bind(&handle_give_money_dialog));
 
-	view_listener_t::addMenu(new LLEnablePayObject(), "EnablePayObject");
-	view_listener_t::addMenu(new LLEnableEdit(), "EnableEdit");
+	enable.add("EnablePayObject", boost::bind(&enable_pay_object));
+	visible.add("VisiblePayObject", boost::bind(&enable_pay_object));
+	enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar));
+	enable.add("EnableEdit", boost::bind(&enable_object_edit));
+	visible.add("Object.VisibleEdit", boost::bind(&enable_object_edit));
 
 	view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
 	view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected");
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index dd6aac2dd3d..75f4f08bdef 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -36,14 +36,12 @@
 #include "llmenugl.h"
 #include "llsafehandle.h"
 
-//newview includes
-#include "llfilepicker.h"
-
+class LLSD;
 class LLUICtrl;
 class LLView;
 class LLParcelSelection;
 class LLObjectSelection;
-
+class LLSelectNode;
 
 void init_menus();
 void cleanup_menus();
@@ -83,7 +81,6 @@ void confirm_replace_attachment(S32 option, void* user_data);
 void handle_detach_from_avatar(const LLSD& user_data);
 void attach_label(std::string& label, const LLSD&);
 void detach_label(std::string& label, const LLSD&);
-BOOL object_selected_and_point_valid(const LLSD&);
 void handle_detach(void*);
 BOOL enable_god_full(void* user_data);
 BOOL enable_god_liaison(void* user_data);
@@ -96,21 +93,34 @@ void exchange_callingcard(const LLUUID& dest_id);
 void handle_gestures(void*);
 void handle_sit_down(void*);
 void handle_object_build(void*);
+void handle_object_touch();
+bool enable_object_open();
+
+// Buy either contents or object itself
+void handle_buy();
+
+void handle_take_copy();
+
+// Can anyone take a free copy of the object?
+// *TODO: Move to separate file
+bool anyone_copy_selection(LLSelectNode* nodep);
+
+// Is this selected object for sale?
+// *TODO: Move to separate file
+bool for_sale_selection(LLSelectNode* nodep);
+
 void handle_save_snapshot(void *);
 void handle_toggle_flycam();
 
-bool handle_sit_or_stand();
-bool handle_give_money_dialog();
+void handle_object_sit_or_stand();
+void handle_give_money_dialog();
+bool enable_pay_object();
+bool enable_buy_object();
 bool handle_go_to();
 
 // Export to XML or Collada
 void handle_export_selected( void * );
 
-// Pass in an empty string and this function will build a string that
-// describes buyer permissions.
-class LLSaleInfo;
-class LLPermissions;
-
 class LLViewerMenuHolderGL : public LLMenuHolderGL
 {
 public:
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 390e1fe0327..2e8580907e8 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -103,6 +103,7 @@
 #include "llsidetray.h"
 #include "llstartup.h"
 #include "llsky.h"
+#include "llslurl.h"
 #include "llstatenums.h"
 #include "llstatusbar.h"
 #include "llimview.h"
@@ -168,9 +169,6 @@ extern BOOL gDebugClicks;
 // function prototypes
 void open_offer(const std::vector<LLUUID>& items, const std::string& from_name);
 bool check_offer_throttle(const std::string& from_name, bool check_only);
-void callbackCacheEstateOwnerName(const LLUUID& id,
-								  const std::string& first, const std::string& last,
-								  BOOL is_group);
 
 //inventory offer throttle globals
 LLFrameTimer gThrottleTimer;
@@ -5576,10 +5574,17 @@ void process_covenant_reply(LLMessageSystem* msg, void**)
 	LLPanelLandCovenant::updateEstateName(estate_name);
 	LLFloaterBuyLand::updateEstateName(estate_name);
 
+	std::string owner_name =
+		LLSLURL::buildCommand("agent", estate_owner_id, "inspect");
+	LLPanelEstateCovenant::updateEstateOwnerName(owner_name);
+	LLPanelLandCovenant::updateEstateOwnerName(owner_name);
+	LLFloaterBuyLand::updateEstateOwnerName(owner_name);
+
 	LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info");
 	if (panel)
 	{
 		panel->updateEstateName(estate_name);
+		panel->updateEstateOwnerName(owner_name);
 	}
 
 	// standard message, not from system
@@ -5607,8 +5612,6 @@ void process_covenant_reply(LLMessageSystem* msg, void**)
 	LLPanelLandCovenant::updateLastModified(last_modified);
 	LLFloaterBuyLand::updateLastModified(last_modified);
 
-	gCacheName->get(estate_owner_id, false, &callbackCacheEstateOwnerName);
-	
 	// load the actual covenant asset data
 	const BOOL high_priority = TRUE;
 	if (covenant_id.notNull())
@@ -5638,32 +5641,10 @@ void process_covenant_reply(LLMessageSystem* msg, void**)
 		LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id);
 		LLPanelLandCovenant::updateCovenantText(covenant_text);
 		LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id);
-		panel->updateCovenantText(covenant_text);
-	}
-}
-
-void callbackCacheEstateOwnerName(const LLUUID& id,
-								  const std::string& first, const std::string& last,
-								  BOOL is_group)
-{
-	std::string name;
-	
-	if (id.isNull())
-	{
-		name = LLTrans::getString("none_text");
-	}
-	else
-	{
-		name = first + " " + last;
-	}
-	LLPanelEstateCovenant::updateEstateOwnerName(name);
-	LLPanelLandCovenant::updateEstateOwnerName(name);
-	LLFloaterBuyLand::updateEstateOwnerName(name);
-
-	LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info");
-	if (panel)
-	{
-		panel->updateEstateOwnerName(name);
+		if (panel)
+		{
+			panel->updateCovenantText(covenant_text);
+		}
 	}
 }
 
diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h
index 275c79fd3b7..3964a56bf60 100644
--- a/indra/newview/llviewerparcelmgr.h
+++ b/indra/newview/llviewerparcelmgr.h
@@ -71,6 +71,9 @@ const F32 PARCEL_POST_HEIGHT = 0.666f;
 
 // Base class for people who want to "observe" changes in the viewer
 // parcel selection.
+
+//FIXME: this should be done by grabbing a floating parcel selection and observing changes on it, not the parcel mgr
+//--RN
 class LLParcelObserver
 {
 public:
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index ceb2698223a..b853bcb46eb 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -32,37 +32,37 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#include "llviewertexteditor.h"
+
+#include "llagent.h"
+#include "llaudioengine.h"
+#include "llavataractions.h"
+#include "llfloaterchat.h"
 #include "llfloaterreg.h"
+#include "llfloaterworldmap.h"
 #include "llfocusmgr.h"
-#include "llaudioengine.h"
-#include "llagent.h"
 #include "llinventory.h"
 #include "llinventorybridge.h"
 #include "llinventorymodel.h"
-
-#include "llviewertexteditor.h"
-
-#include "llfloaterchat.h"
-#include "llfloaterworldmap.h"
+#include "llmemorystream.h"
+#include "llmenugl.h"
+#include "llnotecard.h"
 #include "llnotify.h"
 #include "llpanelplaces.h"
 #include "llpreview.h"
-#include "llpreviewtexture.h"
 #include "llpreviewnotecard.h"
+#include "llpreviewtexture.h"
 #include "llscrollbar.h"
+#include "llscrollcontainer.h"
 #include "llsidetray.h"
 #include "lltooldraganddrop.h"
+#include "lltooltip.h"
 #include "lltrans.h"
+#include "lluictrlfactory.h"
 #include "llviewercontrol.h"
+#include "llviewerinventory.h"
 #include "llviewertexturelist.h"
 #include "llviewerwindow.h"
-#include "llviewerinventory.h"
-#include "lluictrlfactory.h"
-#include "llnotecard.h"
-#include "llmemorystream.h"
-#include "llmenugl.h"
-#include "llscrollcontainer.h"
-#include "llavataractions.h"
 
 #include "llappviewer.h" // for gPacificDaylightTime
 
@@ -142,8 +142,6 @@ class LLEmbeddedItemSegment : public LLTextSegment
 		}
 
 	}
-	//virtual S32					getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
-	//virtual void				updateLayout(const class LLTextEditor& editor);
 
 	/*virtual*/ S32				getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const 
 	{
@@ -167,7 +165,7 @@ class LLEmbeddedItemSegment : public LLTextSegment
 		}
 
 		F32 right_x;
-		mStyle->getFont()->render(mLabel, 0, image_rect.mRight + EMBEDDED_ITEM_LABEL_PADDING, draw_rect.mBottom, color, LLFontGL::LEFT, LLFontGL::BOTTOM, mHasMouseHover ? LLFontGL::UNDERLINE : 0, LLFontGL::NO_SHADOW, mLabel.length(), S32_MAX, &right_x);
+		mStyle->getFont()->render(mLabel, 0, image_rect.mRight + EMBEDDED_ITEM_LABEL_PADDING, draw_rect.mBottom, color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::UNDERLINE, LLFontGL::NO_SHADOW, mLabel.length(), S32_MAX, &right_x);
 		return right_x;
 	}
 	
@@ -176,20 +174,21 @@ class LLEmbeddedItemSegment : public LLTextSegment
 		return llmax(mImage->getHeight(), llceil(mStyle->getFont()->getLineHeight()));
 	}
 	/*virtual*/ bool			canEdit() const { return false; }
-	//virtual void				unlinkFromDocument(class LLTextEditor* editor);
-	//virtual void				linkToDocument(class LLTextEditor* editor);
 
-	virtual void				setHasMouseHover(bool hover) 
+
+	/*virtual*/ BOOL			handleHover(S32 x, S32 y, MASK mask)
 	{
-		mHasMouseHover = hover; 
+		LLUI::getWindow()->setCursor(UI_CURSOR_HAND);
+		return TRUE;
 	}
-	//virtual const LLColor4&	getColor() const;
-	//virtual void 				setColor(const LLColor4 &color);
-	//virtual void 				setStyle(const LLStyleSP &style);
-	virtual BOOL				getToolTip( std::string& msg ) const 
+	virtual BOOL				handleToolTip(S32 x, S32 y, MASK mask )
 	{ 
-		msg = mToolTip; 
-		return TRUE; 
+		if (!mToolTip.empty())
+		{
+			LLToolTipMgr::instance().show(mToolTip);
+			return TRUE;
+		}
+		return FALSE; 
 	}
 
 	/*virtual*/ const LLStyleSP		getStyle() const { return mStyle; }
@@ -562,17 +561,17 @@ void LLEmbeddedItems::markSaved()
 
 ///////////////////////////////////////////////////////////////////
 
-class LLViewerTextEditor::LLTextCmdInsertEmbeddedItem : public LLTextEditor::LLTextCmd
+class LLViewerTextEditor::TextCmdInsertEmbeddedItem : public LLTextBase::TextCmd
 {
 public:
-	LLTextCmdInsertEmbeddedItem( S32 pos, LLInventoryItem* item )
-		: LLTextCmd(pos, FALSE), 
+	TextCmdInsertEmbeddedItem( S32 pos, LLInventoryItem* item )
+		: TextCmd(pos, FALSE), 
 		  mExtCharValue(0)
 	{
 		mItem = item;
 	}
 
-	virtual BOOL execute( LLTextEditor* editor, S32* delta )
+	virtual BOOL execute( LLTextBase* editor, S32* delta )
 	{
 		LLViewerTextEditor* viewer_editor = (LLViewerTextEditor*)editor;
 		// Take this opportunity to remove any unused embedded items from this editor
@@ -587,13 +586,13 @@ class LLViewerTextEditor::LLTextCmdInsertEmbeddedItem : public LLTextEditor::LLT
 		return FALSE;
 	}
 	
-	virtual S32 undo( LLTextEditor* editor )
+	virtual S32 undo( LLTextBase* editor )
 	{
 		remove(editor, getPosition(), 1);
 		return getPosition(); 
 	}
 	
-	virtual S32 redo( LLTextEditor* editor )
+	virtual S32 redo( LLTextBase* editor )
 	{ 
 		LLWString ws;
 		ws += mExtCharValue;
@@ -635,7 +634,6 @@ LLViewerTextEditor::LLViewerTextEditor(const LLViewerTextEditor::Params& p)
 	mDragItemSaved(FALSE),
 	mInventoryCallback(new LLEmbeddedNotecardOpener)
 {
-	mParseHTML = p.allow_html;
 	mEmbeddedItemList = new LLEmbeddedItems(this);
 	mInventoryCallback->setEditor(this);
 }
@@ -673,7 +671,7 @@ BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
 			llwchar wc = 0;
 			if (mCursorPos < getLength())
 			{
-				wc = getWChar(mCursorPos);
+				wc = getWText()[mCursorPos];
 			}
 			LLInventoryItem* item_at_pos = LLEmbeddedItems::getEmbeddedItem(wc);
 			if (item_at_pos)
@@ -773,22 +771,6 @@ BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
 	return handled;
 }
 
-BOOL LLViewerTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask)
-{
-	// pop up a context menu for any Url under the cursor
-	if (handleRightMouseDownOverUrl(this, x, y))
-	{
-		return TRUE;
-	}
-
-	if (childrenHandleRightMouseDown(x, y, mask) != NULL)
-	{
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
 BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
 	BOOL	handled = FALSE;
@@ -955,7 +937,7 @@ std::string LLViewerTextEditor::getEmbeddedText()
 	LLWString outtextw;
 	for (S32 i=0; i<(S32)getWText().size(); i++)
 	{
-		llwchar wch = getWChar(i);
+		llwchar wch = getWText()[i];
 		if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
 		{
 			S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch);
@@ -998,7 +980,8 @@ std::string LLViewerTextEditor::appendTime(bool prepend_newline)
 
 	substitution["datetime"] = (S32) utc_time;
 	LLStringUtil::format (timeStr, substitution);
-	appendColoredText(timeStr, false, prepend_newline, LLColor4::grey);
+	appendText(timeStr, prepend_newline, LLStyle::Params().color(LLColor4::grey));
+	blockUndo();
 
 	return timeStr;
 }
@@ -1057,7 +1040,7 @@ BOOL LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos)
 {
 	if( pos < getLength())
 	{
-		llwchar wc = getWChar(pos);
+		llwchar wc = getWText()[pos];
 		LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem( wc );
 		if( item )
 		{
@@ -1227,7 +1210,7 @@ bool LLViewerTextEditor::onCopyToInvDialog(const LLSD& notification, const LLSD&
 // Returns change in number of characters in mWText
 S32 LLViewerTextEditor::insertEmbeddedItem( S32 pos, LLInventoryItem* item )
 {
-	return execute( new LLTextCmdInsertEmbeddedItem( pos, item ) );
+	return execute( new TextCmdInsertEmbeddedItem( pos, item ) );
 }
 
 bool LLViewerTextEditor::importStream(std::istream& str)
diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h
index 100fa343af0..ba0c40cb2ef 100644
--- a/indra/newview/llviewertexteditor.h
+++ b/indra/newview/llviewertexteditor.h
@@ -43,10 +43,7 @@ class LLViewerTextEditor : public LLTextEditor
 public:
 	struct Params : public LLInitParam::Block<Params, LLTextEditor::Params>
 	{
-		Optional<bool>	allow_html;
-
 		Params()
-		:	allow_html("allow_html", false)
 		{
 			name = "text_editor";
 		}
@@ -64,7 +61,6 @@ class LLViewerTextEditor : public LLTextEditor
 	// mousehandler overrides
 	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask);
-	virtual BOOL	handleRightMouseDown(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleHover(S32 x, S32 y, MASK mask);
 	virtual BOOL	handleDoubleClick(S32 x, S32 y, MASK mask );
 
@@ -139,7 +135,7 @@ class LLViewerTextEditor : public LLTextEditor
 	// Inner classes
 	//
 
-	class LLTextCmdInsertEmbeddedItem;
+	class TextCmdInsertEmbeddedItem;
 };
 
 #endif  // LL_VIEWERTEXTEDITOR_H
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 4a0efbaddc2..24d00cba169 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -835,9 +835,13 @@ void LLViewerWindow::handleMouseMove(LLWindow *window,  LLCoordGL pos, MASK mask
 	// Save mouse point for access during idle() and display()
 
 	LLCoordGL mouse_point(x, y);
-	saveLastMouse(mouse_point);
 
-	LLUI::resetMouseIdleTimer();
+	if (mouse_point != mCurrentMousePoint)
+	{
+		LLUI::resetMouseIdleTimer();
+	}
+
+	saveLastMouse(mouse_point);
 
 	mWindow->showCursorFromMouseMove();
 
@@ -1866,7 +1870,6 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
     if(gStatusBar)
     {
         gStatusBar->setBackgroundColor( new_bg_color );
-		gStatusBar->getChild<LLTextBox>("HealthText")->setBackgroundColor(new_bg_color);
     }
 }
 
@@ -2022,7 +2025,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	}
 
 	// hide tooltips on keypress
-	LLToolTipMgr::instance().hideToolTips();
+	LLToolTipMgr::instance().blockToolTips();
 	
 	// Explicit hack for debug menu.
 	if ((MASK_ALT & mask) &&
@@ -2609,16 +2612,16 @@ void LLViewerWindow::updateUI()
 			append_xui_tooltip(tooltip_view, tool_tip_msg);
 			screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
 			
-			LLToolTipMgr::instance().show(LLToolTipParams()
+			LLToolTipMgr::instance().show(LLToolTip::Params()
 				.message(tool_tip_msg)
 				.sticky_rect(screen_sticky_rect)
-				.width(400));
+				.max_width(400));
 		}
 		// if there is a mouse captor, nothing else gets a tooltip
 		else if (mouse_captor)
 		{
 			mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
-			tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, tool_tip_msg, screen_sticky_rect );
+			tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
 		}
 		else 
 		{
@@ -2626,20 +2629,20 @@ void LLViewerWindow::updateUI()
 			if (!tool_tip_handled && top_ctrl)
 			{
 				top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
-				tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, tool_tip_msg, screen_sticky_rect );
+				tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
 			}
 			
 			if (!tool_tip_handled)
 			{
 				local_x = x; local_y = y;
-				tool_tip_handled = mRootView->handleToolTip(local_x, local_y, tool_tip_msg, screen_sticky_rect );
+				tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
 			}
 
 			LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
 			if (!tool_tip_handled && current_tool)
 			{
 				current_tool->screenPointToLocal(x, y, &local_x, &local_y);
-				tool_tip_handled = current_tool->handleToolTip(local_x, local_y, tool_tip_msg, screen_sticky_rect );
+				tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
 			}
 		}
 	}		
@@ -2687,7 +2690,7 @@ void LLViewerWindow::updateLayout()
 				&& !suppress_toolbox									// not override in third person
 				&& LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset	// not special mode
 				&& LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset
-				&& (!captor || captor->isView())))						// not dragging
+				&& (!captor || dynamic_cast<LLView*>(captor) != NULL)))						// not dragging
 		{
 			// Force floater tools to be visible (unless minimized)
 			if (!gFloaterTools->getVisible())
@@ -2787,6 +2790,14 @@ void LLViewerWindow::updateKeyboardFocus()
 				}
 				parent = parent->getParentUICtrl();
 			}
+
+			// if we didn't find a better place to put focus, just release it
+			// hasFocus() will return true if and only if we didn't touch focus since we
+			// are only moving focus higher in the hierarchy
+			if (cur_focus->hasFocus())
+			{
+				cur_focus->setFocus(FALSE);
+			}
 		}
 		else if (cur_focus->isFocusRoot())
 		{
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 79308f7e167..30736b1e038 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -1181,7 +1181,7 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
 }
 
 
-BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen )
+BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
 {
 	LLVector3d pos_global = viewPosToGlobal(x, y);
 
@@ -1236,9 +1236,10 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, std::string& msg, LLRect& stic
 		S32 screen_x, screen_y;
 
 		localPointToScreen(x, y, &screen_x, &screen_y);
+		LLRect sticky_rect_screen;
 		sticky_rect_screen.setCenterAndSize(screen_x, screen_y, SLOP, SLOP);
 
-		LLToolTipMgr::instance().show(LLToolTipParams()
+		LLToolTipMgr::instance().show(LLToolTip::Params()
 			.message(tooltip_msg)
 			.sticky_rect(sticky_rect_screen));
 	}
diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h
index 8349d5399f5..66793f01018 100644
--- a/indra/newview/llworldmapview.h
+++ b/indra/newview/llworldmapview.h
@@ -72,7 +72,7 @@ class LLWorldMapView : public LLPanel
 	virtual BOOL	handleMouseUp(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	handleToolTip( S32 x, S32 y, std::string& msg, LLRect& sticky_rect_screen );
+	virtual BOOL	handleToolTip( S32 x, S32 y, MASK mask);
 
 	bool			checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track);
 	void			handleClick(S32 x, S32 y, MASK mask, S32* hit_type, LLUUID* id);
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 7e22e17188e..eb62c442db3 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -2,7 +2,6 @@
 <colors>
 
 	<!-- Named Colors -->
-
 	<color
 	 name="EmphasisColor"
 	 value="0.38 0.694 0.573 1" />
@@ -89,6 +88,9 @@
     <color
      name="AlertCautionTextColor"
      reference="Black" />
+    <color
+     name="AgentLinkColor"
+     reference="White" />
     <color
      name="AlertTextColor"
      value="0.58 0.66 0.84 1" />
diff --git a/indra/newview/skins/default/textures/icons/Info_Small.png b/indra/newview/skins/default/textures/icons/Info_Small.png
new file mode 100644
index 0000000000000000000000000000000000000000..81078c32dc21f54db13a4cc39a844125f46f5dec
GIT binary patch
literal 371
zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}Ea{HEjtmSN
z`?>!lvI6-E$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC?Qee
z8c`CQpH@<ySd_{TkeHcQqUYxtqEKe6XKc3e`6E@JnzNoRjv*SsQzt3%F&PTDmdj`d
zR5QMjW7y8rlqf29SaJuGRO8_!PV<8gE_m>8HEaK$sHu6@$!YR*zw}?XXJ)Rwz@a!}
z**u93uP-07?;Q1wIdb^Sq3q2ojs*A|b?K4KsX1~ZnZv7GK*loq?Cca@p1{rp-+~{d
zJ==Rjm8s@Vh;oKauf~kby+W^j4(ReWUHjbIwDX#K;VG6YSIamB<mxy-P1(nJPxGm(
ze#x)Mn4?CXuVYKXqc8U*)^GW`zr8!Y+5MyWLNzP)8%un8-Ur(-in6T#`|V`nF`&m7
NJYD@<);T3K0RVwNh^GJm

literal 0
HcmV?d00001

diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 8a6e9486a29..f106796cd93 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -137,6 +137,7 @@
   <texture name="Icon_Undock_Press" file_name="windows/Icon_Undock_Press.png" preload="false" />
 
   <texture name="Info" file_name="icons/Info.png" preload="false" />
+  <texture name="Info_Small" file_name="icons/Info_Small.png" preload="false" />
   <texture name="Info_Off" file_name="navbar/Info_Off.png" preload="false" />
   <texture name="Info_Press" file_name="navbar/Info_Press.png" preload="false" />
 
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index c9e143bf950..dc6af79db53 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -80,6 +80,7 @@
       label="Support"
       name="support_panel">
       <text_editor
+        allow_html="true" 
        follows="top|left"
        font="SansSerif"
        height="350"
@@ -127,7 +128,7 @@ Thank you to the following residents for helping to ensure that this is the best
 
 
 It is a rare mind indeed that can render the hitherto non-existent blindingly obvious. The cry 'I could have thought of that' is a very popular and misleading one, for the fact is that they didn't, and a very significant and revealing fact it is too.
--- Douglas Adams
+ -- Douglas Adams
       </text_editor>
     </panel>
     <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 5a285cdcb0c..524495d83d5 100644
--- a/indra/newview/skins/default/xui/en/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_about_land.xml
@@ -132,9 +132,6 @@ Go to World menu &gt; About Land or select another parcel to show its details.
                 Description:
             </text>
             <text_editor
-             bevel_style="in"
-             border_style="line"
-             border_thickness="1"
              follows="left|top|right"
              height="52"
              layout="topleft"
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 bd0dac5ca18..62d40bc45f4 100644
--- a/indra/newview/skins/default/xui/en/floater_buy_land.xml
+++ b/indra/newview/skins/default/xui/en/floater_buy_land.xml
@@ -483,7 +483,8 @@ sold with objects
      name="error_message"
      right="435"
      top="208"
-     width="215">
+     width="215"
+     word_wrap="true">
         Something ain&apos;t right.
     </text>
     <button
@@ -583,7 +584,8 @@ sold with objects
      left="72"
      name="land_use_reason"
      right="435"
-     width="215">
+     width="215"
+     word_wrap="true">
         You hold 1309 m² of land.
     This parcel is 512 m² of land.
     </text>
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index be1278e8cce..a233f7f0fa2 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -56,6 +56,8 @@
        layout="topleft"
        max_length="2147483647"
        name="im_text"
+       parse_highlights="true"
+       allow_html="true" 
        track_bottom="true" 
        width="195"
        word_wrap="true">
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 8b271eb41ef..bdce8fa4fcb 100644
--- a/indra/newview/skins/default/xui/en/floater_incoming_call.xml
+++ b/indra/newview/skins/default/xui/en/floater_incoming_call.xml
@@ -33,7 +33,7 @@
     <text_editor
      font="SansSerif"
      height="64"
-     hide_border="true"
+     border_visible="false"
      hide_scrollbar="true"
      layout="topleft"
      left="77"
diff --git a/indra/newview/skins/default/xui/en/floater_inspect.xml b/indra/newview/skins/default/xui/en/floater_inspect.xml
index 00b9f850adf..339604e658d 100644
--- a/indra/newview/skins/default/xui/en/floater_inspect.xml
+++ b/indra/newview/skins/default/xui/en/floater_inspect.xml
@@ -55,7 +55,7 @@
      top_pad="5"
      width="150">
 		<button.commit_callback
-		function="Inspect.OwnerProfilet" />
+		function="Inspect.OwnerProfile" />
 	</button>
     <button
      follows="left|bottom"
diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml
index 70f9c196581..dc6a02efe15 100644
--- a/indra/newview/skins/default/xui/en/floater_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_map.xml
@@ -81,7 +81,6 @@
      left="0"
      name="floater_map_east"
      right="10"
-     text="E"
      text_color="1 1 1 0.7"
      top="215">
         E
@@ -95,7 +94,6 @@
      left="0"
      name="floater_map_west"
      right="11"
-     text="W"
      text_color="1 1 1 0.7"
      top="215">
         W
@@ -109,7 +107,6 @@
      left="0"
      name="floater_map_south"
      right="10"
-     text="S"
      text_color="1 1 1 0.7"
      top="215">
         S
@@ -123,7 +120,6 @@
      left="0"
      name="floater_map_southeast"
      right="20"
-     text="SE"
      text_color="1 1 1 0.7"
      top="215">
         SE
@@ -137,7 +133,6 @@
      left="0"
      name="floater_map_northeast"
      right="20"
-     text="NE"
      text_color="1 1 1 0.7"
      top="215">
         NE
@@ -151,7 +146,6 @@
      left="0"
      name="floater_map_southwest"
      right="20"
-     text="SW"
      text_color="1 1 1 0.7"
      top="215">
         SW
@@ -165,7 +159,6 @@
      left="0"
      name="floater_map_northwest"
      right="20"
-     text="NW"
      text_color="1 1 1 0.7"
      top="215">
         NW
diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
index 78f795b0e2b..e851710ad88 100644
--- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
+++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml
@@ -39,6 +39,7 @@
 			 height="320"
              max_length="2147483647"
              name="Chat History Editor"
+             parse_highlights="true" 
              read_only="true"
              text_color="ChatHistoryTextColor"
              text_readonly_color="ChatHistoryTextColor"
diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
index 1d7b7adca2a..f90f2a81cfb 100644
--- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
+++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml
@@ -74,6 +74,7 @@
      left="4"
      max_length="65536"
      name="Notecard Editor"
+     allow_html="true" 
      handle_edit_keys_directly="true"
      tab_group="1"
      top="46"
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 c7f5a1170f1..abde4ba5fad 100644
--- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml
+++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml
@@ -33,6 +33,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif"
      font.style="BOLD"
      layout="topleft"
      left="10"
@@ -58,6 +59,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left="10"
@@ -83,6 +85,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left="10"
@@ -130,6 +133,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left="48"
@@ -155,6 +159,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left="48"
@@ -345,6 +350,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left_delta="0"
@@ -389,6 +395,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left="10"
@@ -413,6 +420,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left_delta="0"
@@ -437,6 +445,7 @@
      length="1"
      follows="left|top"
      height="16"
+     font.name="SansSerif" 
      font.style="BOLD"
      layout="topleft"
      left_delta="0"
@@ -473,6 +482,7 @@
      height="50"
      layout="topleft"
      left="10"
+     font.name="SansSerif" 
      font.style="BOLD"
      name="incomplete_title"
      top_pad="5"
diff --git a/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml b/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml
index c8b8c34f85b..2085b74a554 100644
--- a/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml
+++ b/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml
@@ -16,6 +16,7 @@
      layout="topleft"
      max_length="10000"
      name="Chat History Editor"
+     parse_highlights="true" 
      width="420"
      word_wrap="true" />
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_telehub.xml b/indra/newview/skins/default/xui/en/floater_telehub.xml
index b703b49b8b8..95de27e0ea8 100644
--- a/indra/newview/skins/default/xui/en/floater_telehub.xml
+++ b/indra/newview/skins/default/xui/en/floater_telehub.xml
@@ -88,7 +88,6 @@
     </text>
     <scroll_list
      follows="left|top"
-     font="SansSerifSmall"
      height="60"
      layout="topleft"
      left_delta="0"
diff --git a/indra/newview/skins/default/xui/en/floater_test_inspectors.xml b/indra/newview/skins/default/xui/en/floater_test_inspectors.xml
index a1a271d0eb7..2011f57d8bf 100644
--- a/indra/newview/skins/default/xui/en/floater_test_inspectors.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_inspectors.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
- can_resize="true"
+ can_resize="false"
  height="400"
  layout="topleft"
  name="floater_test_inspectors"
@@ -15,7 +15,6 @@
    width="300">
     Click to spawn an inspector:
   </text>
-  <!-- James Tester, 4 years old -->
   <button
     name="avatar_2d_btn1"
     label="Avatar 2D"
@@ -25,7 +24,7 @@
     width="100"
 	commit_callback.function="ShowAvatarInspector"
 	commit_callback.parameter="22df1dcb-810a-4975-aab9-0159958fe155" />
-	<!-- DonkeyPuncher 2008-10-1 -->
+	<!-- InspectorA Tester -->
   <button
     name="avatar_2d_btn5"
     label="Avatar 2D"
@@ -34,8 +33,8 @@
     height="20"
     width="100"
 	commit_callback.function="ShowAvatarInspector"
-	commit_callback.parameter="d5330e4e-391a-4f00-9352-b797ed2f9a97" />
-	<!-- DonkeyPuncher 2009-01-15 -->
+	commit_callback.parameter="927e68e0-e52d-4bb8-b1a9-add97a57c86a" />
+	<!-- InspectorB Tester -->
   <button
     name="avatar_2d_btn2"
     label="Avatar 2D"
@@ -44,8 +43,8 @@
     height="20"
     width="100"
 	commit_callback.function="ShowAvatarInspector"
-	commit_callback.parameter="05511655-a58a-48b6-b645-966f69fc17a7" />
-	<!-- 2009-06-14 -->
+	commit_callback.parameter="9a2300ca-e251-45dd-bb61-e33139f6e4eb" />
+	<!-- InspectorC Tester -->
   <button
     name="avatar_2d_btn3"
     label="Avatar 2D"
@@ -54,7 +53,7 @@
     height="20"
     width="100"
 	commit_callback.function="ShowAvatarInspector"
-	commit_callback.parameter="6a164b3d-7c2c-43eb-880a-0ebc0687b3ec" />
+	commit_callback.parameter="8024f082-34cc-48a3-a42e-c42f345efd74" />
 	<!-- jarvtest Bombastic 2009-10-3 -->
   <button
     name="avatar_2d_btn4"
@@ -85,7 +84,9 @@
     top_pad="10"
     left_delta="0"
     height="20"
-    width="100"/>
+    width="100"
+	  commit_callback.function="ShowObjectInspector"
+	  commit_callback.parameter="" />
   <button
     name="group_btn"
     label="Group"
@@ -107,5 +108,17 @@
     left_delta="0"
     height="20"
     width="100"/>
+  <text
+  follows="left|top"
+  font="SansSerif"
+  height="20"
+  layout="topleft"
+  left="0"
+  max_length="65536"
+  name="slurl"
+  top_pad="4"
+  width="100">
+    secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect
+  </text>
 
 </floater>
diff --git a/indra/newview/skins/default/xui/en/floater_test_textbox.xml b/indra/newview/skins/default/xui/en/floater_test_textbox.xml
index 88c001b7144..8305452c850 100644
--- a/indra/newview/skins/default/xui/en/floater_test_textbox.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_textbox.xml
@@ -122,7 +122,6 @@
      left="10"
      name="floater_map_north"
      right="30"
-     text="N"
      text_color="1 1 1 0.7"
      top="370">
         N
diff --git a/indra/newview/skins/default/xui/en/floater_test_widgets.xml b/indra/newview/skins/default/xui/en/floater_test_widgets.xml
index 6ddaa63c1d2..5a29c6a319b 100644
--- a/indra/newview/skins/default/xui/en/floater_test_widgets.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_widgets.xml
@@ -19,6 +19,8 @@
  can_resize="true"
  title="Test Floater"
  height="500"
+ min_width="850" 
+ min_height="500" 
  layout="topleft"
  name="floater_test_widgets"
  help_topic="floater_test_widgets"
@@ -39,6 +41,7 @@
   <menu_bar
    height="18"
    layout="topleft"
+   follows="top|left" 
    tool_tip="menu" 
    left="2"
    name="test_menu_bar"
@@ -74,7 +77,9 @@
   <text
    bottom="55"
    layout="topleft"
-   left="10">
+   follows="top|left"
+   left="10"
+   height="16">
     For widget list see https://wiki.lindenlab.com/wiki/Viewer:UI/Widgets
   </text>
 
@@ -82,6 +87,7 @@
   
   <button
    height="20"
+   follows="top|left" 
    label="Button"
    layout="topleft"
    left_delta="0"
@@ -91,7 +97,7 @@
    width="100" />  
   <!-- "flyout_button" is a button that can spawn a menu -->
   <flyout_button
-   follows="right|bottom"
+   follows="top|left" 
    height="20"
    label="Flyout"
    layout="topleft"
@@ -121,6 +127,7 @@
        provide input that is not a list item. -->
   <combo_box
    bottom_delta="35"
+   follows="top|left" 
    height="16"
    width="150"
    label="Combobox"
@@ -150,6 +157,7 @@
         the text. -->
   <line_editor
    height="20"
+   follows="top|left" 
    layout="topleft"
    left_delta="0"
    name="test_line_editor"
@@ -161,7 +169,7 @@
   <!-- "filter_editor" is a specialized line_editor that shows read-only
        help text until the user clicks in the widget. -->
   <filter_editor
-   follows="left|top|right"
+   follows="left|top"
    height="20"
    label="Type here to search"
    layout="topleft"
@@ -173,6 +181,7 @@
   <!-- "progress_bar" percent completed gets set in C++ code -->
   <progress_bar
    height="16"
+   follows="top|left" 
    layout="topleft"
    left_delta="0"
    name="test_progress_bar"
@@ -227,6 +236,7 @@
   <!-- "scroll_list" is a scrolling list of columnar data. -->
   <scroll_list
    bottom_delta="100"
+   follows="top|left" 
    height="80"
    draw_heading="true"
    tool_tip="scroll list" 
@@ -239,10 +249,19 @@
      dynamic_width="true"
      name="second_column"
      label="Column B"/>
+    <row>
+      <column column="first_column">short text</column>
+      <column column="second_column">more short text</column>
+    </row>
+    <row>
+      <column column="first_column">this is some longer text</column>
+      <column column="second_column">and here is some more long text</column>
+    </row>
   </scroll_list>
   <!-- "slider" is a horizontal input widget for numerical data. -->
   <slider
    bottom_delta="45"
+   follows="top|left" 
    layout="topleft"
    min_val="0"
    max_val="100"
@@ -255,22 +274,36 @@
        change the value. -->
   <spinner
    bottom_delta="35"
+   follows="top|left" 
    label="Spinner"
    layout="topleft"
    name="test_spinner" 
    tool_tip="spinner"/>
   <text
    bottom_delta="50"
+   follows="top|left" 
+   font.name="SansSerifSmall" 
    font.style = "UNDERLINE"
    layout="topleft"
    name="test_text"
    tool_tip="text">
     Text (underlined)
   </text>
+  <text
+   top_pad="10"
+   follows="top|left" 
+   layout="topleft"
+   width="60" 
+   use_ellipses="true" 
+   name="test_text"
+   tool_tip="text">
+    Truncated text here
+  </text>
   <!-- "text_editor" is a multi-line text input widget, similar to 
        textarea in HTML. -->
   <text_editor
-   height="80"
+   height="40"
+   follows="top|left|bottom" 
    layout="topleft"
    left_delta="0"
    name="test_text_editor"
@@ -279,7 +312,18 @@
    width="200">
     Text Editor
   </text_editor>
-  
+  <text
+   height="40"
+   follows="top|left|bottom"
+   layout="topleft"
+   name="test_text_editor"
+   tool_tip="text box"
+   top_pad="5"
+   width="200">
+      Text box
+with
+multiple lines
+  </text>
   <!-- And a third column -->
   
   <!-- "tab_container" is a holder for multiple panels of UI widgets.
@@ -309,7 +353,6 @@
        color="0.3 0.6 0.9 1"
        follows="left|top"
        height="90"
-       border="true"
        layout="topleft"
        left="10"
        label="Color Swatch 1"
@@ -333,7 +376,7 @@
     </panel>
     <!-- panels can also refer to other floaters or panels -->
     <panel
-	 border="true"
+	  border="true"
      filename="floater_test_checkbox.xml"
      height="225"
      label="Tab 2 - Checkbox"
diff --git a/indra/newview/skins/default/xui/en/floater_ui_preview.xml b/indra/newview/skins/default/xui/en/floater_ui_preview.xml
index 9a3d5aa1835..4ed6787f53b 100644
--- a/indra/newview/skins/default/xui/en/floater_ui_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_ui_preview.xml
@@ -17,7 +17,7 @@
      left="0"
      mouse_opaque="false"
      name="main_panel"
-     right="650"
+     right="750"
      top="0">
         <text
          type="string"
diff --git a/indra/newview/skins/default/xui/en/inspect_avatar.xml b/indra/newview/skins/default/xui/en/inspect_avatar.xml
index 2042ffedbc0..b44acebbcf7 100644
--- a/indra/newview/skins/default/xui/en/inspect_avatar.xml
+++ b/indra/newview/skins/default/xui/en/inspect_avatar.xml
@@ -1,102 +1,142 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<!-- All our XML is utf-8 encoded. -->
-
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <!--
   Not can_close / no title to avoid window chrome
   Single instance - only have one at a time, recycle it each spawn
 -->
 <floater
-  background_opaque="false"
-  background_visible="true"
-  bevel_style="in"
-  bg_alpha_color="PanelDefaultBackgroundColor"
-  can_close="false" 
-  can_minimize="false" 
-	name="inspect_avatar"
-	help_topic="inspect_avatar"
-  single_instance="true" 
-  sound_flags="0" 
-	title=""
-  visible="true"
-	width="300"
-	height="200"
-  left="0"
-  top="200"
-  >
+ bevel_style="in"
+ bg_alpha_color="PanelDefaultBackgroundColor"
+ can_close="false"
+ can_minimize="false"
+ height="190"
+ layout="topleft"
+ name="inspect_avatar"
+ single_instance="true"
+ sound_flags="0"
+ visible="true"
+ width="300">
   <!-- Allowed fields include:
 	[BORN_ON] ("12/3/2008")
 	[SL_PROFILE] (Second Life profile),
-    [RW_PROFILE] (real world profile),
+  [RW_PROFILE] (real world profile),
 	[ACCTTYPE] ("Resident"),
 	[PAYMENTINFO] ("Payment Info on File"),
-	[AGE] ("1 year 2 months") -->
-  <string name="Subtitle">
+	[AGE] ("1 year 2 months")
+   -->
+  <string
+   name="Subtitle">
 [AGE]
   </string>
-  <string name="Details">
-[ACCTTYPE], [PAYMENTINFO]
-Profile: [SL_PROFILE]
+  <string
+     name="Details">
+[ACCTTYPE][COMMA] [PAYMENTINFO]
+    </string>
+  <string
+     name="Partner">
+    Partner: [PARTNER]
   </string>
   <text
-      top="180" left="10" width="280" height="70" follows="left|top|right|bottom"
-      use_ellipses="true"  word_wrap="true"
-      font="SansSerifHugeBold" text_color="white"
-      mouse_opaque="true" name="user_name" >
-    Test Name
-  </text>
-  <!-- General purpose subtitle area, not sure yet what goes here -->
-  <text
-    top="155" left="10" width="150" height="20" follows="left|top|right|bottom"
-    font="SansSerifBig"
-    text_color="white"
-    mouse_opaque="true"
-    name="user_subtitle" />
-  <!-- Leave text fields blank so it doesn't flash when data arrives off the network -->
-  <text
-      top="115" left="10" width="290" height="50" follows="left|top|right|bottom"
-      font="SansSerifSmall" text_color="white" word_wrap="true"
-      mouse_opaque="true" name="user_details" />
-  <avatar_icon
-      top="185" left="230" width="60" height="60" follows="left|top|right|bottom"
-      color="1 1 1 1" enabled="true" mouse_opaque="true" name="avatar_icon"
-  />
-  <slider 
-    bottom="35" left="45" width="250" height="30" follows="top|left"
-    name="volume_slider"
-    tool_tip="Voice Volume" 
-    increment="0.05" initial_value="0.75" max_val="1" min_val="0"
-    show_text="false"
-  />
-  <button
-    bottom="40" left="10" width="32" height="16" follows="left|top|right|bottom"
-    name="mute_btn"
-    label=""
-    image_unselected="icn_speaker_dark.tga"
-    image_disabled="icn_speaker_dark.tga"
-    image_selected="icn_speaker-muted_dark.tga"
-    image_hover_selected="icn_speaker-muted_dark.tga"
-    image_disabled_selected="icn_speaker-muted_dark.tga"
-    halign="center"
-    toggle="true"
-  />
-  <button
-		bottom="10" left="10" width="110" height="20" follows="top|left"		
-    name="add_friend_btn"
-    label="Add Friend"
-		font="SansSerif"
-	/>
-  <button
-		bottom="10" left="120" width="110" height="20" follows="top|left"
-    name="view_profile_btn"
-    label="View Profile"
-		font="SansSerif"
-	/>
-  <button
-		bottom="10" left="230" width="60" height="20" follows="top|left" 
-    name="gear_btn"
-    label=""
-    image_overlay="Icon_Gear_Foreground"
-    image_overlay_alignment="center"
-    scale_image="true"
-	/>
-</floater> 
+     follows="left|top|right|bottom"
+     font="SansSerifHugeBold"
+     height="70"
+     left="10"
+     name="user_name"
+     text_color="white"
+     top="20"
+     use_ellipses="true"
+     value="Test Name"
+     width="280"
+     word_wrap="true" />
+    <text
+     follows="left|top|right|bottom"
+     font="SansSerifBig"
+     height="20"
+     left="10"
+     name="user_subtitle"
+     text_color="white"
+     top="45"
+     width="150" />
+    <!-- Leave text fields blank so it doesn't flash when data arrives off the network -->
+    <text
+     follows="left|top|right|bottom"
+     height="20"
+     left="10"
+     name="user_details"
+     text_color="white"
+     top="85"
+     width="290"
+     word_wrap="true" />
+    <text
+     follows="left|top|right|bottom"
+     height="20"
+     left="10"
+     name="user_partner"
+     text_color="white"
+     top="105"
+     width="290"
+     word_wrap="true" />
+    <avatar_icon
+     follows="left|top|right|bottom"
+     height="60"
+     left="230"
+     mouse_opaque="true"
+     name="avatar_icon" 
+     top="15"
+     width="60" />
+    <slider
+     follows="top|left"
+     height="30"
+     increment="0.05"
+     left="20"
+     max_val="0.95"
+     min_val="0.05"
+     name="volume_slider"
+     show_text="false"
+     tool_tip="Voice Volume"
+     top="125"
+     value="0.5"
+     width="240" />
+    <button
+     follows="left|top|right|bottom"
+     height="16"
+     image_disabled="icn_speaker_dark.tga"
+     image_disabled_selected="icn_speaker-muted_dark.tga"
+     image_hover_selected="icn_speaker-muted_dark.tga"
+     image_selected="icn_speaker-muted_dark.tga"
+     image_unselected="icn_speaker_dark.tga"
+     is_toggle="true"
+     left="265"
+     name="mute_btn"
+     picture_style="true"
+     top="132"
+     width="32" />
+    <button
+     follows="top|left"
+     font="SansSerif"
+     height="20"
+     label="Add Friend"
+     left="10"
+     name="add_friend_btn"
+     top_pad="10"
+     width="105" />
+    <button
+     follows="top|left"
+     font="SansSerif"
+     height="20"
+     label="View Profile"
+     left_delta="110"
+     name="view_profile_btn"
+     top_delta="0"
+     width="105" />
+    <menu_button
+     follows="top|left"
+     height="20"
+     image_overlay="windows\Icon_Gear_Foreground.png"
+     image_overlay_alignment="center"
+     menu_filename="menu_inspect_avatar_gear.xml"
+     name="gear_btn"
+     picture_style="true"
+     top_delta="0"
+     left_delta="110"
+     width="60"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/inspect_object.xml b/indra/newview/skins/default/xui/en/inspect_object.xml
new file mode 100644
index 00000000000..cc56f630b0f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/inspect_object.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!--
+  Not can_close / no title to avoid window chrome
+  Single instance - only have one at a time, recycle it each spawn
+-->
+<floater
+ bevel_style="in"
+ bg_opaque_color="MouseGray"
+ can_close="false"
+ can_minimize="false"
+ height="145"
+ layout="topleft"
+ name="inspect_object"
+ single_instance="true"
+ sound_flags="0"
+ visible="true"
+ width="300">
+  <string name="Creator">By [CREATOR]</string>
+  <string name="CreatorAndOwner">
+By [CREATOR]
+Owned by [OWNER]
+  </string>
+  <!-- *TODO: Might need to change to [AMOUNT] if icon contains "L$" -->
+  <string name="Price">L$[AMOUNT]</string>
+  <string name="PriceFree">Free!</string>
+  <string name="Touch">Touch</string>
+  <string name="Sit">Sit</string>
+  <text
+     follows="all"
+     font="SansSerifLargeBold"
+     height="20"
+     left="8"
+     name="object_name"
+     text_color="white"
+     top="8"
+     use_ellipses="true"
+     value="Test Object Name That Is Really Long"
+     width="268" />
+  <text
+   follows="all"
+   font="SansSerif"
+   height="30"
+   left="10"
+   name="object_creator"
+   top_pad="0"
+   width="280">
+By Longavatarname Johnsonlongstonnammer
+Owned by James Linden
+  </text>
+  <text
+   follows="all"
+   height="45"
+   left="100"
+   name="object_description"
+   top_pad="4"
+   width="200"
+   word_wrap="true">
+This is a really long description for an object being as how it is at least 80 characters in length and maybe more like 120 at this point. Who knows, really?
+  </text>
+  <!-- *TODO: Replace this icon -->
+  <icon
+  name="price_icon"
+  image_name="Favorite_Star_Active"
+  left="5"
+  width="16"
+  height="16"
+  top="79"
+  follows="left|top"
+  />
+  <text
+   follows="all"
+   font="SansSerifSmallBold"
+   height="45"
+   left="22"
+   name="price_text"
+   text_color="white"
+   top="80"
+   font_shadow="none"
+   width="80">
+L$300,000
+  </text>
+  <!-- Overlapping buttons for all default actions.  Show "Buy" if
+  for sale, "Sit" if can sit, etc. -->
+  <button
+     follows="top|left"
+     font="SansSerif"
+     height="23"
+     label="Buy"
+     left="10"
+     name="buy_btn"
+     top="116"
+     width="100" />
+  <button
+   follows="top|left"
+   font="SansSerif"
+   height="23"
+   label="Pay"
+   left_delta="0"
+   name="pay_btn"
+   top_delta="0"
+   width="100" />
+  <button
+   follows="top|left"
+   font="SansSerif"
+   height="23"
+   label="Take Copy"
+   left_delta="0"
+   name="take_free_copy_btn"
+   top_delta="0"
+   width="100" />
+  <button
+   follows="top|left"
+   font="SansSerifSmall"
+   height="23"
+   label="Touch"
+   left_delta="0"
+   name="touch_btn"
+   top_delta="0"
+   width="100" />
+  <button
+   follows="top|left"
+   font="SansSerif"
+   height="23"
+   label="Sit"
+   left_delta="0"
+   name="sit_btn"
+   top_delta="0"
+   width="100" />
+  <button
+   follows="top|left"
+   font="SansSerifSmall"
+   height="23"
+   label="Open"
+   left_delta="0"
+   name="open_btn"
+   top_delta="0"
+   width="100" />
+  <!-- non-overlapping buttons here -->
+  <menu_button
+     follows="top|left"
+     height="23"
+     image_overlay="Icon_Gear_Foreground"
+     image_overlay_alignment="center"
+   right="-8"
+     menu_filename="menu_inspect_object_gear.xml" 
+     name="gear_btn"
+     picture_style="true"
+   top_delta="0"
+     width="30" />
+    <button
+     follows="top|left"
+     height="22"
+     image_overlay="TabIcon_Close_Off"
+     layout="topleft"
+     name="more_info_btn"
+     picture_style="true"
+     right="-8"
+     top="7"
+     left_delta="110"
+     tab_stop="false"
+     width="20" />
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
new file mode 100644
index 00000000000..9f5b7f38136
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+         create_jump_keys="true"
+         layout="topleft"
+         mouse_opaque="false"
+         visible="false"
+         name="Gear Menu">
+  <menu_item_call
+   label="View Profile"
+   layout="topleft"
+   enabled="true" 
+   name="view_profile">
+    <menu_item_call.on_click
+     function="InspectAvatar.ViewProfile"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Add Friend"
+   layout="topleft"
+   name="add_friend">
+    <menu_item_call.on_click
+     function="InspectAvatar.AddFriend"/>
+  </menu_item_call>
+  <menu_item_call
+   label="IM"
+   layout="topleft"
+   name="im">
+    <menu_item_call.on_click
+     function="InspectAvatar.IM"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Call"
+   layout="topleft"
+   enabled="true"
+   name="call">
+  </menu_item_call>
+  <menu_item_call
+   label="Teleport"
+   layout="topleft"
+   name="teleport">
+    <menu_item_call.on_click
+     function="InspectAvatar.Teleport"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Invite to Group"
+   layout="topleft"
+   name="invite_to_group">
+    <menu_item_call.on_click
+     function="InspectAvatar.InviteToGroup"/>
+  </menu_item_call>
+  <menu_item_separator layout="topleft" />
+  <menu_item_call
+   label="Block"
+   layout="topleft"
+   name="block">
+    <menu_item_call.on_click
+     function="InspectAvatar.Block"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Report"
+   layout="topleft"
+   name="report">
+    <menu_item_call.on_click
+     function="InspectAvatar.Report"/>
+  </menu_item_call>  
+  <menu_item_call
+   label="Freeze"
+   layout="topleft"
+   name="freeze">
+    <menu_item_call.on_click
+     function="InspectAvatar.Freeze"/>
+    <menu_item_call.on_visible
+     function="InspectAvatar.VisibleGodMode"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Eject"
+   layout="topleft"
+   name="eject">
+    <menu_item_call.on_click
+     function="InspectAvatar.Eject"/>
+    <menu_item_call.on_visible
+     function="InspectAvatar.VisibleGodMode"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Debug"
+   layout="topleft"
+   name="debug">
+    <menu_item_call.on_click
+     function="InspectAvatar.Debug"/>
+    <menu_item_call.on_visible
+     function="InspectAvatar.VisibleGodMode"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Find On Map"
+   layout="topleft"
+   name="find_on_map">
+    <menu_item_call.on_click
+     function="InspectAvatar.FindOnMap"/>
+    <menu_item_call.on_visible
+     function="InspectAvatar.VisibleFindOnMap"/>
+  </menu_item_call>
+  <menu_item_call
+   enabled="false" 
+   label="Zoom In"
+   layout="topleft"
+   name="zoom_in">
+  </menu_item_call>  
+  <menu_item_call
+   label="Pay"
+   layout="topleft"
+   name="pay">
+    <menu_item_call.on_click
+     function="InspectAvatar.Pay"/>
+  </menu_item_call>
+</menu>
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml
new file mode 100644
index 00000000000..1bba8eb2644
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu
+   create_jump_keys="true"
+   layout="topleft"
+   mouse_opaque="false"
+   visible="false"
+   name="Gear Menu">
+  <menu_item_call
+   label="Touch"
+   layout="topleft"
+   enabled="true"
+   name="touch">    
+    <menu_item_call.on_click
+     function="InspectObject.Touch"/>
+    <menu_item_call.on_visible
+     function="Object.VisibleTouch" />
+  </menu_item_call>
+  <menu_item_call
+  label="Sit"
+  layout="topleft"
+  name="sit">
+    <menu_item_call.on_click
+     function="InspectObject.Sit"/>
+    <menu_item_call.on_visible
+     function="Object.EnableSit" />
+  </menu_item_call>
+  <menu_item_call
+   label="Pay"
+   layout="topleft"
+   name="pay">
+    <menu_item_call.on_click
+     function="InspectObject.Pay"/>
+    <menu_item_call.on_visible
+     function="VisiblePayObject" />
+  </menu_item_call>
+  <menu_item_call
+   label="Buy"
+   layout="topleft"
+   enabled="true" 
+   name="buy">
+    <menu_item_call.on_click
+     function="InspectObject.Buy"/>
+    <menu_item_call.on_visible
+     function="Object.VisibleBuy" />
+  </menu_item_call>
+  <menu_item_call
+   label="Take"
+   layout="topleft"
+   name="take">
+    <menu_item_call.on_click
+     function="Object.Take" />
+    <menu_item_call.on_enable
+     function="Object.VisibleTake"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Take Copy"
+   layout="topleft"
+   name="take_copy">
+    <menu_item_call.on_click
+     function="InspectObject.TakeFreeCopy"/>
+    <menu_item_call.on_visible
+      function="Tools.VisibleTakeCopy"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Open"
+   layout="topleft"
+   name="open">
+    <menu_item_call.on_click
+     function="InspectObject.Open"/>
+    <menu_item_call.on_visible
+     function="Object.VisibleOpen" />
+  </menu_item_call>
+  <menu_item_call
+   label="Edit"
+   layout="topleft"
+   name="report">
+        <menu_item_call.on_click
+         function="Object.Edit" />
+        <menu_item_call.on_enable
+         function="Object.VisibleEdit"/>
+  </menu_item_call>  
+  <menu_item_call
+   label="Wear"
+   layout="topleft"
+   name="wear">
+    <menu_item_call.on_click
+     function="Object.AttachToAvatar" />
+    <menu_item_call.on_visible
+     function="Object.VisibleWear" />
+  </menu_item_call>  
+  <menu_item_call
+   label="Report"
+   layout="topleft"
+   name="report">
+    <menu_item_call.on_click
+     function="Object.ReportAbuse" />
+  </menu_item_call>
+  <menu_item_call
+   label="Block"
+   layout="topleft"
+   name="block">
+    <menu_item_call.on_click
+     function="Object.Mute" />
+    <menu_item_call.on_visible
+     function="Object.VisibleMute" />
+  </menu_item_call>
+  <menu_item_call
+    enabled="false" 
+    label="Zoom In"
+    layout="topleft"
+   name="zoom_in">
+  </menu_item_call>    
+  <menu_item_call
+   label="Remove"
+   layout="topleft"
+   name="remove">
+      <menu_item_call.on_click
+       function="Object.Delete" />
+      <menu_item_call.on_visible
+       function="Object.VisibleDelete" />
+  </menu_item_call>
+  <menu_item_call
+   label="More Info"
+   layout="topleft"
+   name="more_info">
+    <menu_item_call.on_click
+     function="InspectObject.MoreInfo"/>
+  </menu_item_call>
+</menu>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index fe088b43be2..829c2e02d8e 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -447,7 +447,7 @@ Your default permissions may not work in older regions.
     icon="alertmodal.tga"
     name="ClickUnimplemented"
     type="alertmodal">
-This feature is yet to be implemented. 
+Sorry, not implemented yet.
   </notification>
 
   <notification
@@ -761,7 +761,7 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now?
 	name="url"
 	openexternally = "1">
 
-			http://secondlife.com/registration/
+			http://join/secondlife.com/
     </url>
     <usetemplate
      name="okcancelbuttons"
diff --git a/indra/newview/skins/default/xui/en/panel_audio_device.xml b/indra/newview/skins/default/xui/en/panel_audio_device.xml
index 5f495ef8ced..4329982209f 100644
--- a/indra/newview/skins/default/xui/en/panel_audio_device.xml
+++ b/indra/newview/skins/default/xui/en/panel_audio_device.xml
@@ -80,7 +80,7 @@
      bg_readonly_color="0 0 0 0"
      enabled="false"
      height="60"
-     hide_border="true"
+     border_visible="false"
      hide_scrollbar="true"
      layout="topleft"
      left_delta="10"
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index d5ed0c986d6..c3ae2d953ae 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -62,7 +62,6 @@
      auto_update="true"
      follows="right"
      draw_border="false"
-     halign="left"
      height="16"
      layout="topleft"
      left_pad="3"
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 0d6d8ba97d4..b13058f40a1 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_profile.xml
@@ -201,7 +201,7 @@
          type="string"
          follows="left|top"
          font="SansSerifSmall"
-	 font.style="BOLD"
+	      font.style="BOLD"
          height="15"
          layout="topleft"
          left="10"
@@ -272,7 +272,7 @@
       <text
          follows="left|top"
          font="SansSerifSmall"
-	 font.style="BOLD"
+	       font.style="BOLD"
          height="15"
          layout="topleft"
          left="10"
@@ -305,7 +305,7 @@
         <text
          follows="left|top"
          font="SansSerifSmall"
-	 font.style="BOLD"
+      	 font.style="BOLD"
          height="15"
          layout="topleft"
          left="10"
@@ -391,6 +391,7 @@
        follows="left|top"
        height="10"
        layout="topleft"
+       font="SansSerifSmall" 
        font.style="BOLD"
        left="12"
        mouse_opaque="false"
diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
index 069cf1d7bd9..999aa814b15 100644
--- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
@@ -55,7 +55,6 @@
     <scroll_list
      draw_heading="true"
      follows="top"
-     font="SansSerifSmall"
      heading_height="14"
      height="100"
      layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index c96c2960572..aeeb884036f 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -9,7 +9,7 @@
  width="800">
     <panel.string
      name="create_account_url">
-        http://secondlife.com/registration/
+        http://join.secondlife.com/
     </panel.string>
     <panel.string
      name="real_url">
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index 02d179d5032..b4212aaa34c 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -16,6 +16,10 @@
      name="payment_update_link_url">
         http://www.secondlife.com/account/billing.php?lang=en
     </string>
+    <string
+     name="partner_edit_link_url">
+        http://www.secondlife.com/account/partners.php?lang=en
+    </string>
     <string
      name="my_account_link_url"
      value="http://secondlife.com/account" />
diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml
index 9b2461db7cb..9abaf29f57b 100644
--- a/indra/newview/skins/default/xui/en/panel_progress.xml
+++ b/indra/newview/skins/default/xui/en/panel_progress.xml
@@ -82,7 +82,8 @@
                      name="progress_text"
                      text_color="LoginProgressBoxTextColor"
                      top_pad="5"
-                     width="593" />
+                     width="593"
+                     word_wrap="true"/>
                     <progress_bar
                      bottom="115"
                      color_bar="1 1 1 0.96"
@@ -100,11 +101,12 @@
                      height="100"
                      layout="topleft"
                      left="45"
-                     line_spacing="2"
+                     line_spacing.pixels="2"
                      name="message_text"
                      text_color="LoginProgressBoxTextColor"
                      top="145"
-                     width="550" />
+                     width="550"
+                     word_wrap="true"/>
                 </layout_panel>
                 <layout_panel
                  height="200"
diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml
index a3c714ce72d..765e2ae6231 100644
--- a/indra/newview/skins/default/xui/en/panel_script_ed.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml
@@ -32,8 +32,6 @@
     <text_editor
      type="string"
      length="1"
-     bevel_style="none"
-     border_style="line"
      bottom="393"
      follows="left|top|right|bottom"
      font="Monospace"
diff --git a/indra/newview/skins/default/xui/en/panel_side_tray.xml b/indra/newview/skins/default/xui/en/panel_side_tray.xml
index 418b88b7b59..d172154d49c 100644
--- a/indra/newview/skins/default/xui/en/panel_side_tray.xml
+++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml
@@ -21,7 +21,6 @@
         filename="panel_sidetray_home_tab.xml"
         label="home"
         border="true"
-        font="SansSerifBold"
       />
   </sidetray_tab>
 
@@ -44,14 +43,12 @@
         name="panel_people"
         filename="panel_people.xml"
         border="true"
-        font="SansSerifBold"
       />
       <panel
         class="panel_profile_view"
         name="panel_profile_view"
         filename="panel_profile_view.xml"
         border="true"
-        font="SansSerifBold"
       />
       <panel
         class="panel_group_info_sidetray"
@@ -107,7 +104,6 @@
         filename="panel_me_profile.xml"
         label="Me"
         border="true"
-        font="SansSerifBold"
       />
   </sidetray_tab>
 
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index f6ffd2e4ee9..07f0806ccba 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -58,7 +58,7 @@
     <text
      type="string"
      length="1"
-     disabled_color="TimeTextColor"
+     text_readonly_color="TimeTextColor"
      follows="right|bottom"
      halign="right"
      height="16"
@@ -100,9 +100,8 @@
      visible="false"
      width="16" />
     <text
-     type="string"
-     length="1"
-     disabled_color="HealthTextColor"
+      bg_visible="false"
+     text_readonly_color="HealthTextColor"
      follows="rsight|bottom"
      font_shadow="hard"
      height="16"
diff --git a/indra/newview/skins/default/xui/en/panel_world_map.xml b/indra/newview/skins/default/xui/en/panel_world_map.xml
index ee355fa95c8..9f08d3a817f 100644
--- a/indra/newview/skins/default/xui/en/panel_world_map.xml
+++ b/indra/newview/skins/default/xui/en/panel_world_map.xml
@@ -51,7 +51,6 @@
      label="N"
      layout="topleft"
      name="floater_map_north"
-     text="N"
      text_color="1 1 1 0.7">
         N
     </text>
@@ -61,7 +60,6 @@
      label="E"
      layout="topleft"
      name="floater_map_east"
-     text="E"
      text_color="1 1 1 0.7">
         E
     </text>
@@ -71,7 +69,6 @@
      label="W"
      layout="topleft"
      name="floater_map_west"
-     text="W"
      text_color="1 1 1 0.7">
         W
     </text>
@@ -81,7 +78,6 @@
      label="S"
      layout="topleft"
      name="floater_map_south"
-     text="S"
      text_color="1 1 1 0.7">
         S
     </text>
@@ -91,7 +87,6 @@
      label="SE"
      layout="topleft"
      name="floater_map_southeast"
-     text="SE"
      text_color="1 1 1 0.7">
         SE
     </text>
@@ -101,7 +96,6 @@
      label="NE"
      layout="topleft"
      name="floater_map_northeast"
-     text="NE"
      text_color="1 1 1 0.7">
         NE
     </text>
@@ -111,7 +105,6 @@
      label="SW"
      layout="topleft"
      name="floater_map_southwest"
-     text="SW"
      text_color="1 1 1 0.7">
         SW
     </text>
@@ -121,7 +114,6 @@
      label="NW"
      layout="topleft"
      name="floater_map_northwest"
-     text="NW"
      text_color="1 1 1 0.7">
         NW
     </text>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index f398cc33b57..3a5347fe122 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -15,9 +15,6 @@
 	<string name="StartupDetectingHardware">Detecting hardware...</string>
 	<string name="StartupLoading">Loading</string>
 	<string name="Fullbright">Fullbright (Legacy)</string>	
-	<string name="CacheWaiting">(Loading...)</string>
-	<string name="CacheNobody">(nobody)</string>
-	<string name="CacheNone">(none)</string>	
 	<!-- Login -->
 	<string name="LoginInProgress">Logging in. [APP_NAME] may appear frozen.  Please wait.</string>
 	<string name="LoginInProgressNoFrozen">Logging in...</string>
@@ -40,13 +37,14 @@
 	<string name="LoginDownloadingClothing">Downloading clothing...</string>
 	<string name="LoginFailedNoNetwork">Network Error: Could not establish connection, please check your network connection.</string>
 	<string name="Quit">Quit</string>
-	<string name="create_account_url">http://secondlife.com/registration/</string>
+	<string name="create_account_url">http://join.secondlife.com/</string>
 
 	<!-- Disconnection -->
 	<string name="AgentLostConnection">This region may be experiencing trouble.  Please check your connection to the Internet.</string>
 	
 	
 	<!-- Tooltip, lltooltipview.cpp -->
+	<!-- *TODO: Most of these are now unused, eliminate them -->
 	<string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar -->
 	<string name="TooltipNoName">(no name)</string> <!-- No name on an object -->
 	<string name="TooltipOwner">Owner:</string> <!-- Owner name follows -->
@@ -118,7 +116,10 @@
 	<!-- Avatar name: text shown while fetching name -->
 	<string name="AvatarNameWaiting">(waiting)</string>
 
-	<!-- Avatar name: text shown as an alternative to AvatarNameFetching, easter egg. -->
+  <!-- Avatar name: More than one avatar is selected/used here -->
+  <string name="AvatarNameMultiple">(multiple)</string>
+  
+  <!-- Avatar name: text shown as an alternative to AvatarNameFetching, easter egg. -->
 	<string name="AvatarNameHippos">(hippos)</string>
 	
 	<!-- Group name: text shown for LLUUID::null -->
@@ -1931,21 +1932,24 @@ this texture in your inventory
 	<string name="Left Pec">Left Pec</string>
 	<string name="Right Pec">Right Pec</string>	
 
-  <!-- Avatar age computation, see LLAvatarPropertiesProcessor::ageFromDate -->
-  <string name="YearsMonthsOld">[AGEYEARS][AGEMONTHS]old</string>
-  <string name="WeeksOld">[AGEWEEKS]old</string>
-  <string name="DaysOld">[AGEDAYS]old</string>
+  <!-- Avatar age computation, see LLDateUtil::ageFromDate -->
+  <string name="YearsMonthsOld">[AGEYEARS] [AGEMONTHS] old</string>
+  <string name="YearsOld">[AGEYEARS] old</string>
+  <string name="MonthsOld">[AGEMONTHS] old</string>
+  <string name="WeeksOld">[AGEWEEKS] old</string>
+  <string name="DaysOld">[AGEDAYS] old</string>
   <string name="TodayOld">Joined today</string>
   
-  <!-- Use value="" because of trailing spaces -->
-  <string name="AgeYears"  value="[YEARS] years " />
-  <string name="Age1Year"  value="1 year "/>
-  <string name="AgeMonths" value="[MONTHS] months "/>
-  <string name="Age1Month" value="1 month "/>
-  <string name="AgeWeeks"  value="[WEEKS] weeks "/>
-  <string name="Age1Week"  value="1 week "/>
-  <string name="AgeDays"   value="[DAYS] days "/>
-  <string name="Age1Day"   value="1 day "/>
+  <!-- AgeYearsA = singular, AgeYearsB = plural, see logic in
+      LLTrans::getCountString() -->
+  <string name="AgeYearsA">[COUNT] year</string>
+  <string name="AgeYearsB">[COUNT] years</string>
+  <string name="AgeMonthsA">[COUNT] month</string>
+  <string name="AgeMonthsB">[COUNT] months</string>
+  <string name="AgeWeeksA">[COUNT] week</string>
+  <string name="AgeWeeksB">[COUNT] weeks</string>
+  <string name="AgeDaysA">[COUNT] day</string>
+  <string name="AgeDaysB">[COUNT] days</string>
 
   <!-- Account types, see LLAvatarPropertiesProcessor -->
   <string name="AcctTypeResident">Resident</string>
@@ -1995,8 +1999,8 @@ this texture in your inventory
 	
 	<!-- groups -->
 	<string name="GroupsNone">none</string>
-	<string name="Group" value=" (group)" />
-	<string name="Unknown">(Unknown)</string>
+  <string name="Group" value=" (group)" />
+  <string name="Unknown">(Unknown)</string>
 	<string name="SummaryForTheWeek"    value="Summary for this week, beginning on " />
 	<string name="NextStipendDay"       value="The next stipend day is " />
 	<string name="GroupIndividualShare" value="                      Group       Individual Share" />
diff --git a/indra/newview/skins/default/xui/en/widgets/line_editor.xml b/indra/newview/skins/default/xui/en/widgets/line_editor.xml
index 8b4126952e8..546fbd9b47f 100644
--- a/indra/newview/skins/default/xui/en/widgets/line_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/line_editor.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<line_editor
-  background_image="TextField_Off"
-  background_image_disabled="TextField_Disabled"
-  background_image_focused="TextField_Active"
+<line_editor background_image="TextField_Off"
+             background_image_disabled="TextField_Disabled"
+             background_image_focused="TextField_Active"
              select_on_focus="false"
              handle_edit_keys_directly="false"
              commit_on_focus_lost="true"
diff --git a/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml b/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml
index 4f2261c9534..8ace7b96bc2 100644
--- a/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml
@@ -1,22 +1,26 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <simple_text_editor
+  allow_html="false" 
   mouse_opaque="true"
   font="SansSerifSmall"
   max_length="255" 
   embedded_items="false" 
   hide_scrollbar="false"
-  hide_border="true"
+  border_visible="false"
   word_wrap="false" 
   ignore_tab="true"
+  line_spacing.pixels="1" 
   track_bottom="false" 
   cursor_color="TextCursorColor"
   default_color="TextDefaultColor"
   text_color="TextFgColor"
   text_readonly_color="TextFgReadOnlyColor"
+  h_pad="5" 
+  v_pad="3"
+  bg_visible="true"
   bg_readonly_color="TextBgReadOnlyColor"
   bg_writeable_color="TextBgWriteableColor"
-  bg_focus_color="TextBgFocusColor"
-  link_color="HTMLLinkColor">
+  bg_focus_color="TextBgFocusColor">
   <simple_text_editor.border
     bevel_style="in"
     follows="all" />
diff --git a/indra/newview/skins/default/xui/en/widgets/text.xml b/indra/newview/skins/default/xui/en/widgets/text.xml
index 3d98cd66f96..7d78a8fa208 100644
--- a/indra/newview/skins/default/xui/en/widgets/text.xml
+++ b/indra/newview/skins/default/xui/en/widgets/text.xml
@@ -1,16 +1,20 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<text name="text_box" 
+<text allow_html="true"
+      clip_to_rect="false"
+      name="text_box" 
       font="SansSerifSmall"
       font_shadow="soft" 
       tab_stop="false" 
       halign="left" 
       hover_color="LabelSelectedColor" 
-      disabled_color="LabelDisabledColor" 
-      background_color="FloaterDefaultBackgroundColor" 
+      h_pad="-1" 
+      hide_scrollbar="true"
+      text_readonly_color="LabelDisabledColor"
+      bg_writeable_color="FloaterDefaultBackgroundColor" 
       border_color="DefaultHighlightLight"
       use_ellipses="false"
       bg_visible="false" 
-      border_drop_shadow_visible="false" 
       border_visible="false" 
       hover="false" 
-      text_color="LabelTextColor"/>
+      text_color="LabelTextColor"
+      v_pad="-1"/>
diff --git a/indra/newview/skins/default/xui/en/widgets/text_editor.xml b/indra/newview/skins/default/xui/en/widgets/text_editor.xml
index deaade04f86..23ca8ea3385 100644
--- a/indra/newview/skins/default/xui/en/widgets/text_editor.xml
+++ b/indra/newview/skins/default/xui/en/widgets/text_editor.xml
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <!-- Core parameters are in simple_text_editor.xml -->
 <text_editor
-  allow_html="false" />
+  allow_html="false"/>
diff --git a/indra/newview/skins/default/xui/en/widgets/textbase.xml b/indra/newview/skins/default/xui/en/widgets/textbase.xml
new file mode 100644
index 00000000000..c352abca3bb
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/textbase.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<textbase clip_to_rect="true"
+          h_pad="4"
+          v_pad="4"/>
diff --git a/indra/newview/skins/default/xui/nl/floater_telehub.xml b/indra/newview/skins/default/xui/nl/floater_telehub.xml
index 5a8abc208a6..8fe8e06c03a 100644
--- a/indra/newview/skins/default/xui/nl/floater_telehub.xml
+++ b/indra/newview/skins/default/xui/nl/floater_telehub.xml
@@ -17,7 +17,7 @@
 	<text name="spawn_points_text">
 		Spawnpunten (posities, niet objecten):
 	</text>
-	<scroll_list bottom_delta="-44" draw_border="true" follows="left|top" font="SansSerifSmall"
+	<scroll_list bottom_delta="-44" draw_border="true" follows="left|top"
 	     height="40" left="10" multi_select="false" name="spawn_points_list"
 	     width="230" />
 
diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp
new file mode 100644
index 00000000000..30e39a3bcf4
--- /dev/null
+++ b/indra/newview/tests/lldateutil_test.cpp
@@ -0,0 +1,159 @@
+/** 
+ * @file lldateutil_test.cpp
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "../test/lltut.h"
+
+#include "../lldateutil.h"
+
+#include "lldate.h"
+#include "llstring.h"	// LLStringUtil::format()
+#include "lltrans.h"
+#include "llui.h"
+
+#include <map>
+
+
+// Baked-in return values for getString()
+std::map< std::string, std::string > gString;
+
+// Baked-in return values for getCountString()
+// map of pairs of input xml_desc and integer count
+typedef std::pair< std::string, int > count_string_t;
+std::map< count_string_t, std::string > gCountString;
+
+std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args)
+{
+	std::string text = gString[xml_desc];
+	LLStringUtil::format(text, args);
+	return text;
+}
+
+std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count)
+{
+	return gCountString[ count_string_t(xml_desc, count) ];
+}
+
+std::string LLUI::getLanguage()
+{
+	return "en";
+}
+
+namespace tut
+{
+    struct dateutil
+    {
+		// Hard-code a "now" date so unit test doesn't change with
+		// current time.  Because server strings are in Pacific time
+		// roll this forward 8 hours to compensate.  This represents
+		// 2009-12-31T00:00:00Z UTC.
+		dateutil()
+			:	mNow(std::string("2009-12-31T08:00:00Z"))
+		{
+			// copied from strings.xml
+			gString["YearsMonthsOld"] = "[AGEYEARS] [AGEMONTHS] old";
+			gString["YearsOld"] = "[AGEYEARS] old";
+			gString["MonthsOld"] = "[AGEMONTHS] old";
+			gString["WeeksOld"] = "[AGEWEEKS] old";
+			gString["DaysOld"] = "[AGEDAYS] old";
+			gString["TodayOld"] = "Joined today";
+
+			gCountString[ count_string_t("AgeYears", 1) ]  = "1 year";
+			gCountString[ count_string_t("AgeYears", 2) ]  = "2 years";
+			gCountString[ count_string_t("AgeMonths", 1) ] = "1 month";
+			gCountString[ count_string_t("AgeMonths", 2) ] = "2 months";
+			gCountString[ count_string_t("AgeWeeks", 1) ]  = "1 week";
+			gCountString[ count_string_t("AgeWeeks", 2) ]  = "2 weeks";
+			gCountString[ count_string_t("AgeDays", 1) ]   = "1 day";
+			gCountString[ count_string_t("AgeDays", 2) ]   = "2 days";
+		}
+		LLDate mNow;
+    };
+    
+	typedef test_group<dateutil> dateutil_t;
+	typedef dateutil_t::object dateutil_object_t;
+	tut::dateutil_t tut_dateutil("dateutil");
+
+	template<> template<>
+	void dateutil_object_t::test<1>()
+	{
+		set_test_name("Years");
+		ensure_equals("years + months",
+			LLDateUtil::ageFromDate("10/30/2007", mNow),
+			"2 years 2 months old" );
+		ensure_equals("years",
+			LLDateUtil::ageFromDate("12/31/2007", mNow),
+			"2 years old" );
+		ensure_equals("single year",
+			LLDateUtil::ageFromDate("12/31/2008", mNow),
+			"1 year old" );
+		ensure_equals("single year + a bit",
+			LLDateUtil::ageFromDate("12/12/2008", mNow),
+			"1 year old" );
+    }
+
+	template<> template<>
+	void dateutil_object_t::test<2>()
+	{
+		set_test_name("Months");
+		ensure_equals("months",
+			LLDateUtil::ageFromDate("10/30/2009", mNow),
+			"2 months old" );
+		ensure_equals("single month",
+			LLDateUtil::ageFromDate("11/30/2009", mNow),
+			"1 month old" );
+	}
+
+	template<> template<>
+	void dateutil_object_t::test<3>()
+	{
+		set_test_name("Weeks");
+		ensure_equals("weeks",
+			LLDateUtil::ageFromDate("12/17/2009", mNow),
+			"2 weeks old" );
+		ensure_equals("single week",
+			LLDateUtil::ageFromDate("12/24/2009", mNow),
+			"1 week old" );
+	}
+
+	template<> template<>
+	void dateutil_object_t::test<4>()
+	{
+		set_test_name("Days");
+		ensure_equals("days",
+			LLDateUtil::ageFromDate("12/29/2009", mNow),
+			"2 days old" );
+		ensure_equals("single day",
+			LLDateUtil::ageFromDate("12/30/2009", mNow),
+			"1 day old" );
+		ensure_equals("today",
+			LLDateUtil::ageFromDate("12/31/2009", mNow),
+			"Joined today" );
+	}
+}
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index ba81c6e49e9..2f50d872eef 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -136,12 +136,9 @@ class LLTestCallback : public tut::callback
 			run_completed_(*mStream);
 		}
 		run_completed_(std::cout);
-
-		if (mFailedTests > 0)
-		{
-			exit(1);
-		}
 	}
+
+	int getFailedTests() const { return mFailedTests; }
 	
 private:
 	void run_completed_(std::ostream &stream)
@@ -340,9 +337,11 @@ int main(int argc, char **argv)
 		tut::runner.get().run_tests(test_group);
 	}
 
+	bool success = (callback.getFailedTests() == 0);
+
 	if (wait_at_exit)
 	{
-		std::cerr << "Waiting for input before exiting..." << std::endl;
+		std::cerr << "Press return to exit..." << std::endl;
 		std::cin.get();
 	}
 	
@@ -352,7 +351,7 @@ int main(int argc, char **argv)
 		delete output;
 	}
 
-	if (touch)
+	if (touch && success)
 	{
 		std::ofstream s;
 		s.open(touch);
@@ -361,5 +360,7 @@ int main(int argc, char **argv)
 	}
 	
 	apr_terminate();
-	return 0;
+	
+	int retval = (success ? 0 : 1);
+	return retval;
 }
-- 
GitLab