From ad4002caea460547870a94b09b804ea1e93b8b00 Mon Sep 17 00:00:00 2001
From: Sergei Litovchuk <slitovchuk@productengine.com>
Date: Tue, 29 Jun 2010 20:07:33 +0300
Subject: EXT-7676 FIXED Added items sorting from gear menu for 'Add Wearable'.
 - Added new gear menu when 'Add Wearable' panel is open in 'Edit Outfit'. -
 Added wearable items list comparator to sort by wearable creation date. -
 Added storing sorting type in viewer settings.

Reviewed by Neal Orman at https://codereview.productengine.com/secondlife/r/661/.

--HG--
branch : product-engine
---
 indra/newview/app_settings/settings.xml            |  11 ++
 indra/newview/llinventorylistitem.cpp              |  11 ++
 indra/newview/llinventorylistitem.h                |   3 +
 indra/newview/llpaneloutfitedit.cpp                | 172 ++++++++++++++++++++-
 indra/newview/llpaneloutfitedit.h                  |   5 +-
 indra/newview/llwearableitemslist.cpp              |  44 +++++-
 indra/newview/llwearableitemslist.h                |  26 ++++
 .../default/xui/en/menu_add_wearable_gear.xml      |  41 +++++
 8 files changed, 303 insertions(+), 10 deletions(-)
 create mode 100644 indra/newview/skins/default/xui/en/menu_add_wearable_gear.xml

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index dd93f1bfa6..3055207ba9 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -35,6 +35,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>AddWearableSortOrder</key>
+    <map>
+      <key>Comment</key>
+      <string>Specifies sort order for add wearable panel (0 = name, 1 = date, 2 = by type)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>AgentPause</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp
index c487aa10a7..7ed4c0dbe5 100644
--- a/indra/newview/llinventorylistitem.cpp
+++ b/indra/newview/llinventorylistitem.cpp
@@ -211,6 +211,17 @@ const std::string& LLPanelInventoryListItemBase::getDescription() const
 	return inv_item->getDescription();
 }
 
