From 32dccaf3d89b40b711d69088a3e390119c7efc7f Mon Sep 17 00:00:00 2001
From: Loren Shih <seraph@lindenlab.com>
Date: Tue, 17 Nov 2009 10:36:11 -0500
Subject: Sidepanel Appearance refactoring.  Work in progress.

1. Changed sidepanel names to have "sidepanel" (e.g. panel_appearance -> sidepanel_appearance)
2. Changed some "Looks" names to "Outfits"
3. Changed LLPanelLooks to LLPanelOutfitsInventory (to match other inventory panel naming)
4. Took out tab from sidepanel_appearance.

--HG--
branch : avatar-pipeline
---
 indra/newview/CMakeLists.txt                       |  10 +-
 indra/newview/llappearancemgr.cpp                  |   6 +-
 indra/newview/llinventoryfilter.cpp                |  17 +-
 indra/newview/llinventorypanel.cpp                 |  35 +-
 indra/newview/llinventorypanel.h                   |   4 +
 indra/newview/llpanelmaininventory.cpp             |   2 +-
 indra/newview/llpaneloutfitsinventory.cpp          | 245 ++++++++++++++
 indra/newview/llpaneloutfitsinventory.h            |  76 +++++
 indra/newview/llsidepanelappearance.cpp            | 373 +++++++++++++++++++++
 indra/newview/llsidepanelappearance.h              | 102 ++++++
 .../skins/default/xui/en/floater_inventory.xml     |   2 +-
 .../default/xui/en/panel_outfits_inventory.xml     |  81 +++++
 .../skins/default/xui/en/panel_side_tray.xml       |   6 +-
 .../skins/default/xui/en/sidepanel_appearance.xml  | 104 ++++++
 14 files changed, 1026 insertions(+), 37 deletions(-)
 create mode 100644 indra/newview/llpaneloutfitsinventory.cpp
 create mode 100644 indra/newview/llpaneloutfitsinventory.h
 create mode 100644 indra/newview/llsidepanelappearance.cpp
 create mode 100644 indra/newview/llsidepanelappearance.h
 create mode 100644 indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
 create mode 100644 indra/newview/skins/default/xui/en/sidepanel_appearance.xml

