From be1c9a867440e4306348887ce07c88ba6cd31241 Mon Sep 17 00:00:00 2001
From: "Mark Palange (Mani)" <palange@lindenlab.com>
Date: Wed, 6 Oct 2010 16:45:45 -0700
Subject: PLAT-40 Fix changing the lang code for polish from 'da' to 'pl'
 reviewed by brad

---
 indra/newview/installers/windows/installer_template.nsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index d1cd335783..d5712f80cf 100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
@@ -52,7 +52,7 @@ LangString LanguageCode ${LANG_JAPANESE} "ja"
 LangString LanguageCode ${LANG_ITALIAN}  "it"
 LangString LanguageCode ${LANG_KOREAN}   "ko"
 LangString LanguageCode ${LANG_DUTCH}    "nl"
-LangString LanguageCode ${LANG_POLISH}   "da"
+LangString LanguageCode ${LANG_POLISH}   "pl"
 LangString LanguageCode ${LANG_PORTUGUESEBR} "pt"
 LangString LanguageCode ${LANG_SIMPCHINESE}  "zh"
 
-- 
cgit v1.2.3


From d53613b5ae7fd14da79b90b9fc65fa9938e331af Mon Sep 17 00:00:00 2001
From: Boroondas Gupte <hg@boroon.dasgupta.ch>
Date: Sat, 16 Oct 2010 17:11:47 +0200
Subject: VWR-23455: Don't download FMOD unless INSTALL_PROPRIETARY is TRUE

---
 indra/cmake/FMOD.cmake | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake
index 4582017bcb..fd9d5fe197 100755
--- a/indra/cmake/FMOD.cmake
+++ b/indra/cmake/FMOD.cmake
@@ -1,5 +1,7 @@
 # -*- cmake -*-
-include(Prebuilt)
+if (INSTALL_PROPRIETARY)
+  include(Prebuilt)
+endif (INSTALL_PROPRIETARY)
 
 set(FMOD_FIND_QUIETLY OFF)
 set(FMOD_FIND_REQUIRED OFF)
@@ -7,7 +9,9 @@ set(FMOD_FIND_REQUIRED OFF)
 if (STANDALONE)
   include(FindFMOD)
 else (STANDALONE)
-  use_prebuilt_binary(fmod)
+  if (INSTALL_PROPRIETARY)
+    use_prebuilt_binary(fmod)
+  endif (INSTALL_PROPRIETARY)
   
   if (WINDOWS)
     set(FMOD_LIBRARY fmod)
-- 
cgit v1.2.3


From ec0f2b831eab0694e333f8defb795a986f921a55 Mon Sep 17 00:00:00 2001
From: Merov Linden <merov@lindenlab.com>
Date: Mon, 18 Oct 2010 15:33:08 -0700
Subject: STORM-406: Fix for fmod inclusion in llaudio cmake

---
 indra/llaudio/CMakeLists.txt | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt
index e869b9717c..21ec622819 100644
--- a/indra/llaudio/CMakeLists.txt
+++ b/indra/llaudio/CMakeLists.txt
@@ -14,7 +14,6 @@ include(LLVFS)
 
 include_directories(
     ${LLAUDIO_INCLUDE_DIRS}
-    ${FMOD_INCLUDE_DIR}
     ${LLCOMMON_INCLUDE_DIRS}
     ${LLMATH_INCLUDE_DIRS}
     ${LLMESSAGE_INCLUDE_DIRS}
@@ -45,6 +44,10 @@ set(llaudio_HEADER_FILES
     )
 
 if (FMOD)
+    include_directories(
+        ${FMOD_INCLUDE_DIR}
+        )
+
     list(APPEND llaudio_SOURCE_FILES
          llaudioengine_fmod.cpp
          lllistener_fmod.cpp
-- 
cgit v1.2.3


From 755fdfb25fe06e35219f6bffcaf929f8dd7e1051 Mon Sep 17 00:00:00 2001
From: Merov Linden <merov@lindenlab.com>
Date: Wed, 20 Oct 2010 14:59:39 -0700
Subject: STORM-423: fix raw file association in strings.xml

---
 indra/newview/skins/default/xui/da/strings.xml | 2 +-
 indra/newview/skins/default/xui/de/strings.xml | 2 +-
 indra/newview/skins/default/xui/en/strings.xml | 2 +-
 indra/newview/skins/default/xui/es/strings.xml | 2 +-
 indra/newview/skins/default/xui/fr/strings.xml | 2 +-
 indra/newview/skins/default/xui/it/strings.xml | 2 +-
 indra/newview/skins/default/xui/ja/strings.xml | 2 +-
 indra/newview/skins/default/xui/nl/strings.xml | 2 +-
 indra/newview/skins/default/xui/pl/strings.xml | 2 +-
 indra/newview/skins/default/xui/pt/strings.xml | 2 +-
 10 files changed, 10 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml
index 9f4119e73b..afd933c7fa 100644
--- a/indra/newview/skins/default/xui/da/strings.xml
+++ b/indra/newview/skins/default/xui/da/strings.xml
@@ -774,7 +774,7 @@
 	<string name="xml_file">
 		XML Fil
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		RAW Fil
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml
index ae2991df45..afcb68f537 100644
--- a/indra/newview/skins/default/xui/de/strings.xml
+++ b/indra/newview/skins/default/xui/de/strings.xml
@@ -798,7 +798,7 @@
 	<string name="xml_file">
 		XML-Datei
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		RAW-Datei
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index bee0e4fde6..403d976350 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -338,7 +338,7 @@
 	<string name="avi_movie_file">AVI Movie File</string>
 	<string name="xaf_animation_file">XAF Anim File</string>
 	<string name="xml_file">XML File</string>
-	<string name="dot_raw_file">RAW File</string>
+	<string name="raw_file">RAW File</string>
 	<string name="compressed_image_files">Compressed Images</string>
 	<string name="load_files">Load Files</string>
 	<string name="choose_the_directory">Choose Directory</string>
diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml
index ac12b700ee..5fa3d54de2 100644
--- a/indra/newview/skins/default/xui/es/strings.xml
+++ b/indra/newview/skins/default/xui/es/strings.xml
@@ -777,7 +777,7 @@
 	<string name="xml_file">
 		Archivo XML
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		Archivo RAW
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml
index a7a766f6a6..af70048106 100644
--- a/indra/newview/skins/default/xui/fr/strings.xml
+++ b/indra/newview/skins/default/xui/fr/strings.xml
@@ -798,7 +798,7 @@
 	<string name="xml_file">
 		Fichier XML
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		Fichier RAW
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml
index 4fc0d19199..9dbfc2b79c 100644
--- a/indra/newview/skins/default/xui/it/strings.xml
+++ b/indra/newview/skins/default/xui/it/strings.xml
@@ -783,7 +783,7 @@
 	<string name="xml_file">
 		File XML
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		File RAW
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml
index 072ae6c630..92bbedaee5 100644
--- a/indra/newview/skins/default/xui/ja/strings.xml
+++ b/indra/newview/skins/default/xui/ja/strings.xml
@@ -798,7 +798,7 @@
 	<string name="xml_file">
 		XML ファイル
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		RAW ファイル
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/nl/strings.xml b/indra/newview/skins/default/xui/nl/strings.xml
index 1ee26c3f24..844945913f 100644
--- a/indra/newview/skins/default/xui/nl/strings.xml
+++ b/indra/newview/skins/default/xui/nl/strings.xml
@@ -665,7 +665,7 @@
 	<string name="xml_file">
 		XML bestand
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		RAW bestand
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml
index c9fe22f3c8..e355bdbb96 100644
--- a/indra/newview/skins/default/xui/pl/strings.xml
+++ b/indra/newview/skins/default/xui/pl/strings.xml
@@ -774,7 +774,7 @@
 	<string name="xml_file">
 		Plik XML
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		Plik RAW
 	</string>
 	<string name="compressed_image_files">
diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml
index 2247b0a76b..800ad479fc 100644
--- a/indra/newview/skins/default/xui/pt/strings.xml
+++ b/indra/newview/skins/default/xui/pt/strings.xml
@@ -777,7 +777,7 @@
 	<string name="xml_file">
 		Arquivo XML
 	</string>
-	<string name="dot_raw_file">
+	<string name="raw_file">
 		Arquivo RAW
 	</string>
 	<string name="compressed_image_files">
-- 
cgit v1.2.3


From 9c09665885783ca9a1405529942912aecca4d938 Mon Sep 17 00:00:00 2001
From: Andrew Productengine <adyukov@productengine.com>
Date: Thu, 21 Oct 2010 21:11:29 +0300
Subject: STORM-322 FIXED Fixed problem with redundant search entries shown in
 People/Groups/Roles/Members.

Bug was caused by adding members with uncached names to search results- when name was uncached, method that added ids
to member list, didn't respect the filter.

- Fixed by adding members only when their names are cached and match the filter. If name is not cached, LLCacheName::get() is
called for such user id, and when name is cached, it calls function that handles adding of user to list depending on filter.

- Added default sorting of members by name, added saving of sort order to settings.
---
 indra/newview/app_settings/settings.xml |  11 ++++
 indra/newview/llpanelgrouproles.cpp     | 107 ++++++++++++++++++++++++--------
 indra/newview/llpanelgrouproles.h       |   6 ++
 3 files changed, 97 insertions(+), 27 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 33f5482e50..3078e4275b 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -12145,5 +12145,16 @@
       <key>Value</key>
       <real>300.0</real>
     </map>
+    <key>GroupMembersSortOrder</key>
+    <map>
+      <key>Comment</key>
+      <string>The order by which group members will be sorted (name|donated|online)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string>name</string>
+    </map>
 </map>
 </llsd>
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 35f898bfa6..0d1d96eae6 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -49,6 +49,7 @@
 #include "llviewertexturelist.h"
 #include "llviewerwindow.h"
 #include "llfocusmgr.h"
+#include "llviewercontrol.h"
 
 #include "roles_constants.h"
 
@@ -742,10 +743,12 @@ LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab()
 	mHasMatch(FALSE),
 	mNumOwnerAdditions(0)
 {
+	mUdpateSessionID = LLUUID::null;
 }
 
 LLPanelGroupMembersSubTab::~LLPanelGroupMembersSubTab()
 {
+	gSavedSettings.setString("GroupMembersSortOrder", mMembersList->getSortColumnName());
 }
 
 BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
@@ -772,6 +775,17 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
 	// Show the member's profile on double click.
 	mMembersList->setDoubleClickCallback(onMemberDoubleClick, this);
 	mMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
+	
+	LLSD row;
+	row["columns"][0]["column"] = "name";
+	row["columns"][1]["column"] = "donated";
+	row["columns"][2]["column"] = "online";
+	mMembersList->addElement(row);
+	std::string order_by = gSavedSettings.getString("GroupMembersSortOrder");
+	if(!order_by.empty())
+	{
+		mMembersList->sortByColumn(order_by, TRUE);
+	}	
 
 	LLButton* button = parent->getChild<LLButton>("member_invite", recurse);
 	if ( button )
@@ -1529,6 +1543,10 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
 		mMemberProgress = gdatap->mMembers.begin();
 		mPendingMemberUpdate = TRUE;
 		mHasMatch = FALSE;
+		// Generate unique ID for current updateMembers()- see onNameCache for details.
+		// Using unique UUID is perhaps an overkill but this way we are perfectly safe
+		// from coincidences.
+		mUdpateSessionID.generate();
 	}
 	else
 	{
@@ -1556,6 +1574,59 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
 	}
 }
 