+time_t LLPanelInventoryListItemBase::getCreationDate() const
+{
+	LLViewerInventoryItem* inv_item = getItem();
+	if (NULL == inv_item)
+	{
+		return 0;
+	}
+
+	return inv_item->getCreationDate();
+}
+
 LLViewerInventoryItem* LLPanelInventoryListItemBase::getItem() const
 {
 	return gInventory.getItem(mInventoryItemUUID);
diff --git a/indra/newview/llinventorylistitem.h b/indra/newview/llinventorylistitem.h
index f29d92d51c..600bf77230 100644
--- a/indra/newview/llinventorylistitem.h
+++ b/indra/newview/llinventorylistitem.h
@@ -146,6 +146,9 @@ public:
 	/** Get the description of a corresponding inventory item */
 	const std::string& getDescription() const;
 
+	/** Get the creation date of a corresponding inventory item */
+	time_t getCreationDate() const;
+
 	/** Get the associated inventory item */
 	LLViewerInventoryItem* getItem() const;
 
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index ffd879dfd7..6a85969649 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -43,7 +43,6 @@
 #include "llcofwearables.h"
 #include "llfilteredwearablelist.h"
 #include "llinventory.h"
-#include "llinventoryitemslist.h"
 #include "llviewercontrol.h"
 #include "llui.h"
 #include "llfloater.h"
@@ -84,6 +83,11 @@ const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
 
 static const std::string REVERT_BTN("revert_btn");
 
+
+///////////////////////////////////////////////////////////////////////////////
+// LLShopURLDispatcher
+///////////////////////////////////////////////////////////////////////////////
+
 class LLShopURLDispatcher
 {
 public:
@@ -143,6 +147,10 @@ std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex
 	return gSavedSettings.getString(setting_name);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// LLPanelOutfitEditGearMenu
+///////////////////////////////////////////////////////////////////////////////
+
 class LLPanelOutfitEditGearMenu
 {
 public:
@@ -158,7 +166,6 @@ public:
 		if (menu)
 		{
 			populateCreateWearableSubmenus(menu);
-			menu->buildDrawLabels();
 		}
 
 		return menu;
@@ -207,6 +214,131 @@ private:
 	}
 };
 
+///////////////////////////////////////////////////////////////////////////////
+// LLAddWearablesGearMenu
+///////////////////////////////////////////////////////////////////////////////
+
+class LLAddWearablesGearMenu : public LLInitClass<LLAddWearablesGearMenu>
+{
+public:
+	static LLMenuGL* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
+	{
+		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+		llassert(flat_list);
+		llassert(inventory_panel);
+
+		registrar.add("AddWearable.Gear.Sort", boost::bind(onSort, flat_list, inventory_panel, _2));
+		enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list, inventory_panel, _2));
+		enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel, _2));
+
+		LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(
+			"menu_add_wearable_gear.xml",
+			LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
+
+		return menu;
+	}
+
+private:
+	static void onSort(LLWearableItemsList* flat_list,
+					   LLInventoryPanel* inventory_panel,
+					   LLSD::String sort_order_str)
+	{
+		if (!flat_list || !inventory_panel) return;
+
+		LLWearableItemsList::ESortOrder	sort_order;
+
+		if ("by_most_recent" == sort_order_str)
+		{
+			sort_order = LLWearableItemsList::E_SORT_BY_MOST_RECENT;
+		}
+		else if ("by_name" == sort_order_str)
+		{
+			sort_order = LLWearableItemsList::E_SORT_BY_NAME;
+		}
+		else if ("by_type" == sort_order_str)
+		{
+			sort_order = LLWearableItemsList::E_SORT_BY_TYPE;
+		}
+		else
+		{
+			llwarns << "Unrecognized sort order action" << llendl;
+			return;
+		}
+
+		if (inventory_panel->getVisible())
+		{
+			inventory_panel->setSortOrder(sort_order);
+		}
+		else
+		{
+			flat_list->setSortOrder(sort_order);
+			gSavedSettings.setU32("AddWearableSortOrder", sort_order);
+		}
+	}
+
+	static bool onCheck(LLWearableItemsList* flat_list,
+						LLInventoryPanel* inventory_panel,
+						LLSD::String sort_order_str)
+	{
+		if (!inventory_panel || !flat_list) return false;
+
+		// Inventory panel uses its own sort order independent from
+		// flat list view so this flag is used to distinguish between
+		// currently visible "tree" or "flat" representation of inventory.
+		bool inventory_tree_visible = inventory_panel->getVisible();
+
+		if (inventory_tree_visible)
+		{
+			U32 sort_order = inventory_panel->getSortOrder();
+
+			if ("by_most_recent" == sort_order_str)
+			{
+				return LLWearableItemsList::E_SORT_BY_MOST_RECENT & sort_order;
+			}
+			else if ("by_name" == sort_order_str)
+			{
+				// If inventory panel is not sorted by date then it is sorted by name.
+				return LLWearableItemsList::E_SORT_BY_MOST_RECENT & ~sort_order;
+			}
+			llwarns << "Unrecognized inventory panel sort order" << llendl;
+		}
+		else
+		{
+			LLWearableItemsList::ESortOrder	sort_order = flat_list->getSortOrder();
+
+			if ("by_most_recent" == sort_order_str)
+			{
+				return LLWearableItemsList::E_SORT_BY_MOST_RECENT == sort_order;
+			}
+			else if ("by_name" == sort_order_str)
+			{
+				return LLWearableItemsList::E_SORT_BY_NAME == sort_order;
+			}
+			else if ("by_type" == sort_order_str)
+			{
+				return LLWearableItemsList::E_SORT_BY_TYPE == sort_order;
+			}
+			llwarns << "Unrecognized wearable list sort order" << llendl;
+		}
+		return false;
+	}
+
+	static bool onVisible(LLInventoryPanel* inventory_panel,
+						  LLSD::String sort_order_str)
+	{
+		// Enable sorting by type only for the flat list of items
+		// because inventory panel doesn't support this kind of sorting.
+		return ( "by_type" == sort_order_str )
+				&&	( !inventory_panel || !inventory_panel->getVisible() );
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// LLCOFDragAndDropObserver
+///////////////////////////////////////////////////////////////////////////////
+
 class LLCOFDragAndDropObserver : public LLInventoryAddItemByAssetObserver
 {
 public:
@@ -242,12 +374,17 @@ void LLCOFDragAndDropObserver::done()
 	LLAppearanceMgr::instance().updateAppearanceFromCOF();
 }
 
+///////////////////////////////////////////////////////////////////////////////
+// LLPanelOutfitEdit
+///////////////////////////////////////////////////////////////////////////////
+
 LLPanelOutfitEdit::LLPanelOutfitEdit()
 :	LLPanel(), 
 	mSearchFilter(NULL),
 	mCOFWearables(NULL),
 	mInventoryItemsPanel(NULL),
 	mGearMenu(NULL),
+	mAddWearablesGearMenu(NULL),
 	mCOFDragAndDropObserver(NULL),
 	mInitialized(false),
 	mAddWearablesPanel(NULL),
@@ -384,10 +521,11 @@ BOOL LLPanelOutfitEdit::postBuild()
 	childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
 
 	mWearablesListViewPanel = getChild<LLPanel>("filtered_wearables_panel");
-	mWearableItemsList = getChild<LLInventoryItemsList>("list_view");
+	mWearableItemsList = getChild<LLWearableItemsList>("list_view");
 	mWearableItemsList->setCommitOnSelectionChange(true);
 	mWearableItemsList->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onInventorySelectionChange, this));
 	mWearableItemsList->setDoubleClickCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