(limited to 'indra')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 4adef84cd3..e7458529be 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -297,8 +297,6 @@ set(viewer_SOURCE_FILES
     llnotify.cpp
     lloutputmonitorctrl.cpp
     lloverlaybar.cpp
-    llpanelappearance.cpp
-    llpanelappearancetab.cpp
     llpanelavatar.cpp
     llpanelavatarrow.cpp
     llpanelavatartag.cpp
@@ -322,7 +320,6 @@ set(viewer_SOURCE_FILES
     llpanellandmedia.cpp
     llpanellogin.cpp
     llpanellookinfo.cpp
-    llpanellooks.cpp
     llpanelmaininventory.cpp
     llpanelmediasettingsgeneral.cpp
     llpanelmediasettingspermissions.cpp
@@ -330,6 +327,7 @@ set(viewer_SOURCE_FILES
     llpanelmeprofile.cpp
     llpanelobject.cpp
     llpanelobjectinventory.cpp
+    llpaneloutfitsinventory.cpp
     llpanelpeople.cpp
     llpanelpeoplemenus.cpp
     llpanelpermissions.cpp
@@ -370,6 +368,7 @@ set(viewer_SOURCE_FILES
     llsearchcombobox.cpp
     llsearchhistory.cpp
     llselectmgr.cpp
+    llsidepanelappearance.cpp
     llsidepanelinventory.cpp
     llsidepanelinventorysubpanel.cpp
     llsidepaneliteminfo.cpp
@@ -792,8 +791,6 @@ set(viewer_HEADER_FILES
     llnotify.h
     lloutputmonitorctrl.h
     lloverlaybar.h
-    llpanelappearance.h
-    llpanelappearancetab.h
     llpanelavatar.h
     llpanelavatarrow.h
     llpanelavatartag.h
@@ -817,7 +814,6 @@ set(viewer_HEADER_FILES
     llpanellandmedia.h
     llpanellogin.h
     llpanellookinfo.h
-    llpanellooks.h
     llpanelmaininventory.h
     llpanelmediasettingsgeneral.h
     llpanelmediasettingspermissions.h
@@ -825,6 +821,7 @@ set(viewer_HEADER_FILES
     llpanelmeprofile.h
     llpanelobject.h
     llpanelobjectinventory.h
+    llpaneloutfitsinventory.h
     llpanelpeople.h
     llpanelpeoplemenus.h
     llpanelpermissions.h
@@ -867,6 +864,7 @@ set(viewer_HEADER_FILES
     llsearchcombobox.h
     llsearchhistory.h
     llselectmgr.h
+    llsidepanelappearance.h
     llsidepanelinventory.h
     llsidepanelinventorysubpanel.h
     llsidepaneliteminfo.h
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 80ac9e4085..554f270c02 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -40,7 +40,7 @@
 #include "llinventorybridge.h"
 #include "llinventoryobserver.h"
 #include "llnotifications.h"
-#include "llpanelappearance.h"
+#include "llsidepanelappearance.h"
 #include "llsidetray.h"
 #include "llvoavatar.h"
 #include "llvoavatarself.h"
@@ -530,10 +530,10 @@ void LLAppearanceManager::updateCOF(const LLUUID& category, bool append)
 							LLAssetType::AT_LINK_FOLDER, link_waiter);
 
 		// Update the current outfit name of the appearance sidepanel.
-		LLPanelAppearance* panel_appearance = dynamic_cast<LLPanelAppearance *>(LLSideTray::getInstance()->getPanel("panel_appearance"));
+		LLSidepanelAppearance* panel_appearance = dynamic_cast<LLSidepanelAppearance *>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
 		if (panel_appearance)
 		{
-			panel_appearance->refreshCurrentLookName(catp->getName());
+			panel_appearance->refreshCurrentOutfitName(catp->getName());
 		}
 	}
 							  
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index 3e4b3327db..085c96c93d 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -100,17 +100,18 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item)
 	bool passed_type = false;
 	if (mFilterOps.mFilterForCategories)
 	{
-		if (listener->getInventoryType() == LLInventoryType::IT_CATEGORY)
+		// Pass if this item is a category of the filter type, or
+		// if its parent is a category of the filter type.
+		LLUUID uuid = listener->getUUID();
+		if (listener->getInventoryType() != LLInventoryType::IT_CATEGORY)
 		{
-			LLViewerInventoryCategory *cat = gInventory.getCategory(listener->getUUID());
-			if (cat)
-			{
-				passed_type |= ((1LL << cat->getPreferredType() & mFilterOps.mFilterTypes) != U64(0));
-			}
+			const LLInventoryObject *obj = gInventory.getObject(uuid);
+			uuid = obj->getParentUUID();
 		}
-		else
+		LLViewerInventoryCategory *cat = gInventory.getCategory(uuid);
+		if (cat)
 		{
-			passed_type = TRUE;
+			passed_type |= ((1LL << cat->getPreferredType() & mFilterOps.mFilterTypes) != U64(0));
 		}
 	}
 	else
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 7b7090d10d..450ce92412 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -145,23 +145,10 @@ BOOL LLInventoryPanel::postBuild()
 	mInventoryObserver = new LLInventoryPanelObserver(this);
 	mInventory->addObserver(mInventoryObserver);
 
-	// determine the root folder, if any, so inventory contents show just the children
-	// of that folder (i.e. not including the folder itself).
-	const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString);
-
-	if ("LIBRARY" == mStartFolderString)
-	{
-		mStartFolderID = gInventory.getLibraryRootFolderID();
-	}
-	else
-	{
-		mStartFolderID = (preferred_type != LLFolderType::FT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null);
-	}
-
 	// build view of inventory if we need default full hierarchy and inventory ready, otherwise wait for modelChanged() callback
 	if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mHasInventoryConnection)
 	{
-		rebuildViewsFor(mStartFolderID);
+		rebuildViews();
 		mHasInventoryConnection = true;
 		defaultOpenInventory();
 	}
@@ -268,7 +255,7 @@ void LLInventoryPanel::modelChanged(U32 mask)
 	// inventory just initialized, do complete build
 	if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty() && !mHasInventoryConnection)
 	{
-		rebuildViewsFor(mStartFolderID);
+		rebuildViews();
 		mHasInventoryConnection = true;
 		defaultOpenInventory();
 		return;
@@ -388,6 +375,24 @@ void LLInventoryPanel::modelChanged(U32 mask)
 }
 
 
+void LLInventoryPanel::rebuildViews()
+{
+	// Determine the root folder and rebuild the views starting
+	// at that folder.
+	const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString);
+
+	if ("LIBRARY" == mStartFolderString)
+	{
+		mStartFolderID = gInventory.getLibraryRootFolderID();
+	}
+	else
+	{
+		mStartFolderID = (preferred_type != LLFolderType::FT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null);
+	}
+	
+	rebuildViewsFor(mStartFolderID);
+}
+
 void LLInventoryPanel::rebuildViewsFor(const LLUUID& id)
 {
 	LLFolderViewItem* old_view = NULL;
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index e398c44105..0ccee337c9 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -162,6 +162,10 @@ public:
 	void unSelectAll()	{ mFolders->setSelection(NULL, FALSE, FALSE); }
 	
 protected:
+	// Destroys the old views, and regenerates them based on the
+	// start folder ID.
+	void rebuildViews();
+
 	// Given the id and the parent, build all of the folder views.
 	void rebuildViewsFor(const LLUUID& id);
 	virtual void buildNewViews(const LLUUID& id); // made virtual to support derived classes. EXT-719
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index e3b2ab77aa..6c7d434eeb 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -49,7 +49,7 @@
 #include "llviewermenu.h"
 #include "llviewertexturelist.h"
 
-static LLRegisterPanelClassWrapper<LLPanelMainInventory> t_inventory("panel_main_inventory"); // Seraph is this redundant with constructor?
+static LLRegisterPanelClassWrapper<LLPanelMainInventory> t_inventory("panel_main_inventory");
 
 void on_file_loaded_for_save(BOOL success, 
 							 LLViewerFetchedTexture *src_vi,
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
new file mode 100644
index 0000000000..2964bbe792
--- /dev/null
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -0,0 +1,245 @@
+/**
+ * @file llpaneloutfitsinventory.cpp
+ * @brief Outfits inventory panel
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpaneloutfitsinventory.h"
+
+#include "llagent.h"
+#include "llbutton.h"
+#include "llfloaterreg.h"
+#include "lllandmark.h"
+
+#include "llfloaterworldmap.h"
+#include "llfloaterinventory.h"
+#include "llfoldervieweventlistener.h"
+#include "llinventoryfunctions.h"
+#include "llinventorypanel.h"
+#include "llsidetray.h"
+#include "lltabcontainer.h"
+#include "llagentwearables.h"
+#include "llviewerjointattachment.h"
+#include "llviewerfoldertype.h"
+#include "llvoavatarself.h"
+
+static LLRegisterPanelClassWrapper<LLPanelOutfitsInventory> t_inventory("panel_outfits_inventory");
+
+LLPanelOutfitsInventory::LLPanelOutfitsInventory() :
+	mInventoryPanel(NULL),
+	mActionBtn(NULL),
+	mWearBtn(NULL),
+	mEditBtn(NULL)
+{
+	mSavedFolderState = new LLSaveFolderState();
+	mSavedFolderState->setApply(FALSE);
+
+	// LLUICtrlFactory::getInstance()->buildPanel(this, "panel_outfits_inventory.xml");
+}
+
+LLPanelOutfitsInventory::~LLPanelOutfitsInventory()
+{
+	delete mSavedFolderState;
+}
+
+// virtual
+BOOL LLPanelOutfitsInventory::postBuild()
+{
+	mInventoryPanel = getChild<LLInventoryPanel>("outfits_list");
+	mInventoryPanel->setFilterTypes(1LL << LLFolderType::FT_OUTFIT, TRUE);
+	mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
+	mInventoryPanel->openDefaultFolderForType(LLFolderType::FT_MY_OUTFITS);
+	mInventoryPanel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onSelectionChange, this, _1, _2));
+	
+	LLFolderView* root_folder = getRootFolder();
+	root_folder->setReshapeCallback(boost::bind(&LLPanelOutfitsInventory::onSelectionChange, this, _1, _2));
+	
+	mWearBtn = getChild<LLButton>("wear_btn");
+	mEditBtn = getChild<LLButton>("edit_btn");
+	mActionBtn = getChild<LLButton>("action_btn");
+	
+	return TRUE;
+}
+
+// virtual
+void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
+{
+	if (string == "")
+	{
+		mInventoryPanel->setFilterSubString(LLStringUtil::null);
+
+		// re-open folders that were initially open
+		mSavedFolderState->setApply(TRUE);
+		getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
+		LLOpenFoldersWithSelection opener;
+		getRootFolder()->applyFunctorRecursively(opener);
+		getRootFolder()->scrollToShowSelection();
+	}
+
+	gInventory.startBackgroundFetch();
+
+	if (mInventoryPanel->getFilterSubString().empty() && string.empty())
+	{
+		// current filter and new filter empty, do nothing
+		return;
+	}
+
+	// save current folder open state if no filter currently applied
+	if (getRootFolder()->getFilterSubString().empty())
+	{
+		mSavedFolderState->setApply(FALSE);
+		getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
+	}
+
+	// set new filter string
+	mInventoryPanel->setFilterSubString(string);
+}
+
+void LLPanelOutfitsInventory::onWear()
+{
+	LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem();
+	if (!current_item)
+		return;
+
+	LLFolderViewEventListener* listenerp = current_item->getListener();
+	if (getIsCorrectType(listenerp))
+	{
+		listenerp->performAction(NULL, NULL,"replaceoutfit");
+	}
+}
+
+void LLPanelOutfitsInventory::onEdit()
+{
+}
+
+void LLPanelOutfitsInventory::onNew()
+{
+	const std::string& outfit_name = LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_OUTFIT);
+	LLUUID outfit_folder = gAgentWearables.makeNewOutfitLinks(outfit_name);
+	getRootFolder()->setSelectionByID(outfit_folder, TRUE);
+	getRootFolder()->setNeedsAutoRename(TRUE);
+}
+
+void LLPanelOutfitsInventory::updateVerbs()
+{
+	BOOL enabled = FALSE;
+
+	LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem();
+	if (current_item)
+	{
+		LLFolderViewEventListener* listenerp = current_item->getListener();
+		if (getIsCorrectType(listenerp))
+		{
+			enabled = TRUE;
+		}
+	}
+
+	if (mWearBtn)
+	{
+		mWearBtn->setEnabled(enabled);
+	}
+	// mEditBtn->setEnabled(enabled);
+}
+
+void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
+{
+	LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem();
+	if (!current_item)
+		return;
+	
+	/*
+	  LLFolderViewEventListener* listenerp = current_item->getListener();
+	  if (getIsCorrectType(listenerp))
+	  {
+	  S32 bottom = 0;
+	  LLFolderViewItem* folder = current_item->getParentFolder();
+
+	  while ( folder->getParentFolder() != NULL )
+	  {
+	  bottom += folder->getRect().mBottom;
+	  folder = folder->getParentFolder();
+	  }
+
+	  LLRect rect = current_item->getRect();
+	  LLRect btn_rect(
+	  rect.mRight - mActionBtn->getRect().getWidth(),
+	  bottom + rect.mTop,
+	  rect.mRight,
+	  bottom + rect.mBottom);
+
+	  mActionBtn->setRect(btn_rect);
+
+	  if (!mActionBtn->getVisible())
+	  mActionBtn->setVisible(TRUE);
+	  }
+	  else
+	  {
+	  if (mActionBtn->getVisible())
+	  mActionBtn->setVisible(FALSE);
+	  } 
+	*/
+
+	updateVerbs();
+}
+
+void LLPanelOutfitsInventory::onSelectorButtonClicked()
+{
+	/*
+	  LLFolderViewItem* cur_item = getRootFolder()->getCurSelectedItem();
+
+	  LLFolderViewEventListener* listenerp = cur_item->getListener();
+	  if (getIsCorrectType(listenerp))
+	  {
+	  LLSD key;
+	  key["type"] = "look";
+	  key["id"] = listenerp->getUUID();
+
+	  LLSideTray::getInstance()->showPanel("sidepanel_appearance", key);
+	  } 
+	*/
+}
+
+bool LLPanelOutfitsInventory::getIsCorrectType(const LLFolderViewEventListener *listenerp) const
+{
+	if (listenerp->getInventoryType() == LLInventoryType::IT_CATEGORY)
+	{
+		LLViewerInventoryCategory *cat = gInventory.getCategory(listenerp->getUUID());
+		if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+LLFolderView *LLPanelOutfitsInventory::getRootFolder()
+{
+	return mInventoryPanel->getRootFolder();
+}
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
new file mode 100644
index 0000000000..3f837d3635
--- /dev/null
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -0,0 +1,76 @@
+/**
+ * @file llpaneloutfitsinventory.h
+ * @brief Outfits inventory panel
+ * class definition
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPANELOUTFITSINVENTORY_H
+#define LL_LLPANELOUTFITSINVENTORY_H
+
+#include "llpanel.h"
+#include "llinventoryobserver.h"
+
+class LLFolderView;
+class LLFolderViewItem;
+class LLFolderViewEventListener;
+class LLInventoryPanel;
+class LLSaveFolderState;
+class LLButton;
+
+class LLPanelOutfitsInventory : public LLPanel
+{
+public:
+	LLPanelOutfitsInventory();
+	virtual ~LLPanelOutfitsInventory();
+
+	/*virtual*/ BOOL postBuild();
+	
+	void onSearchEdit(const std::string& string);
+	void onWear();
+	void onEdit();
+	void onNew();
+	void updateVerbs();
+
+	void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
+	void onSelectorButtonClicked();
+
+	LLFolderView* getRootFolder();
+
+private:
+	bool getIsCorrectType(const LLFolderViewEventListener *listenerp) const;
+	LLInventoryPanel*			mInventoryPanel;
+	LLSaveFolderState*			mSavedFolderState;
+
+	LLButton*					mActionBtn;
+	LLButton*					mWearBtn;
+	LLButton*					mEditBtn;
+
+};
+
+#endif //LL_LLPANELOUTFITSINVENTORY_H
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
new file mode 100644
index 0000000000..d92e404c2c
--- /dev/null
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -0,0 +1,373 @@
+/**
+ * @file llsidepanelappearance.cpp
+ * @brief Side Bar "Appearance" panel
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llsidepanelappearance.h"
+
+#include "llagent.h"
+#include "llagentwearables.h"
+#include "llfiltereditor.h"
+#include "llfloaterreg.h"
+#include "llfloaterworldmap.h"
+#include "llpaneleditwearable.h"
+#include "llpaneloutfitsinventory.h"
+#include "lltextbox.h"
+#include "lluictrlfactory.h"
+#include "llviewerregion.h"
+#include "llvoavatarself.h"
+#include "llwearable.h"
+
+static LLRegisterPanelClassWrapper<LLSidepanelAppearance> t_appearance("sidepanel_appearance");
+
+class LLCurrentlyWornFetchObserver : public LLInventoryFetchObserver
+{
+public:
+	LLCurrentlyWornFetchObserver(LLSidepanelAppearance *panel) :
+		mPanel(panel)
+	{}
+	~LLCurrentlyWornFetchObserver() {}
+	virtual void done()
+	{
+		mPanel->inventoryFetched();
+		gInventory.removeObserver(this);
+	}
+private:
+	LLSidepanelAppearance *mPanel;
+};
+
+LLSidepanelAppearance::LLSidepanelAppearance() :
+	LLPanel(),
+	mFilterSubString(LLStringUtil::null),
+	mFilterEditor(NULL),
+	mLookInfo(NULL),
+	mCurrLookPanel(NULL)
+{
+	//LLUICtrlFactory::getInstance()->buildPanel(this, "panel_appearance.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder()
+	mFetchWorn = new LLCurrentlyWornFetchObserver(this);
+}
+
+LLSidepanelAppearance::~LLSidepanelAppearance()
+{
+}
+
+// virtual
+BOOL LLSidepanelAppearance::postBuild()
+{
+	mEditAppearanceBtn = getChild<LLButton>("editappearance_btn");
+	mEditAppearanceBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditAppearanceButtonClicked, this));
+
+	mWearBtn = getChild<LLButton>("wear_btn");
+	mWearBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onWearButtonClicked, this));
+
+	mEditBtn = getChild<LLButton>("edit_btn");
+	mEditBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditButtonClicked, this));
+
+	mNewLookBtn = getChild<LLButton>("newlook_btn");
+	mNewLookBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onNewOutfitButtonClicked, this));
+	mNewLookBtn->setEnabled(false);
+
+	mOverflowBtn = getChild<LLButton>("overflow_btn");
+
+	mFilterEditor = getChild<LLFilterEditor>("Filter");
+	if (mFilterEditor)
+	{
+		mFilterEditor->setCommitCallback(boost::bind(&LLSidepanelAppearance::onFilterEdit, this, _2));
+	}
+
+	mPanelOutfitsInventory = dynamic_cast<LLPanelOutfitsInventory *>(getChild<LLPanel>("panel_outfits_inventory"));
+
+	mLookInfo = dynamic_cast<LLPanelLookInfo*>(getChild<LLPanel>("panel_look_info"));
+	if (mLookInfo)
+	{
+		LLButton* back_btn = mLookInfo->getChild<LLButton>("back_btn");
+		if (back_btn)
+		{
+			back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onBackButtonClicked, this));
+		}
+
+		// *TODO: Assign the action to an appropriate event.
+		// mOverflowBtn->setClickedCallback(boost::bind(&LLSidepanelAppearance::toggleMediaPanel, this));
+	}
+
+	mEditWearable = dynamic_cast<LLPanelEditWearable*>(getChild<LLPanel>("panel_edit_wearable"));
+	if (mEditWearable)
+	{
+		LLButton* edit_wearable_back_btn = mEditWearable->getChild<LLButton>("back_btn");
+		if (edit_wearable_back_btn)
+		{
+			edit_wearable_back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onEditWearBackClicked, this));
+		}
+	}
+
+	mCurrentLookName = getChild<LLTextBox>("currentlook_name");
+	
+	mCurrLookPanel = getChild<LLPanel>("panel_currentlook");
+
+	return TRUE;
+}
+
+// virtual
+void LLSidepanelAppearance::onOpen(const LLSD& key)
+{
+	fetchInventory();
+	refreshCurrentOutfitName();
+
+	if(key.size() == 0)
+		return;
+
+	toggleLookInfoPanel(TRUE);
+	updateVerbs();
+	
+	mLookInfoType = key["type"].asString();
+
+	if (mLookInfoType == "look")
+	{
+		LLInventoryCategory *pLook = gInventory.getCategory(key["id"].asUUID());
+		if (pLook)
+			mLookInfo->displayLookInfo(pLook);
+	}
+}
+
+void LLSidepanelAppearance::onFilterEdit(const std::string& search_string)
+{
+	if (mFilterSubString != search_string)
+	{
+		mFilterSubString = search_string;
+
+		// Searches are case-insensitive
+		LLStringUtil::toUpper(mFilterSubString);
+		LLStringUtil::trimHead(mFilterSubString);
+
+		mPanelOutfitsInventory->onSearchEdit(mFilterSubString);
+	}
+}
+
+void LLSidepanelAppearance::onWearButtonClicked()
+{
+	if (mLookInfo->getVisible())
+	{
+	}
+	else
+	{
+		mPanelOutfitsInventory->onWear();
+	}
+}
+
+void LLSidepanelAppearance::onEditAppearanceButtonClicked()
+{
+	if (gAgentWearables.areWearablesLoaded())
+	{
+		gAgent.changeCameraToCustomizeAvatar();
+	}
+}
+
+void LLSidepanelAppearance::onEditButtonClicked()
+{
+	toggleLookInfoPanel(FALSE);
+	toggleWearableEditPanel(TRUE, NULL);
+	/*if (mLookInfo->getVisible())
+	  {
+	  }
+	  else
+	  {
+	  mPanelOutfitsInventory->onEdit();
+	  }*/
+}
+
+void LLSidepanelAppearance::onNewOutfitButtonClicked()
+{
+	if (mLookInfo->getVisible())
+	{
+	}
+	else
+	{
+		mPanelOutfitsInventory->onNew();
+	}
+}
+
+
+void LLSidepanelAppearance::onBackButtonClicked()
+{
+	toggleLookInfoPanel(FALSE);
+}
+
+void LLSidepanelAppearance::onEditWearBackClicked()
+{
+	mEditWearable->saveChanges();
+	toggleWearableEditPanel(FALSE, NULL);
+	toggleLookInfoPanel(TRUE);
+}
+
+void LLSidepanelAppearance::toggleLookInfoPanel(BOOL visible)
+{
+	if (!mLookInfo)
+		return;
+
+	mLookInfo->setVisible(visible);
+	mPanelOutfitsInventory->setVisible(!visible);
+	mFilterEditor->setVisible(!visible);
+	mWearBtn->setVisible(!visible);
+	mEditBtn->setVisible(!visible);
+	mNewLookBtn->setVisible(!visible);
+	mOverflowBtn->setVisible(!visible);
+	mCurrLookPanel->setVisible(!visible);
+}
+
+void LLSidepanelAppearance::toggleWearableEditPanel(BOOL visible, LLWearable *wearable)
+{
+	if (!wearable)
+	{
+		wearable = gAgentWearables.getWearable(WT_SHAPE, 0);
+	}
+	if (!mEditWearable || !wearable)
+	{
+		return;
+	}
+
+	mEditWearable->setVisible(visible);
+	mFilterEditor->setVisible(!visible);
+	mPanelOutfitsInventory->setVisible(!visible);
+}
+
+void LLSidepanelAppearance::updateVerbs()
+{
+	bool is_look_info_visible = mLookInfo->getVisible();
+	mOverflowBtn->setEnabled(false);
+
+	if (is_look_info_visible)
+	{
+	}
+	else
+	{
+		mPanelOutfitsInventory->updateVerbs();
+	}
+}
+
+void LLSidepanelAppearance::refreshCurrentOutfitName(const std::string name)
+{
+	if (name == "")
+	{
+		const LLUUID current_outfit_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+		LLInventoryModel::cat_array_t cat_array;
+		LLInventoryModel::item_array_t item_array;
+		// Can't search on AT_OUTFIT since links to categories return AT_CATEGORY for type since they don't
+		// return preferred type.
+		LLIsType is_category( LLAssetType::AT_CATEGORY ); 
+		gInventory.collectDescendentsIf(current_outfit_cat,
+										cat_array,
+										item_array,
+										false,
+										is_category,
+										false);
+		for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
+			 iter != item_array.end();
+			 iter++)
+		{
+			const LLViewerInventoryItem *item = (*iter);
+			const LLViewerInventoryCategory *cat = item->getLinkedCategory();
+			if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
+			{
+				mCurrentLookName->setText(cat->getName());
+				return;
+			}
+		}
+		mCurrentLookName->setText(std::string(""));
+	}
+	else
+	{
+		mCurrentLookName->setText(name);
+	}
+}
+
+//static
+void LLSidepanelAppearance::editWearable(LLWearable *wearable, void *data)
+{
+	LLSidepanelAppearance *panel = (LLSidepanelAppearance*) data;
+	panel->toggleLookInfoPanel(FALSE);
+	panel->toggleWearableEditPanel(TRUE, wearable);
+}
+
+// Fetch currently worn items and only enable the New Look button after everything's been
+// fetched.  Alternatively, we could stuff this logic into llagentwearables::makeNewOutfitLinks.
+void LLSidepanelAppearance::fetchInventory()
+{
+
+	mNewLookBtn->setEnabled(false);
+	LLInventoryFetchObserver::item_ref_t ids;
+	LLUUID item_id;
+	for(S32 type = (S32)WT_SHAPE; type < (S32)WT_COUNT; ++type)
+	{
+		// MULTI_WEARABLE:
+		item_id = gAgentWearables.getWearableItemID((EWearableType)type,0);
+		if(item_id.notNull())
+		{
+			ids.push_back(item_id);
+		}
+	}
+
+	LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
+	if( avatar )
+	{
+		for (LLVOAvatar::attachment_map_t::const_iterator iter = avatar->mAttachmentPoints.begin(); 
+			 iter != avatar->mAttachmentPoints.end(); ++iter)
+		{
+			LLViewerJointAttachment* attachment = iter->second;
+			if (!attachment) continue;
+			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+				 attachment_iter != attachment->mAttachedObjects.end();
+				 ++attachment_iter)
+			{
+				LLViewerObject* attached_object = (*attachment_iter);
+				if (!attached_object) continue;
+				const LLUUID& item_id = attached_object->getItemID();
+				if (item_id.isNull()) continue;
+				ids.push_back(item_id);
+			}
+		}
+	}
+
+	mFetchWorn->fetchItems(ids);
+	// If no items to be fetched, done will never be triggered.
+	// TODO: Change LLInventoryFetchObserver::fetchItems to trigger done() on this condition.
+	if (mFetchWorn->isEverythingComplete())
+	{
+		mFetchWorn->done();
+	}
+	else
+	{
+		gInventory.addObserver(mFetchWorn);
+	}
+}
+
+void LLSidepanelAppearance::inventoryFetched()
+{
+	mNewLookBtn->setEnabled(true);
+}
diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h
new file mode 100644
index 0000000000..7be6d2d432
--- /dev/null
+++ b/indra/newview/llsidepanelappearance.h
@@ -0,0 +1,102 @@
+/** 
+ * @file llsidepanelappearance.h
+ * @brief Side Bar "Appearance" panel
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSIDEPANELAPPEARANCE_H
+#define LL_LLSIDEPANELAPPEARANCE_H
+
+#include "llpanel.h"
+#include "llinventoryobserver.h"
+
+#include "llinventory.h"
+#include "llpanellookinfo.h"
+
+class LLFilterEditor;
+class LLCurrentlyWornFetchObserver;
+class LLPanelEditWearable;
+class LLWearable;
+class LLPanelOutfitsInventory;
+
+class LLSidepanelAppearance : public LLPanel
+{
+public:
+	LLSidepanelAppearance();
+	virtual ~LLSidepanelAppearance();
+
+	/*virtual*/ BOOL postBuild();
+	/*virtual*/ void onOpen(const LLSD& key);
+
+	void refreshCurrentOutfitName(const std::string name = "");
+
+	static void editWearable(LLWearable *wearable, void *data);
+
+	void fetchInventory();
+	void inventoryFetched();
+private:
+	void onFilterEdit(const std::string& search_string);
+
+	void onEditAppearanceButtonClicked();
+	void onWearButtonClicked();
+	void onEditButtonClicked();
+	void onNewOutfitButtonClicked();
+	void onBackButtonClicked();
+	void onEditWearBackClicked();
+	void toggleLookInfoPanel(BOOL visible);
+	void toggleWearableEditPanel(BOOL visible, LLWearable* wearable);
+
+	void updateVerbs();
+
+	LLFilterEditor*			mFilterEditor;
+	LLPanelOutfitsInventory* mPanelOutfitsInventory;
+	LLPanelLookInfo*		mLookInfo;
+	LLPanelEditWearable*	mEditWearable;
+
+	LLButton*					mEditAppearanceBtn;
+	LLButton*					mWearBtn;
+	LLButton*					mEditBtn;
+	LLButton*					mNewLookBtn;
+	LLButton*					mOverflowBtn;
+	LLPanel*					mCurrLookPanel;
+
+	LLTextBox*					mCurrentLookName;
+
+	// Used to make sure the user's inventory is in memory.
+	LLCurrentlyWornFetchObserver* mFetchWorn;
+
+	// Search string for filtering landmarks and teleport
+	// history locations
+	std::string					mFilterSubString;
+
+	// Information type currently shown in Look Information panel
+	std::string					mLookInfoType;
+
+};
+
+#endif //LL_LLSIDEPANELAPPEARANCE_H
diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml
index b48c962413..7cfcac8a9a 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory.xml
@@ -30,7 +30,7 @@
      name="Fetched">
         Fetched
     </floater.string>