+void LLPanelGroupMembersSubTab::addMemberToList(LLUUID id, LLGroupMemberData* data)
+{
+	LLUIString donated = getString("donation_area");
+	donated.setArg("[AREA]", llformat("%d", data->getContribution()));
+
+	LLSD row;
+	row["id"] = id;
+
+	row["columns"][0]["column"] = "name";
+	// value is filled in by name list control
+
+	row["columns"][1]["column"] = "donated";
+	row["columns"][1]["value"] = donated.getString();
+
+	row["columns"][2]["column"] = "online";
+	row["columns"][2]["value"] = data->getOnlineStatus();
+	row["columns"][2]["font"] = "SANSSERIF_SMALL";
+
+	mMembersList->addElement(row);
+
+	mHasMatch = TRUE;
+}
+
+void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, const LLUUID& id)
+{
+	// Update ID is used to determine whether member whose id is passed
+	// into onNameCache() was passed after current or previous user-initiated update.
+	// This is needed to avoid probable duplication of members in list after changing filter
+	// or adding of members of another group if gets for their names were called on
+	// previous update. If this id is from get() called from older update,
+	// we do nothing.
+	if (mUdpateSessionID != update_id) return;
+	
+	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+		if (!gdatap) 
+	{
+		llwarns << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << llendl;
+		return;
+	}
+	
+	std::string fullname;
+	gCacheName->getFullName(id, fullname);
+	if (matchesSearchFilter(fullname))
+	{
+		addMemberToList(id, gdatap->mMembers[id]);
+		if(!mMembersList->getEnabled())
+		{
+			mMembersList->setEnabled(TRUE);
+		}
+	}
+	
+}
+
 void LLPanelGroupMembersSubTab::updateMembers()
 {
 	mPendingMemberUpdate = FALSE;
@@ -1580,12 +1651,13 @@ void LLPanelGroupMembersSubTab::updateMembers()
 
 	//cleanup list only for first iretation
 	if(mMemberProgress == gdatap->mMembers.begin())
+	{
 		mMembersList->deleteAllItems();
+	}
 
 
 	LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
-	LLUIString donated = getString("donation_area");
-
+	
 	S32 i = 0;
 	for( ; mMemberProgress != end && i<UPDATE_MEMBERS_PER_FRAME; 
 			++mMemberProgress, ++i)
@@ -1593,38 +1665,19 @@ void LLPanelGroupMembersSubTab::updateMembers()
 		if (!mMemberProgress->second)
 			continue;
 		// Do filtering on name if it is already in the cache.
-		bool add_member = true;
-
 		std::string fullname;
 		if (gCacheName->getFullName(mMemberProgress->first, fullname))
 		{
-			if ( !matchesSearchFilter(fullname) )
+			if (matchesSearchFilter(fullname))
 			{
-				add_member = false;
+				addMemberToList(mMemberProgress->first, mMemberProgress->second);
 			}
 		}
-
-		if (add_member)
+		else
 		{
-			donated.setArg("[AREA]", llformat("%d", mMemberProgress->second->getContribution()));
-
-			LLSD row;
-			row["id"] = (*mMemberProgress).first;
-
-			row["columns"][0]["column"] = "name";
-			// value is filled in by name list control
-
-			row["columns"][1]["column"] = "donated";
-			row["columns"][1]["value"] = donated.getString();
-
-			row["columns"][2]["column"] = "online";
-			row["columns"][2]["value"] = mMemberProgress->second->getOnlineStatus();
-			row["columns"][2]["font"] = "SANSSERIF_SMALL";
-
-			LLScrollListItem* member = mMembersList->addElement(row);
-
-			LLUUID id = member->getUUID();
-			mHasMatch = TRUE;
+			// If name is not cached, onNameCache() should be called when it is cached and add this member to list.
+			gCacheName->get(mMemberProgress->first, FALSE, boost::bind(&LLPanelGroupMembersSubTab::onNameCache,
+																	   this, mUdpateSessionID, _1));
 		}
 	}
 
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index 6a773f1ebb..270259c16f 100644
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -187,6 +187,9 @@ public:
 
 	virtual void setGroupID(const LLUUID& id);
 
+	void addMemberToList(LLUUID id, LLGroupMemberData* data);
+	void onNameCache(const LLUUID& update_id, const LLUUID& id);
+
 protected:
 	typedef std::map<LLUUID, LLRoleMemberChangeType> role_change_data_map_t;
 	typedef std::map<LLUUID, role_change_data_map_t*> member_role_changes_map_t;
@@ -207,6 +210,9 @@ protected:
 	BOOL mPendingMemberUpdate;
 	BOOL mHasMatch;
 
+	// This id is generated after each user initiated member list update(opening Roles or changing filter)
+	LLUUID mUdpateSessionID;
+
 	member_role_changes_map_t mMemberRoleChangeData;
 	U32 mNumOwnerAdditions;
 
-- 
cgit v1.2.3


From 54da19fdcfa3edadbc58a1f55a3503082e66f16e Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Fri, 22 Oct 2010 02:08:26 +0300
Subject: STORM-426 FIXED Menu button no longer looked pressed while its menu
 is displayed by another control. - LLMenuGL in menu button replaced by
 LLToggleableMenu that handles visibility change upon clicks inside specific
 button rect. - Added visibility change signal to LLToggleableMenu to update
 menu button pressed state. - Added using menu handle in LLMenuButton.

---
 indra/llui/llmenubutton.cpp                        | 100 +++++++++++++--------
 indra/llui/llmenubutton.h                          |  19 ++--
 indra/llui/lltoggleablemenu.cpp                    |  18 ++++
 indra/llui/lltoggleablemenu.h                      |   5 ++
 indra/newview/llinspectavatar.cpp                  |   5 +-
 indra/newview/llinspectobject.cpp                  |   3 +-
 indra/newview/lloutfitslist.cpp                    |   9 +-
 indra/newview/llpanellandmarks.cpp                 |   7 +-
 indra/newview/llpanellandmarks.h                   |   5 +-
 indra/newview/llpanelmaininventory.cpp             |   3 +-
 indra/newview/llpanelmaininventory.h               |   3 +-
 indra/newview/llpaneloutfitedit.cpp                |   9 +-
 indra/newview/llpaneloutfitedit.h                  |   4 +-
 indra/newview/llpanelpeople.cpp                    |   9 +-
 indra/newview/llpanelteleporthistory.cpp           |   3 +-
 indra/newview/llpanelwearing.cpp                   |  10 ++-
 .../default/xui/en/menu_add_wearable_gear.xml      |   4 +-
 .../newview/skins/default/xui/en/menu_cof_gear.xml |   4 +-
 .../skins/default/xui/en/menu_gesture_gear.xml     |   4 +-
 .../default/xui/en/menu_inspect_avatar_gear.xml    |   4 +-
 .../default/xui/en/menu_inspect_object_gear.xml    |   4 +-
 .../default/xui/en/menu_inspect_self_gear.xml      |   4 +-
 .../default/xui/en/menu_inventory_gear_default.xml |   4 +-
 .../skins/default/xui/en/menu_outfit_gear.xml      |   4 +-
 .../xui/en/menu_people_friends_view_sort.xml       |   5 +-
 .../xui/en/menu_people_groups_view_sort.xml        |   5 +-
 .../xui/en/menu_people_nearby_view_sort.xml        |   5 +-
 .../xui/en/menu_people_recent_view_sort.xml        |   5 +-
 .../default/xui/en/menu_places_gear_folder.xml     |   4 +-
 .../default/xui/en/menu_places_gear_landmark.xml   |   4 +-
 .../default/xui/en/menu_teleport_history_gear.xml  |   4 +-
 .../skins/default/xui/en/menu_wearing_gear.xml     |   4 +-
 32 files changed, 175 insertions(+), 105 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp
index c1b5efaa72..ac568a83e4 100644
--- a/indra/llui/llmenubutton.cpp
+++ b/indra/llui/llmenubutton.cpp
@@ -29,7 +29,7 @@
 #include "llmenubutton.h"
 
 // Linden library includes
-#include "llmenugl.h"
+#include "lltoggleablemenu.h"
 #include "llstring.h"
 #include "v4color.h"
 
@@ -44,22 +44,26 @@ LLMenuButton::Params::Params()
 
 LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
 :	LLButton(p),
-	mMenu(NULL),
-	mMenuVisibleLastFrame(false),
+	mIsMenuShown(false),
 	mMenuPosition(MP_BOTTOM_LEFT)
 {
 	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)
+		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+		if (!menu)
 		{
 			llwarns << "Error loading menu_button menu" << llendl;
+			return;
 		}
-	}
 
-	updateMenuOrigin();
+		menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
+
+		mMenuHandle = menu->getHandle();
+
+		updateMenuOrigin();
+	}
 }
 
 boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