+	mWearableItemsList->setSortOrder((LLWearableItemsList::ESortOrder)gSavedSettings.getU32("AddWearableSortOrder"));
 
 	mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this));
 	return TRUE;
@@ -894,13 +1032,33 @@ bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch
 
 void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
 {
-	if(!mGearMenu)
+	LLMenuGL* menu = NULL;
+
+	if (mAddWearablesPanel->getVisible())
+	{
+		if (!mAddWearablesGearMenu)
+		{
+			mAddWearablesGearMenu = LLAddWearablesGearMenu::create(mWearableItemsList, mInventoryItemsPanel);
+		}
+
+		menu = mAddWearablesGearMenu;
+	}
+	else
 	{
-		mGearMenu = LLPanelOutfitEditGearMenu::create();
+		if (!mGearMenu)
+		{
+			mGearMenu = LLPanelOutfitEditGearMenu::create();
+		}
+
+		menu = mGearMenu;
 	}
 
-	S32 menu_y = mGearMenu->getRect().getHeight() + clicked_button->getRect().getHeight();
-	LLMenuGL::showPopup(clicked_button, mGearMenu, 0, menu_y);
+	if (!menu) return;
+
+	menu->arrangeAndClear(); // update menu height
+	S32 menu_y = menu->getRect().getHeight() + clicked_button->getRect().getHeight();
+	menu->buildDrawLabels();
+	LLMenuGL::showPopup(clicked_button, menu, 0, menu_y);
 }
 
 void LLPanelOutfitEdit::onAddMoreButtonClicked()
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index de1bf87fb3..924765d308 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -43,8 +43,8 @@
 #include "llremoteparcelrequest.h"
 #include "llinventory.h"
 #include "llinventoryfunctions.h"
-#include "llinventoryitemslist.h"
 #include "llinventorymodel.h"
+#include "llwearableitemslist.h"
 
 class LLButton;
 class LLCOFWearables;
@@ -211,7 +211,7 @@ private:
 	LLComboBox*			mListViewFilterCmbBox;
 
 	LLFilteredWearableListManager* 	mWearableListManager;
-	LLInventoryItemsList* 			mWearableItemsList;
+	LLWearableItemsList* 			mWearableItemsList;
 	LLPanel*						mWearablesListViewPanel;
 
 	LLCOFDragAndDropObserver* mCOFDragAndDropObserver;
@@ -221,6 +221,7 @@ private:
 
 	LLCOFWearables*		mCOFWearables;
 	LLMenuGL*			mGearMenu;
+	LLMenuGL*			mAddWearablesGearMenu;
 	bool				mInitialized;
 	std::auto_ptr<LLSaveOutfitComboBtn> mSaveComboBtn;
 
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index cf165f8f66..17b871338f 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -437,11 +437,27 @@ LLWearableItemTypeNameComparator::ETypeListOrder LLWearableItemTypeNameComparato
 	}
 }
 