-<panel
+    <panel
      bottom="560"
 	 class="panel_main_inventory"
 	 filename="panel_main_inventory.xml"
diff --git a/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
new file mode 100644
index 0000000000..f511ec0d6f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_outfits_inventory.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel name="Outfits" 
+	  bottom="0" 
+	  height="326" 
+	  left="0" 
+	  width="310"
+	  border="true"
+	  follows="left|top|right|bottom">
+	 <inventory_panel 
+	 	 allow_multi_select="true" 
+		 border="true" 
+		 bottom="0"
+	     follows="left|top|right|bottom" 
+		 height="326" 
+		 left="0" 
+		 mouse_opaque="true"
+	     name="outfits_list"
+		 width="310"
+		 start_folder="My Outfits"/>
+	<button bottom="0"
+		 halign="center"
+		 height="16"
+		 label=">"
+		 enabled="false"
+	     mouse_opaque="false"
+		 name="selector"
+		 width="20"
+		 left="0"
+		 visible="false"
+	     follows="right|bottom"
+		 tool_tip="View outfit properties"/>
+    <panel
+     background_visible="true"
+     bevel_style="none"
+     bottom="0"
+     follows="left|right|bottom"
+     height="30"
+     layout="bottomleft"
+     left="0"
+	 visible="true"
+     name="bottom_panel"
+     width="310">
+        <button
+         follows="bottom|left"
+         tool_tip="Show additional options"
+         height="18"
+         image_disabled="OptionsMenu_Disabled"
+         image_selected="OptionsMenu_Press"
+         image_unselected="OptionsMenu_Off"
+         layout="topleft"
+         left="10"
+         name="options_gear_btn"
+         picture_style="true"
+         top="6"
+         width="18" />
+        <button
+         follows="bottom|left"
+         height="18"
+         image_selected="AddItem_Press"
+         image_unselected="AddItem_Off"
+         image_disabled="AddItem_Disabled"
+         layout="topleft"
+         left_pad="5"
+         name="add_btn"
+         picture_style="true"
+         tool_tip="Add new item"
+         width="18" />
+        <dnd_button
+         follows="bottom|right"
+         height="18"
+         image_selected="TrashItem_Press"
+         image_unselected="TrashItem_Off"
+         layout="topleft"
+         right="-5"
+         name="trash_btn"
+         picture_style="true"
+         tool_tip="Remove selected item"
+         top="6"
+         width="18" />
+    </panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_side_tray.xml b/indra/newview/skins/default/xui/en/panel_side_tray.xml
index a419a02d75..d02354a647 100644
--- a/indra/newview/skins/default/xui/en/panel_side_tray.xml
+++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml
@@ -120,9 +120,9 @@
     background_visible="true"
   >
       <panel