@@ -69,34 +73,34 @@ boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_sign
 
 void LLMenuButton::hideMenu()
 {
-	if(!mMenu) return;
-	mMenu->setVisible(FALSE);
+	if(mMenuHandle.isDead()) return;
+
+	LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+	if (menu)
+	{
+		menu->setVisible(FALSE);
+	}
 }
 
-void LLMenuButton::setMenu(LLMenuGL* menu, EMenuPosition position /*MP_TOP_LEFT*/)
+LLToggleableMenu* LLMenuButton::getMenu()
 {
-	mMenu = menu;
-	mMenuPosition = position;
+	return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
 }
 
-void LLMenuButton::draw()
+void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/)
 {
-	//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);
-	}
+	if (!menu) return;
 
-	LLButton::draw();
+	mMenuHandle = menu->getHandle();
+	mMenuPosition = position;
 
-	setForcePressedState(false);
+	menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
 }
 
 BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
 {
+	if (mMenuHandle.isDead()) return FALSE;
+
 	if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
 	{
 		// *HACK: We emit the mouse down signal to fire the callback bound to the
@@ -107,9 +111,10 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
 		return TRUE;
 	}
 
-	if (mMenu && mMenu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
+	LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+	if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
 	{
-		mMenu->setVisible(FALSE);
+		menu->setVisible(FALSE);
 		return TRUE;
 	}
 	
@@ -119,6 +124,7 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
 BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
 {
 	LLButton::handleMouseDown(x, y, mask);
+
 	toggleMenu();
 	
 	return TRUE;
@@ -126,28 +132,38 @@ BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
 
 void LLMenuButton::toggleMenu()
 {
-    if(!mMenu) return;
+	if(mMenuHandle.isDead()) return;
+
+	LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
+	if (!menu) return;
 
-	if (mMenu->getVisible() || mMenuVisibleLastFrame)
+	// Store the button rectangle to toggle menu visibility if a mouse event
+	// occurred inside or outside the button rect.
+	menu->setButtonRect(this);
+
+	if (!menu->toggleVisibility() && mIsMenuShown)
 	{
-		mMenu->setVisible(FALSE);
+		setForcePressedState(false);
+		mIsMenuShown = false;
 	}
 	else
 	{
-		mMenu->buildDrawLabels();
-		mMenu->arrangeAndClear();
-		mMenu->updateParent(LLMenuGL::sMenuContainer);
+		menu->buildDrawLabels();
+		menu->arrangeAndClear();
+		menu->updateParent(LLMenuGL::sMenuContainer);
 
 		updateMenuOrigin();
 
-	    //mMenu->needsArrange(); //so it recalculates the visible elements
-		LLMenuGL::showPopup(getParent(), mMenu, mX, mY);
+		LLMenuGL::showPopup(getParent(), menu, mX, mY);
+
+		setForcePressedState(true);
+		mIsMenuShown = true;
 	}
 }
 
 void LLMenuButton::updateMenuOrigin()
 {
-	if (!mMenu)	return;
+	if (mMenuHandle.isDead()) return;
 
 	LLRect rect = getRect();
 
@@ -156,7 +172,7 @@ void LLMenuButton::updateMenuOrigin()
 		case MP_TOP_LEFT:
 		{
 			mX = rect.mLeft;
-			mY = rect.mTop + mMenu->getRect().getHeight();
+			mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
 			break;
 		}
 		case MP_BOTTOM_LEFT:
@@ -167,3 +183,17 @@ void LLMenuButton::updateMenuOrigin()
 		}
 	}
 }
+
+void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
+{
+	bool new_visibility = param["visibility"].asBoolean();
+	bool is_closed_by_button_click = param["closed_by_button_click"].asBoolean();
+
+	// Reset the button "pressed" state only if the menu is shown by this particular
+	// menu button (not any other control) and is not being closed by a click on the button.
+	if (!new_visibility && !is_closed_by_button_click && mIsMenuShown)
+	{
+		setForcePressedState(false);
+		mIsMenuShown = false;
+	}
+}
diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h
index 81c3592b16..9e91b9e99d 100644
--- a/indra/llui/llmenubutton.h
+++ b/indra/llui/llmenubutton.h
@@ -29,7 +29,7 @@
 
 #include "llbutton.h"
 
-class LLMenuGL;
+class LLToggleableMenu;
 
 class LLMenuButton
 : public LLButton
@@ -52,14 +52,13 @@ public:
 	
 	boost::signals2::connection setMouseDownCallback( const mouse_signal_t::slot_type& cb );
 
-	/*virtual*/ void draw();
 	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
 	/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
 
 	void hideMenu();
 
-	LLMenuGL* getMenu() { return mMenu; }
-	void setMenu(LLMenuGL* menu, EMenuPosition position = MP_TOP_LEFT);
+	LLToggleableMenu* getMenu();
+	void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT);
 
 	void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
 
@@ -70,12 +69,14 @@ protected:
 	void toggleMenu();
 	void updateMenuOrigin();
 
+	void onMenuVisibilityChange(const LLSD& param);
+
 private:
-	LLMenuGL*		mMenu;
-	bool 			mMenuVisibleLastFrame;
-	EMenuPosition	mMenuPosition;
-	S32				mX;
-	S32				mY;
+	LLHandle<LLView>		mMenuHandle;
+	bool					mIsMenuShown;
+	EMenuPosition			mMenuPosition;
+	S32						mX;
+	S32						mY;
 };
 
 
diff --git a/indra/llui/lltoggleablemenu.cpp b/indra/llui/lltoggleablemenu.cpp
index 0eb2dc1387..d29260750f 100644
--- a/indra/llui/lltoggleablemenu.cpp
+++ b/indra/llui/lltoggleablemenu.cpp
@@ -35,10 +35,22 @@ static LLDefaultChildRegistry::Register<LLToggleableMenu> r("toggleable_menu");
 LLToggleableMenu::LLToggleableMenu(const LLToggleableMenu::Params& p)
 :	LLMenuGL(p),
 	mButtonRect(),
+	mVisibilityChangeSignal(NULL),
 	mClosedByButtonClick(false)
 {
 }
 
+LLToggleableMenu::~LLToggleableMenu()
+{
+	delete mVisibilityChangeSignal;
+}
+
+boost::signals2::connection LLToggleableMenu::setVisibilityChangeCallback(const commit_signal_t::slot_type& cb)
+{
+	if (!mVisibilityChangeSignal) mVisibilityChangeSignal = new commit_signal_t();
+	return mVisibilityChangeSignal->connect(cb);
+}
+
 // virtual
 void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
 {
@@ -49,6 +61,12 @@ void LLToggleableMenu::handleVisibilityChange (BOOL curVisibilityIn)
 	{
 		mClosedByButtonClick = true;
 	}
+
+	if (mVisibilityChangeSignal)
+	{
+		(*mVisibilityChangeSignal)(this,
+				LLSD().with("visibility", curVisibilityIn).with("closed_by_button_click", mClosedByButtonClick));
+	}
 }
 
 void LLToggleableMenu::setButtonRect(const LLRect& rect, LLView* current_view)
diff --git a/indra/llui/lltoggleablemenu.h b/indra/llui/lltoggleablemenu.h
index f036cdfffb..2094bd776f 100644
--- a/indra/llui/lltoggleablemenu.h
+++ b/indra/llui/lltoggleablemenu.h
@@ -41,6 +41,10 @@ protected:
 	LLToggleableMenu(const Params&);
 	friend class LLUICtrlFactory;
 public:
+	~LLToggleableMenu();
+
+	boost::signals2::connection setVisibilityChangeCallback( const commit_signal_t::slot_type& cb );
+
 	virtual void handleVisibilityChange (BOOL curVisibilityIn);
 
 	const LLRect& getButtonRect() const { return mButtonRect; }
@@ -57,6 +61,7 @@ public:
 protected:
 	bool mClosedByButtonClick;
 	LLRect mButtonRect;
+	commit_signal_t*	mVisibilityChangeSignal;
 };
 
 #endif // LL_LLTOGGLEABLEMENU_H
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 29dcb2c4d3..91ede6d221 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -53,6 +53,7 @@
 #include "llfloaterreg.h"
 #include "llmenubutton.h"
 #include "lltextbox.h"
+#include "lltoggleablemenu.h"
 #include "lltooltip.h"	// positionViewNearMouse()
 #include "lltrans.h"
 #include "lluictrl.h"
@@ -402,8 +403,8 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data)
 // if neither the gear menu or self gear menu are open
 void LLInspectAvatar::onMouseLeave(S32 x, S32 y, MASK mask)
 {
-	LLMenuGL* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
-	LLMenuGL* gear_menu_self = getChild<LLMenuButton>("gear_self_btn")->getMenu();
+	LLToggleableMenu* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
+	LLToggleableMenu* gear_menu_self = getChild<LLMenuButton>("gear_self_btn")->getMenu();
 	if ( gear_menu && gear_menu->getVisible() &&
 		 gear_menu_self && gear_menu_self->getVisible() )
 	{
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index 532ffca4be..ee076f68ea 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -47,6 +47,7 @@
 #include "llsafehandle.h"
 #include "llsidetray.h"
 #include "lltextbox.h"			// for description truncation
+#include "lltoggleablemenu.h"
 #include "lltrans.h"
 #include "llui.h"				// positionViewNearMouse()
 #include "lluictrl.h"
@@ -568,7 +569,7 @@ void LLInspectObject::updateSecureBrowsing()
 // if the gear menu is not open
 void LLInspectObject::onMouseLeave(S32 x, S32 y, MASK mask)
 {
-	LLMenuGL* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
+	LLToggleableMenu* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
 	if ( gear_menu && gear_menu->getVisible() )
 	{
 		return;
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 33c968bf00..70295259b3 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -42,6 +42,7 @@
 #include "llnotificationsutil.h"
 #include "lloutfitobserver.h"
 #include "llsidetray.h"
+#include "lltoggleablemenu.h"
 #include "lltransutil.h"
 #include "llviewermenu.h"
 #include "llvoavatar.h"
@@ -122,7 +123,7 @@ public:
 		enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenu::onEnable, this, _2));
 		enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenu::onVisible, this, _2));
 