+/*virtual*/
+bool LLWearableItemCreationDateComparator::doCompare(const LLPanelInventoryListItemBase* item1, const LLPanelInventoryListItemBase* item2) const
+{
+	time_t date1 = item1->getCreationDate();
+	time_t date2 = item2->getCreationDate();
+
+	if (date1 == date2)
+	{
+		return LLWearableItemNameComparator::doCompare(item1, item2);
+	}
+
+	return date1 > date2;
+}
+
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 
 static const LLWearableItemTypeNameComparator WEARABLE_TYPE_NAME_COMPARATOR;
+static const LLWearableItemNameComparator WEARABLE_NAME_COMPARATOR;
+static const LLWearableItemCreationDateComparator WEARABLE_CREATION_DATE_COMPARATOR;
 
 static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_items_list");
 
@@ -453,7 +469,7 @@ LLWearableItemsList::Params::Params()
 LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p)
 :	LLInventoryItemsList(p)
 {
-	setComparator(&WEARABLE_TYPE_NAME_COMPARATOR);
+	setSortOrder(E_SORT_BY_TYPE, false);
 	mIsStandalone = p.standalone;
 	if (mIsStandalone)
 	{
@@ -553,6 +569,32 @@ void LLWearableItemsList::onRightClick(S32 x, S32 y)
 	ContextMenu::instance().show(this, selected_uuids, x, y);
 }
 
+void LLWearableItemsList::setSortOrder(ESortOrder sort_order, bool sort_now)
+{
+	switch (sort_order)
+	{
+	case E_SORT_BY_MOST_RECENT:
+		setComparator(&WEARABLE_CREATION_DATE_COMPARATOR);
+		break;
+	case E_SORT_BY_NAME:
+		setComparator(&WEARABLE_NAME_COMPARATOR);
+		break;
+	case E_SORT_BY_TYPE:
+		setComparator(&WEARABLE_TYPE_NAME_COMPARATOR);
+		break;
+
+	// No "default:" to raise compiler warning
+	// if we're not handling something
+	}
+
+	mSortOrder = sort_order;
+
+	if (sort_now)
+	{
+		sort();
+	}
+}
+
 //////////////////////////////////////////////////////////////////////////
 /// ContextMenu
 //////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index d16a2a89c8..b6d210b4fe 100644
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -310,6 +310,19 @@ private:
 	static LLWearableItemTypeNameComparator::ETypeListOrder getTypeListOrder(LLAssetType::EType item_type);
 };
 
+/**
+ * @class LLWearableItemCreationDateComparator
+ *
+ * Comparator for sorting wearable list items by creation date (newest go first).
+ */
+class LLWearableItemCreationDateComparator : public LLWearableItemNameComparator
+{
+	LOG_CLASS(LLWearableItemCreationDateComparator);
+
+protected:
+	/*virtual*/ bool doCompare(const LLPanelInventoryListItemBase* item1, const LLPanelInventoryListItemBase* item2) const;
+};
+
 /**
  * @class LLWearableItemsList
  *
@@ -362,6 +375,13 @@ public:
 		Params();
 	};
 
+	typedef enum e_sort_order {
+		// Values should be compatible with InventorySortOrder setting.
+		E_SORT_BY_NAME			= 0,
+		E_SORT_BY_MOST_RECENT	= 1,
+		E_SORT_BY_TYPE			= 2,
+	} ESortOrder;
+
 	virtual ~LLWearableItemsList();
 
 	/*virtual*/ void addNewItem(LLViewerInventoryItem* item, bool rearrange = true);
@@ -376,6 +396,10 @@ public:
 
 	bool isStandalone() const { return mIsStandalone; }
 
+	ESortOrder getSortOrder() const { return mSortOrder; }
+
+	void setSortOrder(ESortOrder sort_order, bool sort_now = true);
+
 protected:
 	friend class LLUICtrlFactory;
 	LLWearableItemsList(const LLWearableItemsList::Params& p);
@@ -384,6 +408,8 @@ protected:
 
 	bool mIsStandalone;
 	bool mWornIndicationEnabled;