-        class="panel_appearance"
-        name="panel_appearance"
-        filename="panel_appearance.xml"
+        class="sidepanel_appearance"
+        name="sidepanel_appearance"
+        filename="sidepanel_appearance.xml"
         label="Edit Appearance"
         font="SansSerifBold"
       />
diff --git a/indra/newview/skins/default/xui/en/sidepanel_appearance.xml b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
new file mode 100644
index 0000000000..d87211d432
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/sidepanel_appearance.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+	  background_visible="true"
+	  follows="all"
+	  height="400"
+	  label="Appearance"
+	  layout="topleft"
+	  min_height="350"
+	  min_width="240"
+	  name="appearance panel"
+	  width="333">
+     <string
+		 name="looks_tab_title"
+		 value="Looks" />
+     <panel
+		 left="5" width="320" height="55"
+		 background_visible="true"
+		 background_opaque="false"
+		 bg_alpha_color="0.2 0.2 0.2 1.0"
+		 name="panel_currentlook"
+		 follows="left|top|right">
+		<text
+			 top="-5" width="200" left="5" height="10" follows="left|right|top"
+        	 font="SansSerif" text_color="LtGray" word_wrap="true"
+        	 mouse_opaque="false" name="currentlook_title">
+					Current Look
+    	</text>
+  		<text
+			 top="-30" left="8" height="10" follows="left|right|top"
+      		 font="SansSerifBold" text_color="white" word_wrap="true"
+      		 mouse_opaque="false" name="currentlook_name" >
+					MyLook
+  		</text>
+  	    <button
+  	     	 follows="left|right|top"
+  	     	 font="SansSerif"
+  	     	 top="28" right="-105" width="60" height="20"
+  	     	 layout="topleft"
+  		 	 label="Edit"
+  	     	 name="editappearance_btn"/>
+	</panel>
+
+    <filter_editor
+  	     follows="left|top|right"
+  	     font="SansSerif"
+  	     label="Filter"
+  	     layout="topleft"
+  	     left="15" 
+		 width="313"
+		 height="20"
+  	     name="Filter" />
+    <panel
+   	     class="panel_outfits_inventory"
+   	     filename="panel_outfits_inventory.xml"
+ 	     name="panel_outfits_inventory"
+  	     follows="all"
+  	     height="271"
+  	     halign="center"
+  	     layout="topleft"
+  	     left="10"
+  	     top_pad="19"
+  	     width="313" />
+    <button
+  	     follows="bottom|left"
+  	     font="SansSerifSmallBold"
+  	     height="25"
+  	     label="Wear"
+  	     layout="topleft"
+  	     left="10"
+  	     name="wear_btn"
+     	 top_pad="0"
+       	 width="80" />
+    <button
+    	 follows="bottom|left"
+  	     font="SansSerifSmallBold"
+  	     height="25"
+  	     label="New Look"
+  	     layout="topleft"
+  	     left_pad="0"
+  	     name="newlook_btn"
+  	     top_delta="0"
+   	     width="90" />
+
+	<panel
+       	 class="panel_look_info"
+       	 filename="panel_look_info.xml"
+       	 follows="all"
+       	 layout="topleft"
+       	 left="0"
+       	 name="panel_look_info"
+       	 top="-200"
+       	 visible="false" />
+
+	<panel
+	   	 class="panel_edit_wearable"
+	   	 filename="panel_edit_wearable.xml"
+	   	 follows="all"
+	   	 layout="topleft"
+	   	 left="0"
+	   	 name="panel_edit_wearable"
+	   	 top="-200"
+	   	 visible="false"
+	   	 width="333" />
+</panel>
-- 
cgit v1.2.3