-		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
 			"menu_outfit_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 		llassert(mMenu);
 	}
@@ -137,7 +138,7 @@ public:
 		mMenu->arrangeAndClear(); // update menu height
 	}
 
-	LLMenuGL* getMenu() { return mMenu; }
+	LLToggleableMenu* getMenu() { return mMenu; }
 
 private:
 	const LLUUID& getSelectedOutfitID()
@@ -251,8 +252,8 @@ private:
 		return true;
 	}
 
-	LLOutfitsList*	mOutfitList;
-	LLMenuGL*		mMenu;
+	LLOutfitsList*			mOutfitList;
+	LLToggleableMenu*		mMenu;
 };
 
 //////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index e5695f420a..d25b8e0e02 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -51,6 +51,7 @@
 #include "llplacesinventorybridge.h"
 #include "llplacesinventorypanel.h"
 #include "llsidetray.h"
+#include "lltoggleablemenu.h"
 #include "llviewermenu.h"
 #include "llviewerregion.h"
 
@@ -706,8 +707,8 @@ void LLLandmarksPanel::initListCommandsHandlers()
 	mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2));
 	mEnableCallbackRegistrar.add("Places.LandmarksGear.Check", boost::bind(&LLLandmarksPanel::isActionChecked, this, _2));
 	mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));
-	mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
-	mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 
 	mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::showActionMenu, this, mMenuAdd, ADD_BUTTON_NAME));
@@ -726,7 +727,7 @@ void LLLandmarksPanel::updateListCommands()
 
 void LLLandmarksPanel::onActionsButtonClick()
 {
-	LLMenuGL* menu = mGearFolderMenu;
+	LLToggleableMenu* menu = mGearFolderMenu;
 
 	LLFolderViewItem* cur_item = NULL;
 	if(mCurrentSelectedList)
diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h
index 28c19d3e5f..8dcbca0440 100644
--- a/indra/newview/llpanellandmarks.h
+++ b/indra/newview/llpanellandmarks.h
@@ -41,6 +41,7 @@ class LLAccordionCtrlTab;
 class LLFolderViewItem;
 class LLMenuButton;
 class LLMenuGL;
+class LLToggleableMenu;
 class LLInventoryPanel;
 class LLPlacesInventoryPanel;
 
@@ -157,8 +158,8 @@ private:
 	LLPlacesInventoryPanel*		mMyInventoryPanel;
 	LLPlacesInventoryPanel*		mLibraryInventoryPanel;
 	LLMenuButton*				mGearButton;
-	LLMenuGL*					mGearLandmarkMenu;
-	LLMenuGL*					mGearFolderMenu;
+	LLToggleableMenu*			mGearLandmarkMenu;
+	LLToggleableMenu*			mGearFolderMenu;
 	LLMenuGL*					mMenuAdd;
 	LLPlacesInventoryPanel*		mCurrentSelectedList;
 	LLInventoryObserver*		mInventoryObserver;
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index cc69dbd9d4..904e3dabcc 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -46,6 +46,7 @@
 #include "llscrollcontainer.h"
 #include "llsdserialize.h"
 #include "llspinctrl.h"
+#include "lltoggleablemenu.h"
 #include "lltooldraganddrop.h"
 #include "llviewermenu.h"
 #include "llviewertexturelist.h"
@@ -915,7 +916,7 @@ void LLPanelMainInventory::initListCommandsHandlers()
 
 	mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2));
 	mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2));
-	mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	mGearMenuButton->setMenu(mMenuGearDefault);
 	mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 
diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h
index f95a99157d..d136e2d32e 100644
--- a/indra/newview/llpanelmaininventory.h
+++ b/indra/newview/llpanelmaininventory.h
@@ -42,6 +42,7 @@ class LLTabContainer;
 class LLFloaterInventoryFinder;
 class LLMenuButton;
 class LLMenuGL;
+class LLToggleableMenu;
 class LLFloater;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -143,7 +144,7 @@ protected:
 	void setUploadCostIfNeeded();
 private:
 	LLDragAndDropButton*		mTrashButton;
-	LLMenuGL*					mMenuGearDefault;
+	LLToggleableMenu*			mMenuGearDefault;
 	LLMenuGL*					mMenuAdd;
 	LLMenuButton*				mGearMenuButton;
 
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 5638374178..6394239889 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -62,6 +62,7 @@
 #include "llsaveoutfitcombobtn.h"
 #include "llscrolllistctrl.h"
 #include "lltextbox.h"
+#include "lltoggleablemenu.h"
 #include "lltrans.h"
 #include "lluictrlfactory.h"
 #include "llsdutil.h"
@@ -152,13 +153,13 @@ std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex
 class LLPanelOutfitEditGearMenu
 {
 public:
-	static LLMenuGL* create()
+	static LLToggleableMenu* create()
 	{
 		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 
 		registrar.add("Wearable.Create", boost::bind(onCreate, _2));
 
-		LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
 			"menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
 		llassert(menu);
 		if (menu)
@@ -219,7 +220,7 @@ private:
 class LLAddWearablesGearMenu : public LLInitClass<LLAddWearablesGearMenu>
 {
 public:
-	static LLMenuGL* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
+	static LLToggleableMenu* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
 	{
 		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
@@ -234,7 +235,7 @@ public:
 		enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2));
 		enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2));
 
-		LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
 			"menu_add_wearable_gear.xml",
 			LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
 
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 963db84503..fd366e9cbc 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -233,8 +233,8 @@ private:
 	std::vector<LLFilterItem*> mListViewItemTypes;
 
 	LLCOFWearables*		mCOFWearables;
-	LLMenuGL*			mGearMenu;
-	LLMenuGL*			mAddWearablesGearMenu;
+	LLToggleableMenu*	mGearMenu;
+	LLToggleableMenu*	mAddWearablesGearMenu;
 	bool				mInitialized;
 	std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn;
 	LLMenuButton*		mWearablesGearMenuBtn;
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index b79a2d3224..71c812efe2 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -35,6 +35,7 @@
 #include "lleventtimer.h"
 #include "llfiltereditor.h"
 #include "lltabcontainer.h"
+#include "lltoggleablemenu.h"
 #include "lluictrlfactory.h"
 
 #include "llpanelpeople.h"
@@ -632,28 +633,28 @@ BOOL LLPanelPeople::postBuild()
 	LLMenuGL* plus_menu  = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_group_plus.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	mGroupPlusMenuHandle  = plus_menu->getHandle();
 
-	LLMenuGL* nearby_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_nearby_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	LLToggleableMenu* nearby_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_nearby_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	if(nearby_view_sort)
 	{
 		mNearbyViewSortMenuHandle  = nearby_view_sort->getHandle();
 		mNearbyGearButton->setMenu(nearby_view_sort);
 	}
 
-	LLMenuGL* friend_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_friends_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	LLToggleableMenu* friend_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_friends_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	if(friend_view_sort)
 	{
 		mFriendsViewSortMenuHandle  = friend_view_sort->getHandle();
 		mFriendsGearButton->setMenu(friend_view_sort);
 	}
 
-	LLMenuGL* group_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_groups_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	LLToggleableMenu* group_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_groups_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	if(group_view_sort)
 	{
 		mGroupsViewSortMenuHandle  = group_view_sort->getHandle();
 		mGroupsGearButton->setMenu(group_view_sort);
 	}
 
-	LLMenuGL* recent_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_people_recent_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	LLToggleableMenu* recent_view_sort  = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_recent_view_sort.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 	if(recent_view_sort)
 	{
 		mRecentViewSortMenuHandle  = recent_view_sort->getHandle();
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index 766f93e0a5..fff8ccb912 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -41,6 +41,7 @@
 #include "llflatlistview.h"
 #include "llnotificationsutil.h"
 #include "lltextbox.h"
+#include "lltoggleablemenu.h"
 #include "llviewermenu.h"
 #include "lllandmarkactions.h"
 #include "llclipboard.h"
@@ -450,7 +451,7 @@ BOOL LLTeleportHistoryPanel::postBuild()
 
 	mMenuGearButton = getChild<LLMenuButton>("gear_btn");
 
-	LLMenuGL* gear_menu  = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_teleport_history_gear.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());;
+	LLToggleableMenu* gear_menu  = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_teleport_history_gear.xml",  gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());;
 	if(gear_menu)
 	{
 		mGearMenuHandle  = gear_menu->getHandle();
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index 3b3d0cdce5..911a9e5dda 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -28,6 +28,8 @@
 
 #include "llpanelwearing.h"
 
+#include "lltoggleablemenu.h"
+
 #include "llappearancemgr.h"
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
@@ -59,12 +61,12 @@ public:
 
 		enable_registrar.add("Gear.OnEnable", boost::bind(&LLPanelWearing::isActionEnabled, mPanelWearing, _2));
 
-		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
 			"menu_wearing_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 		llassert(mMenu);
 	}
 
-	LLMenuGL* getMenu() { return mMenu; }
+	LLToggleableMenu* getMenu() { return mMenu; }
 
 private:
 
@@ -79,8 +81,8 @@ private:
 		}
 	}
 
-	LLMenuGL*		mMenu;
-	LLPanelWearing* mPanelWearing;
+	LLToggleableMenu*		mMenu;
+	LLPanelWearing* 		mPanelWearing;
 };
 
 //////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/skins/default/xui/en/menu_add_wearable_gear.xml b/indra/newview/skins/default/xui/en/menu_add_wearable_gear.xml
index 1925d3396f..5033ea9546 100644
--- a/indra/newview/skins/default/xui/en/menu_add_wearable_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_add_wearable_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  layout="topleft"
  name="Add Wearable Gear Menu">
     <menu_item_check
@@ -38,4 +38,4 @@
          function="AddWearable.Gear.Visible"
          parameter="by_type" />
     </menu_item_check>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_cof_gear.xml b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
index c2a11a64ec..a6e9a40e31 100644
--- a/indra/newview/skins/default/xui/en/menu_cof_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_cof_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  layout="topleft"
  name="Gear COF">
     <menu