+
+	ESortOrder		mSortOrder;
 };
 
 #endif //LL_LLWEARABLEITEMSLIST_H
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
new file mode 100644
index 0000000000..1925d3396f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_add_wearable_gear.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu
+ layout="topleft"
+ name="Add Wearable Gear Menu">
+    <menu_item_check
+     label="Sort by Most Recent"
+     layout="topleft"
+     name="sort_by_most_recent">
+        <on_check
+         function="AddWearable.Gear.Check"
+         parameter="by_most_recent" />
+        <on_click
+         function="AddWearable.Gear.Sort"
+         parameter="by_most_recent" />
+    </menu_item_check>
+    <menu_item_check
+     label="Sort by Name"
+     layout="topleft"
+     name="sort_by_name">
+        <on_check
+         function="AddWearable.Gear.Check"
+         parameter="by_name" />
+        <on_click
+         function="AddWearable.Gear.Sort"
+         parameter="by_name" />
+    </menu_item_check>
+    <menu_item_check
+     label="Sort by Type"
+     layout="topleft"
+     name="sort_by_type">
+        <on_check
+         function="AddWearable.Gear.Check"
+         parameter="by_type" />
+        <on_click
+         function="AddWearable.Gear.Sort"
+         parameter="by_type" />
+        <on_visible
+         function="AddWearable.Gear.Visible"
+         parameter="by_type" />
+    </menu_item_check>
+</menu>
-- 
cgit v1.2.3


From 5285a7fa7ec67c2337c5f071e6785b143e24c9a6 Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Thu, 1 Jul 2010 20:00:00 +0300
Subject: EXT-7565 FIXED Would be nice to preserve selection while switching
 between folder/list view modes

- Created callback called 'SaveSelecton' (which preserves selection while switching between folder/list view modes) for folder/list view modes buttons in LLPanelOutfitEdit.

- Added 'scrollToShowFirstSelectedItem' method in the LLFlatListView which scrools and shows the first selected item in case multiselection.

- It's possible to set selection for flat list view items before list is build. The result is that any items will be selected. To get rid of it:
   1. Overrided LLFlatListView::selectItemByValue method in LLInventoryItemsList so that if list is not created yet, items ids are saved to the vector.
   2. Added 'LLInventoryItemsList::updateSelection()' method which selects items with ids from that vector when list is created.

- A little refactoring: moved funcionality of updating WearablesPanel's verb buttons to the separate method called LLPanelOutfitEdit::updateWearablesPanelVerbButtons() to made code more readable and self-explanatory

Reviewed by Vadim Savchuk and Neal Orman at https://codereview.productengine.com/secondlife/r/579/

--HG--
branch : product-engine
---
 indra/llui/llflatlistview.cpp          | 12 ++++++
 indra/llui/llflatlistview.h            |  1 +
 indra/newview/llinventoryitemslist.cpp | 37 +++++++++++++++++
 indra/newview/llinventoryitemslist.h   |  7 ++++
 indra/newview/llpaneloutfitedit.cpp    | 72 +++++++++++++++++++++++++++++++---
 indra/newview/llpaneloutfitedit.h      |  6 +++
 6 files changed, 129 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index b87851490d..a3debdb19a 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -776,6 +776,18 @@ bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select)
 	return true;
 }
 
+void LLFlatListView::scrollToShowFirstSelectedItem()
+{
+	if (!mSelectedItemPairs.size())	return;
+
+	LLRect selected_rc = mSelectedItemPairs.front()->first->getRect();
+
+	if (selected_rc.isValid())
+	{
+		scrollToShowRect(selected_rc);
+	}
+}
+
 LLRect LLFlatListView::getLastSelectedItemRect()
 {
 	if (!mSelectedItemPairs.size())
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index ded46d8122..bf72289c47 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -293,6 +293,7 @@ public:
 
 	bool updateValue(const LLSD& old_value, const LLSD& new_value);
 
+	void scrollToShowFirstSelectedItem();
 
 	void selectFirstItem	();
 	void selectLastItem		();
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp
index fbb3774917..83725f40ee 100644
--- a/indra/newview/llinventoryitemslist.cpp
+++ b/indra/newview/llinventoryitemslist.cpp
@@ -85,6 +85,37 @@ boost::signals2::connection LLInventoryItemsList::setRefreshCompleteCallback(con
 	return mRefreshCompleteSignal.connect(cb);
 }
 
+bool LLInventoryItemsList::selectItemByValue(const LLSD& value, bool select)
+{
+	if (!LLFlatListView::selectItemByValue(value, select) && !value.isUndefined())
+	{
+		mSelectTheseIDs.push_back(value);
+		return false;
+	}
+	return true;
+}
+
+void LLInventoryItemsList::updateSelection()
+{
+	if(mSelectTheseIDs.empty()) return;
+
+	std::vector<LLSD> cur;
+	getValues(cur);
+
+	for(std::vector<LLSD>::const_iterator cur_id_it = cur.begin(); cur_id_it != cur.end() && !mSelectTheseIDs.empty(); ++cur_id_it)
+	{
+		uuid_vec_t::iterator select_ids_it = std::find(mSelectTheseIDs.begin(), mSelectTheseIDs.end(), *cur_id_it);
+		if(select_ids_it != mSelectTheseIDs.end())
+		{
+			selectItemByUUID(*select_ids_it);
+			mSelectTheseIDs.erase(select_ids_it);
+		}
+	}
+
+	scrollToShowFirstSelectedItem();
+	mSelectTheseIDs.clear();
+}
+
 void LLInventoryItemsList::doIdle()
 {
 	if (!mNeedsRefresh) return;
@@ -149,6 +180,12 @@ void LLInventoryItemsList::refresh()
 	bool needs_refresh = add_limit_exceeded;
 	setNeedsRefresh(needs_refresh);
 	setForceRefresh(needs_refresh);
+
+	// After list building completed, select items that had been requested to select before list was build
+	if(!needs_refresh)
+	{
+		updateSelection();
+	}
 }
 
 void LLInventoryItemsList::computeDifference(
diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h
index 71c7b6a675..5800111f46 100644
--- a/indra/newview/llinventoryitemslist.h
+++ b/indra/newview/llinventoryitemslist.h
@@ -68,6 +68,10 @@ public:
 	 */
 	void setForceRefresh(bool force_refresh){ mForceRefresh = force_refresh; }
 
+	virtual bool selectItemByValue(const LLSD& value, bool select = true);
+
+	void updateSelection();
+
 	/**
 	 * Idle routine used to refresh the list regardless of the current list
 	 * visibility, unlike draw() which is called only for the visible list.
@@ -104,6 +108,9 @@ protected:
 private:
 	uuid_vec_t mIDs; // IDs of items that were added in refreshList().
 					 // Will be used in refresh() to determine added and removed ids
+
+	uuid_vec_t mSelectTheseIDs; // IDs that will be selected if list is not loaded till now
+
 	bool mNeedsRefresh;
 
 	bool mForceRefresh;
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 6a85969649..a04a040141 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -42,6 +42,7 @@
 #include "lloutfitobserver.h"
 #include "llcofwearables.h"
 #include "llfilteredwearablelist.h"
+#include "llfolderviewitem.h"
 #include "llinventory.h"
 #include "llviewercontrol.h"
 #include "llui.h"
@@ -462,7 +463,9 @@ BOOL LLPanelOutfitEdit::postBuild()
 
 	childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
 	childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesFolderView, this), NULL);
+	childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
 	childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesListView, this), NULL);
+	childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
 	childSetCommitCallback("wearables_gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
 	childSetCommitCallback("gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
 	childSetCommitCallback("shop_btn_1", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
@@ -610,9 +613,7 @@ void LLPanelOutfitEdit::showWearablesListView()
 {
 	if(switchPanels(mInventoryItemsPanel, mWearablesListViewPanel))
 	{
-		mFolderViewBtn->setToggleState(FALSE);
-		mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign());
-		mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign());
+		updateWearablesPanelVerbButtons();
 		updateFiltersVisibility();
 	}
 	mListViewBtn->setToggleState(TRUE);
@@ -622,9 +623,7 @@ void LLPanelOutfitEdit::showWearablesFolderView()
 {
 	if(switchPanels(mWearablesListViewPanel, mInventoryItemsPanel))
 	{
-		mListViewBtn->setToggleState(FALSE);
-		mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign());
-		mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign());
+		updateWearablesPanelVerbButtons();
 		updateFiltersVisibility();
 	}
 	mFolderViewBtn->setToggleState(TRUE);
@@ -1138,5 +1137,66 @@ void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list)
 //	return selected_id;
 }
 
+void LLPanelOutfitEdit::updateWearablesPanelVerbButtons()
+{
+	if(mWearablesListViewPanel->getVisible())
+	{
+		mFolderViewBtn->setToggleState(FALSE);
+		mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign());
+		mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign());
+	}
+	else if(mInventoryItemsPanel->getVisible())
+	{
+		mListViewBtn->setToggleState(FALSE);
+		mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign());
+		mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign());
+	}
+}
+
+void LLPanelOutfitEdit::saveListSelection()
+{
+	if(mWearablesListViewPanel->getVisible())
+	{
+		std::set<LLUUID> selected_ids = mInventoryItemsPanel->getRootFolder()->getSelectionList();
+
+		if(!selected_ids.size()) return;
+
+		mWearableItemsList->resetSelection();
+
+		for (std::set<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id)
+		{
+			mWearableItemsList->selectItemByUUID(*item_id, true);
+		}
+		mWearableItemsList->scrollToShowFirstSelectedItem();
+	}
+	else if(mInventoryItemsPanel->getVisible())
+	{
+		std::vector<LLUUID> selected_ids;
+		mWearableItemsList->getSelectedUUIDs(selected_ids);
+
+		if(!selected_ids.size()) return;
+
+		mInventoryItemsPanel->clearSelection();
+		LLFolderView* root = mInventoryItemsPanel->getRootFolder();
+
+		if(!root) return;
+
+		for(std::vector<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id)
+		{
+			LLFolderViewItem* item = root->getItemByID(*item_id);
+			if (!item) continue;
+
+			LLFolderViewFolder* parent = item->getParentFolder();
+			if(parent)
+			{
+				parent->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
+			}
+			mInventoryItemsPanel->getRootFolder()->changeSelection(item, TRUE);
+		}
+		mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
+	}
+
+}
+
 
 // EOF
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 924765d308..c19b43c9fd 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -140,6 +140,12 @@ public:
 	void showWearablesListView();
 	void showWearablesFolderView();
 
+	/**
+	 * Method preserves selection while switching between folder/list view modes
+	*/
+	void saveListSelection();
+
+	void updateWearablesPanelVerbButtons();
 	void updateFiltersVisibility();
 
 	void onFolderViewFilterCommitted(LLUICtrl* ctrl);
-- 
cgit v1.2.3


From 863e6ea4035683610e35bfa90171b7a35b9dce64 Mon Sep 17 00:00:00 2001
From: Vladimir Pchelko <pchelko@productengine.com>
Date: Fri, 2 Jul 2010 17:17:19 +0300
Subject: EXT-7473 FIXED ("Share" button was added to "gear" menu in Inventory
 SP.)

Reviewed by Vadim Savchuk at https://codereview.productengine.com/secondlife/r/678/

--HG--
branch : product-engine
---
 indra/newview/llpanelmaininventory.cpp                        |  8 ++++++++
 indra/newview/llsidepanelinventory.h                          |  5 +++--
 .../skins/default/xui/en/menu_inventory_gear_default.xml      | 11 +++++++++++
 3 files changed, 22 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index 9eece81861..7412812c62 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -53,6 +53,8 @@
 #include "lltooldraganddrop.h"
 #include "llviewermenu.h"
 #include "llviewertexturelist.h"
+#include "llsidepanelinventory.h"
+#include "llsidetray.h"
 
 const std::string FILTERS_FILENAME("filters.xml");
 
@@ -1158,6 +1160,12 @@ BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata)
 		return FALSE;
 	}
 