@@ -10,4 +10,4 @@
      label="New Body Parts"
      layout="topleft"
      name="COF.Geear.New_Body_Parts" />
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
index 649f0edff7..b08d21e8f4 100644
--- a/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_gesture_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  layout="topleft"
  mouse_opaque="false"
  name="menu_gesture_gear"
@@ -62,4 +62,4 @@
          function="Gesture.EnableAction"
          parameter="edit_gesture" />
     </menu_item_call>
-</menu>
+</toggleable_menu>
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
index 334decdf58..58d58a6ca9 100644
--- a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<menu
+<toggleable_menu
          create_jump_keys="true"
          layout="topleft"
          mouse_opaque="false"
@@ -124,4 +124,4 @@
     <menu_item_call.on_click
      function="InspectAvatar.Share"/>
   </menu_item_call>
-</menu>
+</toggleable_menu>
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
index 76f68c6d4b..f818ebe2d7 100644
--- a/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_inspect_object_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<menu
+<toggleable_menu
    create_jump_keys="true"
    layout="topleft"
    mouse_opaque="false"
@@ -136,4 +136,4 @@
     <menu_item_call.on_click
      function="InspectObject.MoreInfo"/>
   </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
index 30c2cde552..50ad3f834e 100644
--- a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<menu
+<toggleable_menu
          create_jump_keys="true"
          layout="topleft"
          mouse_opaque="false"
@@ -63,4 +63,4 @@
     <menu_item_call.on_visible
      function="IsGodCustomerService"/>
   </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
index c394700081..679d5bc82e 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_gear_default.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  bottom="806"
  layout="topleft"
  left="0"
@@ -125,4 +125,4 @@
          function="Inventory.GearDefault.Custom.Action"
          parameter="empty_trash" />
     </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
index 732b8a788d..5fc25b8f0f 100644
--- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  layout="topleft"
  visible="false"
  name="Gear Outfit">
@@ -212,4 +212,4 @@
          function="Gear.OnVisible"
          parameter="delete" />
     </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml
index 22796f7b68..29eeb93ac1 100644
--- a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu name="menu_group_plus"
+<toggleable_menu
+     name="menu_group_plus"
      left="0" bottom="0" visible="false"
      mouse_opaque="false">
   <menu_item_check
@@ -43,4 +44,4 @@
   <menu_item_call name="show_blocked_list" label="Show Blocked Residents &amp; Objects">
     <menu_item_call.on_click function="SideTray.ShowPanel" parameter="panel_block_list_sidetray" />
   </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_groups_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_groups_view_sort.xml
index 2efb204ffb..c710fe3b9b 100644
--- a/indra/newview/skins/default/xui/en/menu_people_groups_view_sort.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_groups_view_sort.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu name="menu_group_plus"
+<toggleable_menu 
+     name="menu_group_plus"
      left="0" bottom="0" visible="false"
      mouse_opaque="false">
   <menu_item_check
@@ -22,4 +23,4 @@
       <menu_item_call.on_enable
        function="People.Group.Minus.Enable"/>
   </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml
index 69b3831738..f9db64b524 100644
--- a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu name="menu_group_plus"
+<toggleable_menu
+     name="menu_group_plus"
      left="0" bottom="0" visible="false"
      mouse_opaque="false">
   <menu_item_check
@@ -45,4 +46,4 @@
   <menu_item_call name="show_blocked_list" label="Show Blocked Residents &amp; Objects">
     <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" />
   </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml
index 5c9555db92..0634e3bd3b 100644
--- a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml
+++ b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu name="menu_group_plus"
+<toggleable_menu 
+     name="menu_group_plus"
      left="0" bottom="0" visible="false"
      mouse_opaque="false">
   <menu_item_check
@@ -35,4 +36,4 @@
   <menu_item_call name="show_blocked_list" label="Show Blocked Residents &amp; Objects">
     <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" />
   </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml
index 77cc3910fd..6f46165883 100644
--- a/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml
+++ b/indra/newview/skins/default/xui/en/menu_places_gear_folder.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  bottom="806"
  layout="topleft"
  left="0"
@@ -145,4 +145,4 @@
          function="Places.LandmarksGear.Folding.Action"
          parameter="sort_by_date" />
     </menu_item_check>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml
index 4b8bc8132f..121e7cc07a 100644
--- a/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml
+++ b/indra/newview/skins/default/xui/en/menu_places_gear_landmark.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  bottom="806"
  layout="topleft"
  left="0"
@@ -174,4 +174,4 @@
          function="Places.LandmarksGear.Enable"
          parameter="create_pick" />
     </menu_item_call>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml b/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml
index 134b331514..bc7d4fe33b 100644
--- a/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_teleport_history_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  name="Teleport History Gear Context Menu"
  left="0"
  bottom="0"
@@ -33,4 +33,4 @@
         <menu_item_call.on_click
          function="TeleportHistory.ClearTeleportHistory" />
     </menu_item_call>    
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_wearing_gear.xml b/indra/newview/skins/default/xui/en/menu_wearing_gear.xml
index 84ab16c709..0ac2c14253 100644
--- a/indra/newview/skins/default/xui/en/menu_wearing_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_wearing_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
  layout="topleft"
  visible="false"
  name="Gear Wearing">
@@ -20,4 +20,4 @@
          function="Gear.OnEnable"
          parameter="take_off" />
     </menu_item_call>
-</menu>
+</toggleable_menu>
-- 
cgit v1.2.3


From 6f4a21531ae7e5d095034f7315501421dd94d124 Mon Sep 17 00:00:00 2001
From: Merov Linden <merov@lindenlab.com>
Date: Thu, 21 Oct 2010 17:12:24 -0700
Subject: STORM-173 : never enable return object if no object selected

---
 indra/newview/llviewermenu.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ccf3df827d..dc7c6f17a9 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -4160,6 +4160,12 @@ class LLObjectEnableReturn : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+		LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+		if (!node)
+		{
+			// Do not enable if nothing selected
+			return false;
+		}
 #ifdef HACKED_GODLIKE_VIEWER
 		bool new_value = true;
 #else
-- 
cgit v1.2.3


From 07353619d0069acc9933bed2772e0e6925636efb Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Fri, 22 Oct 2010 19:39:38 +0300
Subject: STORM-297 FIXED Fixed "<nolink>" text appearing in confirmation
 message if there is "<" symbol in Landmarks name.

Modified the "<nolink>...</nolink>" clause parsing regexp to allow "<" in the middle.
---
 indra/llui/llurlentry.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index f58c07754f..f49dfec82b 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -972,7 +972,7 @@ std::string LLUrlEntryWorldMap::getLocation(const std::string &url) const
 //
 LLUrlEntryNoLink::LLUrlEntryNoLink()
 {
-	mPattern = boost::regex("<nolink>[^<]*</nolink>",
+	mPattern = boost::regex("<nolink>.*</nolink>",
 							boost::regex::perl|boost::regex::icase);
 }
 
-- 
cgit v1.2.3


From 9e8ff9be024edb279ba1e22548ee3fc48214fda5 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Fri, 22 Oct 2010 20:14:13 +0300
Subject: STORM-449 FIXED Updated some notification templates for NL locale to
 display avatar names correctly.

---
 indra/newview/skins/default/xui/nl/notifications.xml | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/skins/default/xui/nl/notifications.xml b/indra/newview/skins/default/xui/nl/notifications.xml
index a282c70364..b4b56a035f 100644
--- a/indra/newview/skins/default/xui/nl/notifications.xml
+++ b/indra/newview/skins/default/xui/nl/notifications.xml
@@ -2409,10 +2409,10 @@ Wilt u de [SECOND_LIFE] website bezoeken om dit in te stellen?
 		Onderwerp: [SUBJECT], Bericht: [MESSAGE]
 	</notification>
 	<notification name="FriendOnline">
-		[FIRST] [LAST] is Online
+		[NAME] is Online
 	</notification>
 	<notification name="FriendOffline">
-		[FIRST] [LAST] is Offline
+		[NAME] is Offline
 	</notification>
 	<notification name="AddSelfFriend">
 		U kunt uzelf niet als vriend toevoegen.
@@ -2574,7 +2574,7 @@ Indien u streaming media wilt zien op percelen die dit ondersteunen, dient u naa
 		De objecten die uw eigendom zijn op het geselecteerde perceel zijn geretourneerd naar uw inventaris.
 	</notification>
 	<notification name="OtherObjectsReturned">
-		De objecten op het geselecteerde perceel dat het eigendom is van [FIRST] [LAST], zijn geretourneerd naar zijn of haar inventaris.
+		De objecten op het geselecteerde perceel dat het eigendom is van [NAME], zijn geretourneerd naar zijn of haar inventaris.
 	</notification>
 	<notification name="OtherObjectsReturned2">
 		De objecten op het geselecteerde perceel dat het eigendom is van inwoner &apos;[NAME]&apos;, zijn geretourneerd naar hun eigenaar.
@@ -2701,7 +2701,7 @@ Probeer het alstublieft opnieuw over enkele ogenblikken.
 		Geen geldig perceel kon gevonden worden.
 	</notification>
 	<notification name="ObjectGiveItem">
-		Een object genaamd [OBJECTFROMNAME], eigendom van [FIRST] [LAST], heeft u een [OBJECTTYPE] genaamd [OBJECTNAME] gegeven.
+		Een object genaamd &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt;, eigendom van [NAME_SLURL], heeft u een [OBJECTTYPE] genaamd [ITEM_SLURL] gegeven.
 		<form name="form">
 			<button name="Keep" text="Behouden"/>
 			<button name="Discard" text="Afwijzen"/>
@@ -2840,7 +2840,7 @@ Dit verzoek inwilligen?
 		</form>
 	</notification>
 	<notification name="ScriptDialog">
-		[FIRST] [LAST]&apos;s &apos;[TITLE]&apos;
+		[NAME]&apos;s &apos;&lt;nolink&gt;[TITLE]&lt;/nolink&gt;&apos;
 [MESSAGE]
 		<form name="form">
 			<button name="Ignore" text="Negeren"/>
@@ -2941,13 +2941,13 @@ Klik Accepteren om deel te nemen aan dit gesprek of Afwijzen om de uitnodiging a
 		</form>
 	</notification>
 	<notification name="AutoUnmuteByIM">
-		Er is een instant message naar [FIRST] [LAST] gestuurd, waardoor deze automatisch van de negeerlijst is gehaald.
+		Er is een instant message naar [NAME] gestuurd, waardoor deze automatisch van de negeerlijst is gehaald.
 	</notification>
 	<notification name="AutoUnmuteByMoney">
-		Er is geld gegeven aan [FIRST] [LAST], waardoor deze automatisch van de negeerlijst is gehaald.
+		Er is geld gegeven aan [NAME], waardoor deze automatisch van de negeerlijst is gehaald.
 	</notification>
 	<notification name="AutoUnmuteByInventory">
-		Er is inventaris aangeboden aan [FIRST] [LAST], waardoor deze automatisch van de negeerlijst is gehaald.
+		Er is inventaris aangeboden aan [NAME], waardoor deze automatisch van de negeerlijst is gehaald.
 	</notification>
 	<notification name="VoiceInviteGroup">
 		[NAME] doet nu mee met een Voice chat gesprek binnen de groep [GROUP].
-- 
cgit v1.2.3


From 7a597cf4f14e7d4950875c2ecd3221234a98562b Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Fri, 22 Oct 2010 20:47:55 +0300
Subject: STORM-350 FIXED Wrong icon (texture) was displayed for sounds in
 inventory.

By the way, just for consistency changed LINKFOLDER icon from "Inv_LinkItem" "Inv_LinkFolder".
The icons are equal, so this change has no effect.
---
 indra/newview/llinventoryicon.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
index 7216d61e7f..3f4f33e88d 100644
--- a/indra/newview/llinventoryicon.cpp
+++ b/indra/newview/llinventoryicon.cpp
@@ -50,7 +50,7 @@ public:
 LLIconDictionary::LLIconDictionary()
 {
 	addEntry(LLInventoryIcon::ICONNAME_TEXTURE, 				new IconEntry("Inv_Texture"));
-	addEntry(LLInventoryIcon::ICONNAME_SOUND, 					new IconEntry("Inv_Texture"));
+	addEntry(LLInventoryIcon::ICONNAME_SOUND, 					new IconEntry("Inv_Sound"));
 	addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_ONLINE, 		new IconEntry("Inv_CallingCard"));
 	addEntry(LLInventoryIcon::ICONNAME_CALLINGCARD_OFFLINE, 	new IconEntry("Inv_CallingCard"));
 	addEntry(LLInventoryIcon::ICONNAME_LANDMARK, 				new IconEntry("Inv_Landmark"));
@@ -83,7 +83,7 @@ LLIconDictionary::LLIconDictionary()
 	addEntry(LLInventoryIcon::ICONNAME_GESTURE, 				new IconEntry("Inv_Gesture"));
 
 	addEntry(LLInventoryIcon::ICONNAME_LINKITEM, 				new IconEntry("Inv_LinkItem"));
-	addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, 				new IconEntry("Inv_LinkItem"));
+	addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, 				new IconEntry("Inv_LinkFolder"));
 
 	addEntry(LLInventoryIcon::ICONNAME_INVALID, 				new IconEntry("Inv_Invalid"));
 
-- 
cgit v1.2.3


From c16f0ef5ebceaae11ab9108c1bfe012b1c4fd622 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Fri, 22 Oct 2010 16:04:00 -0500
Subject: Disable FBO by default for all settings.

---
 indra/newview/featuretable.txt    | 6 +++---
 indra/newview/featuretable_xp.txt | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index b09dd699ba..d69842d5f1 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 23
+version 25
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -144,7 +144,7 @@ WLSkyDetail					1	48
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderShadowDetail			1	0
-RenderUseFBO				1	1
+RenderUseFBO				1	0
 
 //
 // Ultra graphics (REALLY PURTY!)
@@ -171,7 +171,7 @@ WLSkyDetail					1	128
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderShadowDetail			1	0
-RenderUseFBO				1	1
+RenderUseFBO				1	0
 
 //
 // Class Unknown Hardware (unknown)
diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt
index 1e83bc73a5..dae7705971 100644
--- a/indra/newview/featuretable_xp.txt
+++ b/indra/newview/featuretable_xp.txt
@@ -1,4 +1,4 @@
-version 23
+version 25
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -144,7 +144,7 @@ WLSkyDetail					1	48
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderShadowDetail			1	0
-RenderUseFBO				1	1
+RenderUseFBO				1	0
 
 //
 // Ultra graphics (REALLY PURTY!)
@@ -171,7 +171,7 @@ WLSkyDetail					1	128
 RenderDeferred				1	0
 RenderDeferredSSAO			1	0
 RenderShadowDetail			1	0
-RenderUseFBO				1	1
+RenderUseFBO				1	0
 
 //
 // Class Unknown Hardware (unknown)
-- 
cgit v1.2.3


From cb5d8d1a9295076327f23e5f6d6c91fd0d4580ea Mon Sep 17 00:00:00 2001
From: Leyla Farazha <leyla@lindenlab.com>
Date: Fri, 22 Oct 2010 17:41:06 -0700
Subject: DN-181 Chat & IM logs saved in unreadable .llsd instead of .txt

---
 indra/llmessage/llcachename.cpp |  27 +++++++
 indra/llmessage/llcachename.h   |   6 ++
 indra/newview/llchathistory.cpp |  47 ++++++++++--
 indra/newview/llimview.cpp      |  30 ++++++--
 indra/newview/lllogchat.cpp     | 157 +++++++++++++++++++++++++++++-----------
 indra/newview/lllogchat.h       |  40 ++++++++--
 indra/newview/llnearbychat.cpp  |  56 ++++++++++----
 7 files changed, 287 insertions(+), 76 deletions(-)

(limited to 'indra')

diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index 4a66a31c35..522b99bc02 100644
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -38,6 +38,8 @@
 #include "message.h"
 #include "llmemtype.h"
 
+#include <boost/regex.hpp>
+
 // llsd serialization constants
 static const std::string AGENTS("agents");
 static const std::string GROUPS("groups");
@@ -551,6 +553,31 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
 	return full_name;
 }
 
+//static 
+std::string LLCacheName::buildLegacyName(const std::string& complete_name)
+{
+	boost::regex complete_name_regex("(.+)( \\()([A-Za-z]+)(.[A-Za-z]+)*(\\))");
+	boost::match_results<std::string::const_iterator> name_results;
+	if (!boost::regex_match(complete_name, name_results, complete_name_regex)) return complete_name;
+
+	std::string legacy_name = name_results[3];
+	// capitalize the first letter
+	std::string cap_letter = legacy_name.substr(0, 1);
+	LLStringUtil::toUpper(cap_letter);
+	legacy_name = cap_letter + legacy_name.substr(1);
+
+	if (name_results[4].matched)
+	{
+		std::string last_name = name_results[4];
+		std::string cap_letter = last_name.substr(1, 1);
+		LLStringUtil::toUpper(cap_letter);
+		last_name = cap_letter + last_name.substr(2);
+		legacy_name = legacy_name + " " + last_name;
+	}
+
+	return legacy_name;
+}
+
 // This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
 //  The reason it is a slot is so that the legacy get() function below can bind an old callback
 //  and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior
diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h
index b469803060..b108e37157 100644
--- a/indra/llmessage/llcachename.h
+++ b/indra/llmessage/llcachename.h
@@ -90,6 +90,12 @@ public:
 	// "Random Linden" -> "random.linden"
 	static std::string buildUsername(const std::string& name);
 	
+	// Converts a complete display name to a legacy name
+	// if possible, otherwise returns the input
+	// "Alias (random.linden)" -> "Random Linden"
+	// "Something random" -> "Something random"
+	static std::string buildLegacyName(const std::string& name);
+	
 	// If available, this method copies the group name into the string
 	// provided. The caller must allocate at least
 	// DB_GROUP_NAME_BUF_SIZE characters. If not available, this
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 378c4358b3..cb5cf4a61d 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -54,6 +54,7 @@
 #include "llviewertexteditor.h"
 #include "llworld.h"
 #include "lluiconstants.h"
+#include "llstring.h"
 
 #include "llviewercontrol.h"
 
@@ -260,7 +261,7 @@ public:
 		if((chat.mFromID.isNull() && chat.mFromName.empty()) || chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull())
 		{
 			mSourceType = CHAT_SOURCE_SYSTEM;
-		}
+		}  
 
 		mUserNameFont = style_params.font();
 		LLTextBox* user_name = getChild<LLTextBox>("user_name");
@@ -268,14 +269,14 @@ public:
 		user_name->setColor(style_params.color());
 
 		if (chat.mFromName.empty()
-			|| mSourceType == CHAT_SOURCE_SYSTEM
-			|| mAvatarID.isNull())
+			|| mSourceType == CHAT_SOURCE_SYSTEM)
 		{
 			mFrom = LLTrans::getString("SECOND_LIFE");
 			user_name->setValue(mFrom);
 			updateMinUserNameWidth();
 		}
 		else if (mSourceType == CHAT_SOURCE_AGENT
+				 && !mAvatarID.isNull()
 				 && chat.mChatStyle != CHAT_STYLE_HISTORY)
 		{
 			// ...from a normal user, lookup the name and fill in later.
@@ -288,7 +289,41 @@ public:
 			LLAvatarNameCache::get(mAvatarID,
 				boost::bind(&LLChatHistoryHeader::onAvatarNameCache, this, _1, _2));
 		}