+	if (command_name == "share")
+	{
+		LLSidepanelInventory* parent = dynamic_cast<LLSidepanelInventory*>(LLSideTray::getInstance()->getPanel("sidepanel_inventory"));
+		return parent ? parent->canShare() : FALSE;
+	}
+
 	return TRUE;
 }
 
diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h
index 951fdd630c..f2f2509f9a 100644
--- a/indra/newview/llsidepanelinventory.h
+++ b/indra/newview/llsidepanelinventory.h
@@ -58,6 +58,9 @@ public:
 	void showTaskInfoPanel();
 	void showInventoryPanel();
 
+	// checks can share selected item(s)
+	bool canShare();
+
 protected:
 	// Tracks highlighted (selected) item in inventory panel.
 	LLInventoryItem *getSelectedItem();
@@ -65,8 +68,6 @@ protected:
 	void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
 	// "wear", "teleport", etc.
 	void performActionOnSelection(const std::string &action);
-	bool canShare();
-
 	void updateVerbs();
 
 	//
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 62365f7cc2..c394700081 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
@@ -81,6 +81,17 @@
 			 function="Inventory.GearDefault.Enable"
 			 parameter="save_texture" />
         </menu_item_call>
+    <menu_item_call
+     label="Share"
+     layout="topleft"
+     name="Share"
+     visible="true">
+     <on_click
+         function="Inventory.Share" />
+     <on_enable
+         function="Inventory.GearDefault.Enable"
+         parameter="share" />
+    </menu_item_call>
     <menu_item_call 
          label="Find Original"
          layout="topleft"