-		else {
+		else if (chat.mChatStyle == CHAT_STYLE_HISTORY ||
+				 mSourceType == CHAT_SOURCE_AGENT)
+		{
+			//if it's an avatar name with a username add formatting
+			S32 username_start = chat.mFromName.rfind(" (");
+			S32 username_end = chat.mFromName.rfind(')');
+			
+			if (username_start != std::string::npos &&
+				username_end == (chat.mFromName.length() - 1))
+			{
+				mFrom = chat.mFromName.substr(0, username_start);
+				user_name->setValue(mFrom);
+
+				if (gSavedSettings.getBOOL("NameTagShowUsernames"))
+				{
+					std::string username = chat.mFromName.substr(username_start + 2);
+					username = username.substr(0, username.length() - 1);
+					LLStyle::Params style_params_name;
+					LLColor4 userNameColor = LLUIColorTable::instance().getColor("EmphasisColor");
+					style_params_name.color(userNameColor);
+					style_params_name.font.name("SansSerifSmall");
+					style_params_name.font.style("NORMAL");
+					style_params_name.readonly_color(userNameColor);
+					user_name->appendText("  - " + username, FALSE, style_params_name);
+				}
+			}
+			else
+			{
+				mFrom = chat.mFromName;
+				user_name->setValue(mFrom);
+				updateMinUserNameWidth();
+			}
+		}
+		else
+		{
 			// ...from an object, just use name as given
 			mFrom = chat.mFromName;
 			user_name->setValue(mFrom);
@@ -367,7 +402,9 @@ public:
 		user_name->setValue( LLSD(av_name.mDisplayName ) );
 		user_name->setToolTip( av_name.mUsername );
 
-		if (gSavedSettings.getBOOL("NameTagShowUsernames") && LLAvatarNameCache::useDisplayNames())
+		if (gSavedSettings.getBOOL("NameTagShowUsernames") && 
+			LLAvatarNameCache::useDisplayNames() &&
+			!av_name.mIsDisplayNameDefault)
 		{
 			LLStyle::Params style_params_name;
 			LLColor4 userNameColor = LLUIColorTable::instance().getColor("EmphasisColor");
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index c865dcf9a3..ba0dc31005 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -430,8 +430,9 @@ void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& histo
 		}
 		else
 		{
-			// Legacy chat logs only wrote the legacy name, not the agent_id
-			gCacheName->getUUID(from, from_id);
+			// convert it to a legacy name if we have a complete name
+			std::string legacy_name = gCacheName->buildLegacyName(from);
+ 			gCacheName->getUUID(legacy_name, from_id);
 		}
 
 		std::string timestamp = msg[IM_TIME];
@@ -526,8 +527,15 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
 
 void LLIMModel::LLIMSession::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name)
 {
-	// if username is empty, display names isn't enabled, use the display name
-	mHistoryFileName = av_name.mUsername.empty() ? av_name.mDisplayName : av_name.mUsername;
+	if (av_name.getLegacyName().empty())
+	{
+		// if display names is off the legacy name will be the display name
+		mHistoryFileName = LLCacheName::cleanFullName(av_name.mDisplayName);
+	}
+	else
+	{  
+		mHistoryFileName = LLCacheName::cleanFullName(av_name.getLegacyName());
+	}
 }
 
 void LLIMModel::LLIMSession::buildHistoryFileName()
@@ -737,8 +745,18 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,
 bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
 {
 	if (gSavedPerAccountSettings.getBOOL("LogInstantMessages"))
-	{
-		LLLogChat::saveHistory(file_name, from, from_id, utf8_text);
+	{	
+		std::string from_name = from;
+
+		LLAvatarName av_name;
+		if (!from_id.isNull() && 
+			LLAvatarNameCache::get(from_id, &av_name) &&
+			!av_name.mIsDisplayNameDefault)
+		{	
+			from_name = av_name.getCompleteName();
+		}
+
+		LLLogChat::saveHistory(file_name, from_name, from_id, utf8_text);
 		return true;
 	}
 	else
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index c8fd1e1d9a..8c70b1e973 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -26,18 +26,13 @@
 
 #include "llviewerprecompiledheaders.h"
 
-#include "lllogchat.h"
-
-// viewer includes
 #include "llagent.h"
 #include "llagentui.h"
+#include "lllogchat.h"
 #include "lltrans.h"
 #include "llviewercontrol.h"
 
-// library includes
-#include "llchat.h"
 #include "llinstantmessage.h"
-#include "llsdserialize.h"
 #include "llsingleton.h" // for LLSingleton
 
 #include <boost/algorithm/string/trim.hpp>
@@ -65,7 +60,6 @@ const std::string IM_TIME("time");
 const std::string IM_TEXT("message");
 const std::string IM_FROM("from");
 const std::string IM_FROM_ID("from_id");
-const std::string IM_SOURCE_TYPE("source_type");
 
 const static std::string IM_SEPARATOR(": ");
 const static std::string NEW_LINE("\n");
@@ -93,7 +87,7 @@ const static boost::regex TIMESTAMP_AND_STUFF("^(\\[\\d{4}/\\d{1,2}/\\d{1,2}\\s+
  *  Regular expression suitable to match names like
  *  "You", "Second Life", "Igor ProductEngine", "Object", "Mega House"
  */
-const static boost::regex NAME_AND_TEXT("(You:|Second Life:|[^\\s:]+\\s*[:]{1}|\\S+\\s+[^\\s:]+[:]{1})?(\\s*)(.*)");
+const static boost::regex NAME_AND_TEXT("([^:]+[:]{1})?(\\s*)(.*)");
 
 //is used to parse complex object names like "Xstreet SL Terminal v2.2.5 st"
 const static std::string NAME_TEXT_DIVIDER(": ");
@@ -190,8 +184,7 @@ std::string LLLogChat::makeLogFileName(std::string filename)
 {
 	filename = cleanFileName(filename);
 	filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS,filename);
-	// new files are llsd notation format
-	filename += ".llsd";
+	filename += ".txt";
 	return filename;
 }
 
@@ -240,18 +233,6 @@ void LLLogChat::saveHistory(const std::string& filename,
 			    const std::string& from,
 			    const LLUUID& from_id,
 			    const std::string& line)
-{
-	LLChat chat;
-	chat.mText = line;
-	chat.mFromName = from;
-	chat.mFromID = from_id;
-	// default to being from an agent
-	chat.mSourceType = CHAT_SOURCE_AGENT;
-	saveHistory(filename, chat);
-}
-
-//static
-void LLLogChat::saveHistory(const std::string& filename, const LLChat& chat)
 {
 	std::string tmp_filename = filename;
 	LLStringUtil::trim(tmp_filename);
@@ -273,27 +254,89 @@ void LLLogChat::saveHistory(const std::string& filename, const LLChat& chat)
 	LLSD item;
 
 	if (gSavedPerAccountSettings.getBOOL("LogTimestamp"))
-		 item[IM_TIME] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate"));
+		 item["time"] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate"));
 
-	item[IM_FROM_ID] = chat.mFromID;
-	item[IM_TEXT] = chat.mText;
-	item[IM_SOURCE_TYPE] = chat.mSourceType;
+	item["from_id"]	= from_id;
+	item["message"]	= line;
 
 	//adding "Second Life:" for all system messages to make chat log history parsing more reliable
-	if (chat.mFromName.empty() && chat.mFromID.isNull())
+	if (from.empty() && from_id.isNull())
 	{
-		item[IM_FROM] = SYSTEM_FROM; 
+		item["from"] = SYSTEM_FROM; 
 	}
 	else
 	{
-		item[IM_FROM] = chat.mFromName;
+		item["from"] = from;
 	}
 
-	file << LLSDOStreamer<LLSDNotationFormatter>(item) << std::endl;
+	file << LLChatLogFormatter(item) << std::endl;
 
 	file.close();
 }
 
+void LLLogChat::loadHistory(const std::string& filename, void (*callback)(ELogLineType, const LLSD&, void*), void* userdata)
+{
+	if(!filename.size())
+	{
+		llwarns << "Filename is Empty!" << llendl;
+		return ;
+	}
+        
+	LLFILE* fptr = LLFile::fopen(makeLogFileName(filename), "r");		/*Flawfinder: ignore*/
+	if (!fptr)
+	{
+		callback(LOG_EMPTY, LLSD(), userdata);
+		return;			//No previous conversation with this name.
+	}
+	else
+	{
+		char buffer[LOG_RECALL_SIZE];		/*Flawfinder: ignore*/
+		char *bptr;
+		S32 len;
+		bool firstline=TRUE;
+
+		if ( fseek(fptr, (LOG_RECALL_SIZE - 1) * -1  , SEEK_END) )		
+		{	//File is smaller than recall size.  Get it all.
+			firstline = FALSE;
+			if ( fseek(fptr, 0, SEEK_SET) )
+			{
+				fclose(fptr);
+				return;
+			}
+		}
+
+		while ( fgets(buffer, LOG_RECALL_SIZE, fptr)  && !feof(fptr) ) 
+		{
+			len = strlen(buffer) - 1;		/*Flawfinder: ignore*/
+			for ( bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--)	*bptr='\0';
+			
+			if (!firstline)
+			{
+				LLSD item;
+				std::string line(buffer);
+				std::istringstream iss(line);
+				
+				if (!LLChatLogParser::parse(line, item))
+				{
+					item["message"]	= line;
+					callback(LOG_LINE, item, userdata);
+				}
+				else
+				{
+					callback(LOG_LLSD, item, userdata);
+				}
+			}
+			else
+			{
+				firstline = FALSE;
+			}
+		}
+		callback(LOG_END, LLSD(), userdata);
+		
+		fclose(fptr);
+	}
+}
+
 void append_to_last_message(std::list<LLSD>& messages, const std::string& line)
 {
 	if (!messages.size()) return;
@@ -367,24 +410,52 @@ void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& me
 	fclose(fptr);
 }
 
-// static
-bool LLChatLogParser::parse(const std::string& raw, LLSD& im)
+//*TODO mark object's names in a special way so that they will be distinguishable form avatar name 
+//which are more strict by its nature (only firstname and secondname)
+//Example, an object's name can be writen like "Object <actual_object's_name>"
+void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const
 {
-	if (!raw.length()) return false;
+	if (!im.isMap())
+	{
+		llwarning("invalid LLSD type of an instant message", 0);
+		return;
+	}
+
+	if (im[IM_TIME].isDefined())
+{
+		std::string timestamp = im[IM_TIME].asString();
+		boost::trim(timestamp);
+		ostr << '[' << timestamp << ']' << TWO_SPACES;
+	}
 	
-	im = LLSD::emptyMap();
+	//*TODO mark object's names in a special way so that they will be distinguishable form avatar name 
+	//which are more strict by its nature (only firstname and secondname)
+	//Example, an object's name can be writen like "Object <actual_object's_name>"
+	if (im[IM_FROM].isDefined())
+	{
+		std::string from = im[IM_FROM].asString();
+		boost::trim(from);
+		if (from.size())
+		{
+			ostr << from << IM_SEPARATOR;
+		}
+	}
 
-	// In Viewer 2.1 we added UUID to chat/IM logging so we can look up
-	// display names
-	if (raw[0] == '{')
+	if (im[IM_TEXT].isDefined())
 	{
-		// ...this is a viewer 2.1, new-style LLSD notation format log
-		std::istringstream raw_stream(raw);
-		LLPointer<LLSDParser> parser = new LLSDNotationParser();
-		S32 count = parser->parse(raw_stream, im, raw.length());
-		// expect several map items per parsed line
-		return (count != LLSDParser::PARSE_FAILURE);
+		std::string im_text = im[IM_TEXT].asString();
+
+		//multilined text will be saved with prepended spaces
+		boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX);
+		ostr << im_text;
 	}
+	}
+
+bool LLChatLogParser::parse(std::string& raw, LLSD& im)
+{
+	if (!raw.length()) return false;
+	
+	im = LLSD::emptyMap();
 
 	//matching a timestamp
 	boost::match_results<std::string::const_iterator> matches;
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index 8b1cc3484f..6958d56311 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -41,21 +41,48 @@ public:
 	};
 	static std::string timestamp(bool withdate = false);
 	static std::string makeLogFileName(std::string(filename));
-
-	// Log a single line item to the appropriate chat file
-	static void saveHistory(const std::string& filename, const LLChat& chat);
-
-	// Prefer the above version - it saves more metadata about the item
 	static void saveHistory(const std::string& filename,
 				const std::string& from,
 				const LLUUID& from_id,
 				const std::string& line);
 
+	/** @deprecated @see loadAllHistory() */
+	static void loadHistory(const std::string& filename, 
+		                    void (*callback)(ELogLineType, const LLSD&, void*), 
+							void* userdata);
+
 	static void loadAllHistory(const std::string& file_name, std::list<LLSD>& messages);
 private:
 	static std::string cleanFileName(std::string filename);
 };
 
+/**
+ * Formatter for the plain text chat log files
+ */
+class LLChatLogFormatter
+{
+public:
+	LLChatLogFormatter(const LLSD& im) : mIM(im) {}
+	virtual ~LLChatLogFormatter() {};
+
+	friend std::ostream& operator<<(std::ostream& str, const LLChatLogFormatter& formatter)
+	{
+		formatter.format(formatter.mIM, str);
+		return str;
+	}
+
+protected:
+
+	/**
+	 * Format an instant message to a stream
+	 * Timestamps and sender names are required
+	 * New lines of multilined messages are prepended with a space
+	 */
+	void format(const LLSD& im, std::ostream& ostr) const;
+
+	LLSD mIM;
+};
+
 /**
  * Parser for the plain text chat log files
  */
@@ -74,7 +101,7 @@ public:
 	 *
 	 * @return false if failed to parse mandatory data - message text
 	 */
-	static bool parse(const std::string& raw, LLSD& im);
+	static bool parse(std::string& raw, LLSD& im);
 
 protected:
 	LLChatLogParser();
@@ -86,6 +113,5 @@ extern const std::string IM_TIME; //("time");
 extern const std::string IM_TEXT; //("message");
 extern const std::string IM_FROM; //("from");
 extern const std::string IM_FROM_ID; //("from_id");
-extern const std::string IM_SOURCE_TYPE; //("source_type");
 
 #endif
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index f16cc4cef4..180695e40b 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -46,6 +46,8 @@
 #include "llchathistory.h"
 #include "llstylemap.h"
 
+#include "llavatarnamecache.h"
+
 #include "lldraghandle.h"
 
 #include "llbottomtray.h"
@@ -179,7 +181,21 @@ void	LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args)
 
 	if (gSavedPerAccountSettings.getBOOL("LogNearbyChat"))
 	{
-		LLLogChat::saveHistory("chat", chat);
+		std::string from_name = chat.mFromName;
+
+		if (chat.mSourceType == CHAT_SOURCE_AGENT)
+		{
+			// if the chat is coming from an agent, log the complete name
+			LLAvatarName av_name;
+			LLAvatarNameCache::get(chat.mFromID, &av_name);
+
+			if (!av_name.mIsDisplayNameDefault)
+			{
+				from_name = av_name.getCompleteName();
+			}
+		}
+
+		LLLogChat::saveHistory("chat", from_name, chat.mFromID, chat.mText);
 	}
 }
 