-- 
cgit v1.2.3


From 623dae525dc14a69322266e33421770431c34a66 Mon Sep 17 00:00:00 2001
From: Igor Borovkov <iborovkov@productengine.com>
Date: Mon, 12 Jul 2010 19:47:44 +0300
Subject: EXT-7796 FIXED disabling/enabling presets and camera modes on
 switching to/from camera customize mode

Reviewed by Neal Orman at https://codereview.productengine.com/secondlife/r/732/

--HG--
branch : product-engine
---
 indra/newview/llagent.cpp         |  4 ++++
 indra/newview/llfloatercamera.cpp | 14 ++++++++++++++
 indra/newview/llfloatercamera.h   |  3 +++
 3 files changed, 21 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 4e5fdb1219..92c2570c33 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1785,6 +1785,8 @@ void LLAgent::endAnimationUpdateUI()
 			
 		}
 		gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
+
+		LLFloaterCamera::onAvatarEditingAppearance(false);
 	}
 
 	//---------------------------------------------------------------------
@@ -1891,6 +1893,8 @@ void LLAgent::endAnimationUpdateUI()
 		{
 			mPauseRequest = gAgentAvatarp->requestPause();
 		}
+
+		LLFloaterCamera::onAvatarEditingAppearance(true);
 	}
 
 	if (isAgentAvatarValid())
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index d6effb2b21..0fa536dfad 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -243,6 +243,20 @@ void LLFloaterCamera::resetCameraMode()
 	floater_camera->switchMode(CAMERA_CTRL_MODE_PAN);
 }
 
+void LLFloaterCamera::onAvatarEditingAppearance(bool editing)
+{
+	LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance();
+	if (!floater_camera) return;
+
+	//camera presets (rear, front, etc.)
+	floater_camera->childSetEnabled("preset_views_list", !editing);
+	floater_camera->childSetEnabled("presets_btn", !editing);
+
+	//camera modes (object view, mouselook view)
+	floater_camera->childSetEnabled("camera_modes_list", !editing);
+	floater_camera->childSetEnabled("avatarview_btn", !editing);
+}
+
 void LLFloaterCamera::update()
 {
 	ECameraControlMode mode = determineMode();
diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h
index 564e38d02d..c5f8cd6db5 100644
--- a/indra/newview/llfloatercamera.h
+++ b/indra/newview/llfloatercamera.h
@@ -68,6 +68,9 @@ public:
 	/** resets current camera mode to orbit mode */
 	static void resetCameraMode();
 
+	/** Called when Avatar is entered/exited editing appearance mode */
+	static void onAvatarEditingAppearance(bool editing);
+
 	/* determines actual mode and updates ui */
 	void update();
 
-- 
cgit v1.2.3


From 4965f9f2d5da84d3b60ccb1bc63497fdbfa99e51 Mon Sep 17 00:00:00 2001
From: Igor Borovkov <iborovkov@productengine.com>
Date: Tue, 13 Jul 2010 18:43:30 +0300
Subject: EXT-7668 FIXED prohibited deselecting a single selected item w/o
 using CTRL

Reviewed by Vadim Savchuk at https://codereview.productengine.com/secondlife/r/746/

--HG--
branch : product-engine
---
 indra/llui/llflatlistview.cpp | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index f9e08a3f4c..fbc6295d49 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -608,8 +608,14 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
 		return;
 	}
 
-	if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection();
-	selectItemPair(item_pair, select_item);
+	//no need to do additional commit on selection reset
+	if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(true);
+
+	//only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it
+	if (mask & MASK_CONTROL)
+		selectItemPair(item_pair, select_item);
+	else
+		selectItemPair(item_pair, true);
 }
 
 void LLFlatListView::onItemRightMouseClick(item_pair_t* item_pair, MASK mask)
-- 
cgit v1.2.3