@@ -248,11 +264,23 @@ void LLNearbyChat::processChatHistoryStyleUpdate(const LLSD& newvalue)
 		nearby_chat->updateChatHistoryStyle();
 }
 
-bool isTwoWordsName(const std::string& name)
+bool isWordsName(const std::string& name)
 {
-	//checking for a single space
-	S32 pos = name.find(' ', 0);
-	return std::string::npos != pos && name.rfind(' ', name.length()) == pos && 0 != pos && name.length()-1 != pos;
+	// checking to see if it's display name plus username in parentheses 
+	S32 open_paren = name.find(" (", 0);
+	S32 close_paren = name.find(')', 0);
+
+	if (open_paren != std::string::npos &&
+		close_paren == name.length()-1)
+	{
+		return true;
+	}
+	else
+	{
+		//checking for a single space
+		S32 pos = name.find(' ', 0);
+		return std::string::npos != pos && name.rfind(' ', name.length()) == pos && 0 != pos && name.length()-1 != pos;
+	}
 }
 
 void LLNearbyChat::loadHistory()
@@ -275,9 +303,10 @@ void LLNearbyChat::loadHistory()
 			from_id = msg[IM_FROM_ID].asUUID();
 		}
 		else
-		{
-			gCacheName->getUUID(from, from_id);
-		}
+ 		{
+			std::string legacy_name = gCacheName->buildLegacyName(from);
+ 			gCacheName->getUUID(legacy_name, from_id);
+ 		}
 
 		LLChat chat;
 		chat.mFromName = from;
@@ -286,18 +315,15 @@ void LLNearbyChat::loadHistory()
 		chat.mTimeStr = msg[IM_TIME].asString();
 		chat.mChatStyle = CHAT_STYLE_HISTORY;
 
-		if (msg.has(IM_SOURCE_TYPE))
-		{
-			S32 source_type = msg[IM_SOURCE_TYPE].asInteger();
-			chat.mSourceType = (EChatSourceType)source_type;
-		}
-		else if (from_id.isNull() && SYSTEM_FROM == from)
+		chat.mSourceType = CHAT_SOURCE_AGENT;
+		if (from_id.isNull() && SYSTEM_FROM == from)
 		{	
 			chat.mSourceType = CHAT_SOURCE_SYSTEM;
+			
 		}
 		else if (from_id.isNull())
 		{
-			chat.mSourceType = isTwoWordsName(from) ? CHAT_SOURCE_UNKNOWN : CHAT_SOURCE_OBJECT;
+			chat.mSourceType = isWordsName(from) ? CHAT_SOURCE_UNKNOWN : CHAT_SOURCE_OBJECT;
 		}
 
 		addMessage(chat, true, do_not_log);
-- 
cgit v1.2.3


From c0e9594e9d509ba665c3b5a2fe01049b0dbb92fd Mon Sep 17 00:00:00 2001
From: Merov Linden <merov@lindenlab.com>
Date: Mon, 25 Oct 2010 10:27:37 -0700
Subject: STORM-173 : use isEmpty() instead of getFirstRootNode() to check
 selection

---
 indra/newview/llviewermenu.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index dc7c6f17a9..68935d536b 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -4160,8 +4160,7 @@ class LLObjectEnableReturn : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
-		if (!node)
+		if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
 		{
 			// Do not enable if nothing selected
 			return false;
-- 
cgit v1.2.3


From e98eff02ae4894050267a6b302c4887393ff1244 Mon Sep 17 00:00:00 2001
From: Leyla Farazha <leyla@lindenlab.com>
Date: Mon, 25 Oct 2010 10:31:47 -0700
Subject: DN-181 Chat & IM logs saved in unreadable .llsd instead of .txt -
 fixing saving of p2p logs

---
 indra/newview/llimview.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index ba0dc31005..349ef8185f 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -527,9 +527,10 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
 
 void LLIMModel::LLIMSession::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name)
 {
-	if (av_name.getLegacyName().empty())
+	if (av_name.mLegacyFirstName.empty())
 	{
-		// if display names is off the legacy name will be the display name
+		// if mLegacyFirstName is empty it means display names is off and the 
+		// data came from the gCacheName, mDisplayName will be the legacy name
 		mHistoryFileName = LLCacheName::cleanFullName(av_name.mDisplayName);
 	}
 	else
-- 
cgit v1.2.3


From ba0d4ccaf49753bd8c3eca127d41fa7072782473 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Mon, 25 Oct 2010 21:38:22 +0300
Subject: STORM-341 FIXED Crash on exiting viewer while Outfit Editor is opened
 in detached Appearance SP.

Reason: An inventory observer (LLFilteredWearableListManager) tried to use
a deleted collect functor (LLFilterItem::collector in LLPanelOutfitEdit::mListViewItemTypes).

Fix: De-register (and delete) the observer when the collector gets deleted.
---
 indra/newview/llpaneloutfitedit.cpp | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 5638374178..63076364bc 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -404,6 +404,7 @@ LLPanelOutfitEdit::LLPanelOutfitEdit()
 	mAddWearablesPanel(NULL),
 	mFolderViewFilterCmbBox(NULL),
 	mListViewFilterCmbBox(NULL),
+	mWearableListManager(NULL),
 	mPlusBtn(NULL),
 	mWearablesGearMenuBtn(NULL),
 	mGearMenuBtn(NULL)
@@ -431,6 +432,7 @@ LLPanelOutfitEdit::LLPanelOutfitEdit()
 
 LLPanelOutfitEdit::~LLPanelOutfitEdit()
 {
+	delete mWearableListManager;
 	delete mSavedFolderState;
 
 	delete mCOFDragAndDropObserver;
-- 
cgit v1.2.3