PageRenderTime 183ms CodeModel.GetById 63ms app.highlight 109ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llpaneloutfitedit.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1415 lines | 1028 code | 246 blank | 141 comment | 176 complexity | 65ed7320619a0e6d353df119b1b8b468 MD5 | raw file
   1/**
   2 * @file llpaneloutfitedit.cpp
   3 * @brief Displays outfit edit information in Side Tray.
   4 *
   5 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llpaneloutfitedit.h"
  30
  31// *TODO: reorder includes to match the coding standard
  32#include "llagent.h"
  33#include "llagentcamera.h"
  34#include "llagentwearables.h"
  35#include "llappearancemgr.h"
  36#include "lloutfitobserver.h"
  37#include "llcofwearables.h"
  38#include "llfilteredwearablelist.h"
  39#include "llfolderview.h"
  40#include "llinventory.h"
  41#include "llinventoryitemslist.h"
  42#include "llviewercontrol.h"
  43#include "llui.h"
  44#include "llfloater.h"
  45#include "llfloaterreg.h"
  46#include "llinventoryfunctions.h"
  47#include "llinventorypanel.h"
  48#include "llviewermenu.h"
  49#include "llviewerwindow.h"
  50#include "llviewerinventory.h"
  51#include "llbutton.h"
  52#include "llcombobox.h"
  53#include "llfiltereditor.h"
  54#include "llfloaterinventory.h"
  55#include "llinventorybridge.h"
  56#include "llinventorymodel.h"
  57#include "llinventorymodelbackgroundfetch.h"
  58#include "llloadingindicator.h"
  59#include "llmenubutton.h"
  60#include "llpaneloutfitsinventory.h"
  61#include "lluiconstants.h"
  62#include "llsaveoutfitcombobtn.h"
  63#include "llscrolllistctrl.h"
  64#include "lltextbox.h"
  65#include "lltoggleablemenu.h"
  66#include "lltrans.h"
  67#include "lluictrlfactory.h"
  68#include "llsdutil.h"
  69#include "llsidepanelappearance.h"
  70#include "lltoggleablemenu.h"
  71#include "llvoavatarself.h"
  72#include "llwearablelist.h"
  73#include "llwearableitemslist.h"
  74#include "llwearabletype.h"
  75#include "llweb.h"
  76
  77static LLRegisterPanelClassWrapper<LLPanelOutfitEdit> t_outfit_edit("panel_outfit_edit");
  78
  79const U64 WEARABLE_MASK = (1LL << LLInventoryType::IT_WEARABLE);
  80const U64 ATTACHMENT_MASK = (1LL << LLInventoryType::IT_ATTACHMENT) | (1LL << LLInventoryType::IT_OBJECT);
  81const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
  82
  83static const std::string REVERT_BTN("revert_btn");
  84
  85
  86///////////////////////////////////////////////////////////////////////////////
  87// LLShopURLDispatcher
  88///////////////////////////////////////////////////////////////////////////////
  89
  90class LLShopURLDispatcher
  91{
  92public:
  93	std::string resolveURL(LLWearableType::EType wearable_type, ESex sex);
  94	std::string resolveURL(LLAssetType::EType asset_type, ESex sex);
  95};
  96
  97std::string LLShopURLDispatcher::resolveURL(LLWearableType::EType wearable_type, ESex sex)
  98{
  99	const std::string prefix = "MarketplaceURL";
 100	const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female";
 101	const std::string type_str = LLWearableType::getTypeName(wearable_type);
 102
 103	std::string setting_name = prefix;
 104
 105	switch (wearable_type)
 106	{
 107	case LLWearableType::WT_ALPHA:
 108	case LLWearableType::WT_NONE:
 109	case LLWearableType::WT_INVALID:	// just in case, this shouldn't happen
 110	case LLWearableType::WT_COUNT:		// just in case, this shouldn't happen
 111		break;
 112
 113	default:
 114		setting_name += '_';
 115		setting_name += type_str;
 116		setting_name += sex_str;
 117		break;
 118	}
 119
 120	return gSavedSettings.getString(setting_name);
 121}
 122
 123std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex sex)
 124{
 125	const std::string prefix = "MarketplaceURL";
 126	const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female";
 127	const std::string type_str = LLAssetType::lookup(asset_type);
 128
 129	std::string setting_name = prefix;
 130
 131	switch (asset_type)
 132	{
 133	case LLAssetType::AT_CLOTHING:
 134	case LLAssetType::AT_OBJECT:
 135	case LLAssetType::AT_BODYPART:
 136		setting_name += '_';
 137		setting_name += type_str;
 138		setting_name += sex_str;
 139		break;
 140
 141	// to suppress warnings
 142	default:
 143		break;
 144	}
 145
 146	return gSavedSettings.getString(setting_name);
 147}
 148
 149///////////////////////////////////////////////////////////////////////////////
 150// LLPanelOutfitEditGearMenu
 151///////////////////////////////////////////////////////////////////////////////
 152
 153class LLPanelOutfitEditGearMenu
 154{
 155public:
 156	static LLToggleableMenu* create()
 157	{
 158		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 159
 160		registrar.add("Wearable.Create", boost::bind(onCreate, _2));
 161
 162		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
 163			"menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
 164		llassert(menu);
 165		if (menu)
 166		{
 167			populateCreateWearableSubmenus(menu);
 168		}
 169
 170		return menu;
 171	}
 172
 173private:
 174	static void onCreate(const LLSD& param)
 175	{
 176		LLWearableType::EType type = LLWearableType::typeNameToType(param.asString());
 177		if (type == LLWearableType::WT_NONE)
 178		{
 179			llwarns << "Invalid wearable type" << llendl;
 180			return;
 181		}
 182
 183		LLAgentWearables::createWearable(type, true);
 184	}
 185
 186	// Populate the menu with items like "New Skin", "New Pants", etc.
 187	static void populateCreateWearableSubmenus(LLMenuGL* menu)
 188	{
 189		LLView* menu_clothes	= gMenuHolder->getChildView("COF.Gear.New_Clothes", FALSE);
 190		LLView* menu_bp			= gMenuHolder->getChildView("COF.Geear.New_Body_Parts", FALSE);
 191
 192		for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i)
 193		{
 194			LLWearableType::EType type = (LLWearableType::EType) i;
 195			const std::string& type_name = LLWearableType::getTypeName(type);
 196
 197			LLMenuItemCallGL::Params p;
 198			p.name = type_name;
 199			p.label = LLTrans::getString(LLWearableType::getTypeDefaultNewName(type));
 200			p.on_click.function_name = "Wearable.Create";
 201			p.on_click.parameter = LLSD(type_name);
 202
 203			LLView* parent = LLWearableType::getAssetType(type) == LLAssetType::AT_CLOTHING ?
 204				menu_clothes : menu_bp;
 205			LLUICtrlFactory::create<LLMenuItemCallGL>(p, parent);
 206		}
 207	}
 208};
 209
 210///////////////////////////////////////////////////////////////////////////////
 211// LLAddWearablesGearMenu
 212///////////////////////////////////////////////////////////////////////////////
 213
 214class LLAddWearablesGearMenu : public LLInitClass<LLAddWearablesGearMenu>
 215{
 216public:
 217	static LLToggleableMenu* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
 218	{
 219		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 220		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
 221
 222		llassert(flat_list);
 223		llassert(inventory_panel);
 224
 225		LLHandle<LLView> flat_list_handle = flat_list->getHandle();
 226		LLHandle<LLPanel> inventory_panel_handle = inventory_panel->getHandle();
 227
 228		registrar.add("AddWearable.Gear.Sort", boost::bind(onSort, flat_list_handle, inventory_panel_handle, _2));
 229		enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2));
 230		enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2));
 231
 232		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
 233			"menu_add_wearable_gear.xml",
 234			LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
 235
 236		return menu;
 237	}
 238
 239private:
 240	static void onSort(LLHandle<LLView> flat_list_handle,
 241					   LLHandle<LLPanel> inventory_panel_handle,
 242					   LLSD::String sort_order_str)
 243	{
 244		if (flat_list_handle.isDead() || inventory_panel_handle.isDead()) return;
 245
 246		LLWearableItemsList* flat_list = dynamic_cast<LLWearableItemsList*>(flat_list_handle.get());
 247		LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
 248
 249		if (!flat_list || !inventory_panel) return;
 250
 251		LLWearableItemsList::ESortOrder	sort_order;
 252
 253		if ("by_most_recent" == sort_order_str)
 254		{
 255			sort_order = LLWearableItemsList::E_SORT_BY_MOST_RECENT;
 256		}
 257		else if ("by_name" == sort_order_str)
 258		{
 259			sort_order = LLWearableItemsList::E_SORT_BY_NAME;
 260		}
 261		else if ("by_type" == sort_order_str)
 262		{
 263			sort_order = LLWearableItemsList::E_SORT_BY_TYPE_NAME;
 264		}
 265		else
 266		{
 267			llwarns << "Unrecognized sort order action" << llendl;
 268			return;
 269		}
 270
 271		if (inventory_panel->getVisible())
 272		{
 273			inventory_panel->setSortOrder(sort_order);
 274		}
 275		else
 276		{
 277			flat_list->setSortOrder(sort_order);
 278		}
 279	}
 280
 281	static bool onCheck(LLHandle<LLView> flat_list_handle,
 282						LLHandle<LLPanel> inventory_panel_handle,
 283						LLSD::String sort_order_str)
 284	{
 285		if (flat_list_handle.isDead() || inventory_panel_handle.isDead()) return false;
 286
 287		LLWearableItemsList* flat_list = dynamic_cast<LLWearableItemsList*>(flat_list_handle.get());
 288		LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
 289
 290		if (!inventory_panel || !flat_list) return false;
 291
 292		// Inventory panel uses its own sort order independent from
 293		// flat list view so this flag is used to distinguish between
 294		// currently visible "tree" or "flat" representation of inventory.
 295		bool inventory_tree_visible = inventory_panel->getVisible();
 296
 297		if (inventory_tree_visible)
 298		{
 299			U32 sort_order = inventory_panel->getSortOrder();
 300
 301			if ("by_most_recent" == sort_order_str)
 302			{
 303				return LLWearableItemsList::E_SORT_BY_MOST_RECENT & sort_order;
 304			}
 305			else if ("by_name" == sort_order_str)
 306			{
 307				// If inventory panel is not sorted by date then it is sorted by name.
 308				return LLWearableItemsList::E_SORT_BY_MOST_RECENT & ~sort_order;
 309			}
 310			llwarns << "Unrecognized inventory panel sort order" << llendl;
 311		}
 312		else
 313		{
 314			LLWearableItemsList::ESortOrder	sort_order = flat_list->getSortOrder();
 315
 316			if ("by_most_recent" == sort_order_str)
 317			{
 318				return LLWearableItemsList::E_SORT_BY_MOST_RECENT == sort_order;
 319			}
 320			else if ("by_name" == sort_order_str)
 321			{
 322				return LLWearableItemsList::E_SORT_BY_NAME == sort_order;
 323			}
 324			else if ("by_type" == sort_order_str)
 325			{
 326				return LLWearableItemsList::E_SORT_BY_TYPE_NAME == sort_order;
 327			}
 328			llwarns << "Unrecognized wearable list sort order" << llendl;
 329		}
 330		return false;
 331	}
 332
 333	static bool onVisible(LLHandle<LLPanel> inventory_panel_handle,
 334						  LLSD::String sort_order_str)
 335	{
 336		if (inventory_panel_handle.isDead()) return false;
 337
 338		LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
 339
 340		// Enable sorting by type only for the flat list of items
 341		// because inventory panel doesn't support this kind of sorting.
 342		return ( "by_type" == sort_order_str )
 343				&&	( !inventory_panel || !inventory_panel->getVisible() );
 344	}
 345};
 346
 347///////////////////////////////////////////////////////////////////////////////
 348// LLCOFDragAndDropObserver
 349///////////////////////////////////////////////////////////////////////////////
 350
 351class LLCOFDragAndDropObserver : public LLInventoryAddItemByAssetObserver
 352{
 353public:
 354	LLCOFDragAndDropObserver(LLInventoryModel* model);
 355
 356	virtual ~LLCOFDragAndDropObserver();
 357
 358	virtual void done();
 359
 360private:
 361	LLInventoryModel* mModel;
 362};
 363
 364inline LLCOFDragAndDropObserver::LLCOFDragAndDropObserver(LLInventoryModel* model):
 365		mModel(model)
 366{
 367	if (model != NULL)
 368	{
 369		model->addObserver(this);
 370	}
 371}
 372
 373inline LLCOFDragAndDropObserver::~LLCOFDragAndDropObserver()
 374{
 375	if (mModel != NULL && mModel->containsObserver(this))
 376	{
 377		mModel->removeObserver(this);
 378	}
 379}
 380
 381void LLCOFDragAndDropObserver::done()
 382{
 383	LLAppearanceMgr::instance().updateAppearanceFromCOF();
 384}
 385
 386///////////////////////////////////////////////////////////////////////////////
 387// LLPanelOutfitEdit
 388///////////////////////////////////////////////////////////////////////////////
 389
 390LLPanelOutfitEdit::LLPanelOutfitEdit()
 391:	LLPanel(), 
 392	mSearchFilter(NULL),
 393	mCOFWearables(NULL),
 394	mInventoryItemsPanel(NULL),
 395	mGearMenu(NULL),
 396	mAddWearablesGearMenu(NULL),
 397	mCOFDragAndDropObserver(NULL),
 398	mInitialized(false),
 399	mAddWearablesPanel(NULL),
 400	mFolderViewFilterCmbBox(NULL),
 401	mListViewFilterCmbBox(NULL),
 402	mWearableListManager(NULL),
 403	mPlusBtn(NULL),
 404	mWearablesGearMenuBtn(NULL),
 405	mGearMenuBtn(NULL)
 406{
 407	mSavedFolderState = new LLSaveFolderState();
 408	mSavedFolderState->setApply(FALSE);
 409	
 410
 411	LLOutfitObserver& observer = LLOutfitObserver::instance();
 412	observer.addBOFReplacedCallback(boost::bind(&LLPanelOutfitEdit::updateCurrentOutfitName, this));
 413	observer.addBOFChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
 414	observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
 415	observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitEdit::onCOFChanged, this));
 416
 417	gAgentWearables.addLoadingStartedCallback(boost::bind(&LLPanelOutfitEdit::onOutfitChanging, this, true));
 418	gAgentWearables.addLoadedCallback(boost::bind(&LLPanelOutfitEdit::onOutfitChanging, this, false));
 419	
 420	mFolderViewItemTypes.reserve(NUM_FOLDER_VIEW_ITEM_TYPES);
 421	for (U32 i = 0; i < NUM_FOLDER_VIEW_ITEM_TYPES; i++)
 422	{
 423		mFolderViewItemTypes.push_back(LLLookItemType());
 424	}
 425
 426}
 427
 428LLPanelOutfitEdit::~LLPanelOutfitEdit()
 429{
 430	delete mWearableListManager;
 431	delete mSavedFolderState;
 432
 433	delete mCOFDragAndDropObserver;
 434
 435	while (!mListViewItemTypes.empty()) {
 436		delete mListViewItemTypes.back();
 437		mListViewItemTypes.pop_back();
 438	}
 439}
 440
 441BOOL LLPanelOutfitEdit::postBuild()
 442{
 443	// gInventory.isInventoryUsable() no longer needs to be tested per Richard's fix for race conditions between inventory and panels
 444	
 445	mFolderViewItemTypes[FVIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK);
 446	mFolderViewItemTypes[FVIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK);
 447	mFolderViewItemTypes[FVIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK);
 448
 449	//order is important, see EListViewItemType for order information
 450	mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.All"), new LLFindNonLinksByMask(ALL_ITEMS_MASK)));
 451	mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Clothing"), new LLIsTypeActual(LLAssetType::AT_CLOTHING)));
 452	mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Bodyparts"), new LLIsTypeActual(LLAssetType::AT_BODYPART)));
 453	mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Objects"), new LLFindNonLinksByMask(ATTACHMENT_MASK)));;
 454	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shape"), new LLFindActualWearablesOfType(LLWearableType::WT_SHAPE)));
 455	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skin"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIN)));
 456	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("hair"), new LLFindActualWearablesOfType(LLWearableType::WT_HAIR)));
 457	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("eyes"), new LLFindActualWearablesOfType(LLWearableType::WT_EYES)));
 458	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SHIRT)));
 459	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("pants"), new LLFindActualWearablesOfType(LLWearableType::WT_PANTS)));
 460	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shoes"), new LLFindActualWearablesOfType(LLWearableType::WT_SHOES)));
 461	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("socks"), new LLFindActualWearablesOfType(LLWearableType::WT_SOCKS)));
 462	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("jacket"), new LLFindActualWearablesOfType(LLWearableType::WT_JACKET)));
 463	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("gloves"), new LLFindActualWearablesOfType(LLWearableType::WT_GLOVES)));
 464	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("undershirt"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERSHIRT)));
 465	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("underpants"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERPANTS)));
 466	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIRT)));
 467	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("alpha"), new LLFindActualWearablesOfType(LLWearableType::WT_ALPHA)));
 468	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("tattoo"), new LLFindActualWearablesOfType(LLWearableType::WT_TATTOO)));
 469	mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("physics"), new LLFindActualWearablesOfType(LLWearableType::WT_PHYSICS)));
 470
 471	mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name"); 
 472	mStatus = getChild<LLTextBox>("status");
 473
 474	mFolderViewBtn = getChild<LLButton>("folder_view_btn");
 475	mListViewBtn = getChild<LLButton>("list_view_btn");
 476
 477	childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
 478	childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesFolderView, this), NULL);
 479	childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
 480	childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesListView, this), NULL);
 481	childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
 482	childSetCommitCallback("shop_btn_1", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
 483	childSetCommitCallback("shop_btn_2", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
 484
 485	setVisibleCallback(boost::bind(&LLPanelOutfitEdit::onVisibilityChange, this, _2));
 486
 487	mWearablesGearMenuBtn = getChild<LLMenuButton>("wearables_gear_menu_btn");
 488	mGearMenuBtn = getChild<LLMenuButton>("gear_menu_btn");
 489
 490	mCOFWearables = findChild<LLCOFWearables>("cof_wearables_list");
 491	mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::filterWearablesBySelectedItem, this));
 492
 493	mCOFWearables->getCOFCallbacks().mAddWearable = boost::bind(&LLPanelOutfitEdit::onAddWearableClicked, this);
 494	mCOFWearables->getCOFCallbacks().mEditWearable = boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this);
 495	mCOFWearables->getCOFCallbacks().mDeleteWearable = boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this);
 496	mCOFWearables->getCOFCallbacks().mMoveWearableCloser = boost::bind(&LLPanelOutfitEdit::moveWearable, this, true);
 497	mCOFWearables->getCOFCallbacks().mMoveWearableFurther = boost::bind(&LLPanelOutfitEdit::moveWearable, this, false);
 498
 499	mAddWearablesPanel = getChild<LLPanel>("add_wearables_panel");
 500
 501	mInventoryItemsPanel = getChild<LLInventoryPanel>("folder_view");
 502	mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK);
 503	mInventoryItemsPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
 504	mInventoryItemsPanel->setSelectCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
 505	mInventoryItemsPanel->getRootFolder()->setReshapeCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
 506
 507	mCOFDragAndDropObserver = new LLCOFDragAndDropObserver(mInventoryItemsPanel->getModel());
 508
 509	mFolderViewFilterCmbBox = getChild<LLComboBox>("folder_view_filter_combobox");
 510	mFolderViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onFolderViewFilterCommitted, this, _1));
 511	mFolderViewFilterCmbBox->removeall();
 512	for (U32 i = 0; i < mFolderViewItemTypes.size(); ++i)
 513	{
 514		mFolderViewFilterCmbBox->add(mFolderViewItemTypes[i].displayName);
 515	}
 516	mFolderViewFilterCmbBox->setCurrentByIndex(FVIT_ALL);
 517	
 518	mListViewFilterCmbBox = getChild<LLComboBox>("list_view_filter_combobox");
 519	mListViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onListViewFilterCommitted, this, _1));
 520	mListViewFilterCmbBox->removeall();
 521	for (U32 i = 0; i < mListViewItemTypes.size(); ++i)
 522	{
 523		mListViewFilterCmbBox->add(mListViewItemTypes[i]->displayName);
 524	}
 525	mListViewFilterCmbBox->setCurrentByIndex(LVIT_ALL);
 526
 527	mSearchFilter = getChild<LLFilterEditor>("look_item_filter");
 528	mSearchFilter->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onSearchEdit, this, _2));
 529
 530	childSetAction("show_add_wearables_btn", boost::bind(&LLPanelOutfitEdit::onAddMoreButtonClicked, this));
 531
 532	mPlusBtn = getChild<LLButton>("plus_btn");
 533	mPlusBtn->setClickedCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
 534	
 535	mEditWearableBtn = getChild<LLButton>("edit_wearable_btn");
 536	mEditWearableBtn->setEnabled(FALSE);
 537	mEditWearableBtn->setVisible(FALSE);
 538	mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this));
 539
 540	childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
 541
 542	/*
 543	 * By default AT_CLOTHING are sorted by (in in MY OUTFITS):
 544	 *  - by type (types order determined in LLWearableType::EType)
 545	 *  - each LLWearableType::EType by outer layer on top
 546	 *
 547	 * In Add More panel AT_CLOTHING should be sorted in a such way:
 548	 *  - by type (types order determined in LLWearableType::EType)
 549	 *  - each LLWearableType::EType by name (EXT-8205)
 550	*/
 551	mWearableListViewItemsComparator = new LLWearableItemTypeNameComparator();
 552	mWearableListViewItemsComparator->setOrder(LLAssetType::AT_CLOTHING, LLWearableItemTypeNameComparator::ORDER_RANK_1, false, true);
 553
 554	mWearablesListViewPanel = getChild<LLPanel>("filtered_wearables_panel");
 555	mWearableItemsList = getChild<LLWearableItemsList>("list_view");
 556	mWearableItemsList->setCommitOnSelectionChange(true);
 557	mWearableItemsList->setCommitCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
 558	mWearableItemsList->setDoubleClickCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
 559
 560	mWearableItemsList->setComparator(mWearableListViewItemsComparator);
 561
 562	// Creating "Add Wearables" panel gear menu after initialization of mWearableItemsList and mInventoryItemsPanel.
 563	mAddWearablesGearMenu = LLAddWearablesGearMenu::create(mWearableItemsList, mInventoryItemsPanel);
 564	mWearablesGearMenuBtn->setMenu(mAddWearablesGearMenu);
 565
 566	mGearMenu = LLPanelOutfitEditGearMenu::create();
 567	mGearMenuBtn->setMenu(mGearMenu);
 568
 569	mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this));
 570	return TRUE;
 571}
 572
 573// virtual
 574void LLPanelOutfitEdit::onOpen(const LLSD& key)
 575{
 576	if (!mInitialized)
 577	{
 578		// *TODO: this method is called even panel is not visible to user because its parent layout panel is hidden.
 579		// So, we can defer initializing a bit.
 580		mWearableListManager = new LLFilteredWearableListManager(mWearableItemsList, mListViewItemTypes[LVIT_ALL]->collector);
 581		mWearableListManager->populateList();
 582		displayCurrentOutfit();
 583		mInitialized = true;
 584	}
 585}
 586
 587void LLPanelOutfitEdit::moveWearable(bool closer_to_body)
 588{
 589	LLUUID item_id = mCOFWearables->getSelectedUUID();
 590	if (item_id.isNull()) return;
 591	
 592	LLViewerInventoryItem* wearable_to_move = gInventory.getItem(item_id);
 593	LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body);
 594}
 595
 596void LLPanelOutfitEdit::toggleAddWearablesPanel()
 597{
 598	BOOL current_visibility = mAddWearablesPanel->getVisible();
 599	showAddWearablesPanel(!current_visibility);
 600}
 601
 602void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables)
 603{
 604	mAddWearablesPanel->setVisible(show_add_wearables);
 605	
 606	getChild<LLUICtrl>("show_add_wearables_btn")->setValue(show_add_wearables);
 607
 608	updateFiltersVisibility();
 609	getChildView("filter_button")->setVisible( show_add_wearables);
 610
 611	//search filter should be disabled
 612	if (!show_add_wearables)
 613	{
 614		getChild<LLUICtrl>("filter_button")->setValue(false);
 615
 616		mFolderViewFilterCmbBox->setVisible(false);
 617		mListViewFilterCmbBox->setVisible(false);
 618
 619		showWearablesFilter();
 620
 621		/*
 622		 * By default AT_CLOTHING are sorted by (in in MY OUTFITS):
 623		 *  - by type (types order determined in LLWearableType::EType)
 624		 *  - each LLWearableType::EType by outer layer on top
 625		 *
 626		 * In Add More panel AT_CLOTHING should be sorted in a such way:
 627		 *  - by type (types order determined in LLWearableType::EType)
 628		 *  - each LLWearableType::EType by name (EXT-8205)
 629		*/
 630		mWearableItemsList->setSortOrder(LLWearableItemsList::E_SORT_BY_TYPE_NAME);
 631
 632		// Reset mWearableItemsList position to top. See EXT-8180.
 633		mWearableItemsList->goToTop();
 634	}
 635
 636	//switching button bars
 637	getChildView("no_add_wearables_button_bar")->setVisible( !show_add_wearables);
 638	getChildView("add_wearables_button_bar")->setVisible( show_add_wearables);
 639}
 640
 641void LLPanelOutfitEdit::showWearablesFilter()
 642{
 643	bool filter_visible = getChild<LLUICtrl>("filter_button")->getValue();
 644
 645	getChildView("filter_panel")->setVisible( filter_visible);
 646
 647	if(!filter_visible)
 648	{
 649		mSearchFilter->clear();
 650		onSearchEdit(LLStringUtil::null);
 651	}
 652	else
 653	{
 654		mSearchFilter->setFocus(TRUE);
 655	}
 656}
 657
 658void LLPanelOutfitEdit::showWearablesListView()
 659{
 660	if(switchPanels(mInventoryItemsPanel, mWearablesListViewPanel))
 661	{
 662		updateWearablesPanelVerbButtons();
 663		updateFiltersVisibility();
 664	}
 665	mListViewBtn->setToggleState(TRUE);
 666}
 667
 668void LLPanelOutfitEdit::showWearablesFolderView()
 669{
 670	if(switchPanels(mWearablesListViewPanel, mInventoryItemsPanel))
 671	{
 672		updateWearablesPanelVerbButtons();
 673		updateFiltersVisibility();
 674	}
 675	mFolderViewBtn->setToggleState(TRUE);
 676}
 677
 678void LLPanelOutfitEdit::updateFiltersVisibility()
 679{
 680	mListViewFilterCmbBox->setVisible(mWearablesListViewPanel->getVisible());
 681	mFolderViewFilterCmbBox->setVisible(mInventoryItemsPanel->getVisible());
 682}
 683
 684void LLPanelOutfitEdit::onFolderViewFilterCommitted(LLUICtrl* ctrl)
 685{
 686	S32 curr_filter_type = mFolderViewFilterCmbBox->getCurrentIndex();
 687	if (curr_filter_type < 0) return;
 688
 689	mInventoryItemsPanel->setFilterTypes(mFolderViewItemTypes[curr_filter_type].inventoryMask);
 690
 691	mSavedFolderState->setApply(TRUE);
 692	mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
 693	
 694	LLOpenFoldersWithSelection opener;
 695	mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);
 696	mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
 697	
 698	LLInventoryModelBackgroundFetch::instance().start();
 699}
 700
 701void LLPanelOutfitEdit::onListViewFilterCommitted(LLUICtrl* ctrl)
 702{
 703	S32 curr_filter_type = mListViewFilterCmbBox->getCurrentIndex();
 704	if (curr_filter_type < 0) return;
 705
 706	mWearableListManager->setFilterCollector(mListViewItemTypes[curr_filter_type]->collector);
 707}
 708
 709void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
 710{
 711	if (mSearchString != string)
 712	{
 713		mSearchString = string;
 714		
 715		// Searches are case-insensitive
 716		LLStringUtil::toUpper(mSearchString);
 717		LLStringUtil::trimHead(mSearchString);
 718	}
 719	
 720	if (mSearchString == "")
 721	{
 722		mInventoryItemsPanel->setFilterSubString(LLStringUtil::null);
 723		mWearableItemsList->setFilterSubString(LLStringUtil::null);
 724		// re-open folders that were initially open
 725		mSavedFolderState->setApply(TRUE);
 726		mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
 727		LLOpenFoldersWithSelection opener;
 728		mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);
 729		mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
 730	}
 731	
 732	LLInventoryModelBackgroundFetch::instance().start();
 733	
 734	if (mInventoryItemsPanel->getFilterSubString().empty() && mSearchString.empty())
 735	{
 736		// current filter and new filter empty, do nothing
 737		return;
 738	}
 739	
 740	// save current folder open state if no filter currently applied
 741	if (mInventoryItemsPanel->getRootFolder()->getFilterSubString().empty())
 742	{
 743		mSavedFolderState->setApply(FALSE);
 744		mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
 745	}
 746	
 747	// set new filter string
 748	mInventoryItemsPanel->setFilterSubString(mSearchString);
 749	mWearableItemsList->setFilterSubString(mSearchString);
 750
 751}
 752
 753void LLPanelOutfitEdit::onPlusBtnClicked(void)
 754{
 755	uuid_vec_t selected_items;
 756	getSelectedItemsUUID(selected_items);
 757
 758	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
 759	
 760	for(uuid_vec_t::iterator iter = selected_items.begin(); iter != selected_items.end(); iter++)
 761	{
 762		LLUUID selected_id = *iter;
 763		if (!selected_id.isNull())
 764		{
 765			//replacing instead of adding the item
 766			LLAppearanceMgr::getInstance()->wearItemOnAvatar(selected_id, false, true, link_waiter);
 767		}
 768	}
 769}
 770
 771void LLPanelOutfitEdit::onVisibilityChange(const LLSD &in_visible_chain)
 772{
 773	showAddWearablesPanel(false);
 774	mWearableItemsList->resetSelection();
 775	mInventoryItemsPanel->clearSelection();
 776
 777	if (in_visible_chain.asBoolean())
 778	{
 779		update();
 780	}
 781}
 782
 783void LLPanelOutfitEdit::onAddWearableClicked(void)
 784{
 785	LLPanelDummyClothingListItem* item = dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem());
 786
 787	if(item)
 788	{
 789		showFilteredWearablesListView(item->getWearableType());
 790	}
 791}
 792
 793void LLPanelOutfitEdit::onReplaceMenuItemClicked(LLUUID selected_item_id)
 794{
 795	LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
 796
 797	if (item)
 798	{
 799		showFilteredWearablesListView(item->getWearableType());
 800	}
 801}
 802
 803void LLPanelOutfitEdit::onShopButtonClicked()
 804{
 805	static LLShopURLDispatcher url_resolver;
 806
 807	// will contain the resultant URL
 808	std::string url;
 809
 810	if (isAgentAvatarValid())
 811	{
 812		// try to get wearable type from 'Add More' panel first (EXT-7639)
 813		selection_info_t selection_info = getAddMorePanelSelectionType();
 814
 815		LLWearableType::EType type = selection_info.first;
 816
 817		if (selection_info.second > 1)
 818		{
 819			// the second argument is not important in this case: generic market place will be opened
 820			url = url_resolver.resolveURL(LLWearableType::WT_NONE, SEX_FEMALE);
 821		}
 822		else
 823		{
 824		if (type == LLWearableType::WT_NONE)
 825		{
 826			type = getCOFWearablesSelectionType();
 827		}
 828
 829		ESex sex = gAgentAvatarp->getSex();
 830
 831		// WT_INVALID comes for attachments
 832		if (type != LLWearableType::WT_INVALID && type != LLWearableType::WT_NONE)
 833		{
 834			url = url_resolver.resolveURL(type, sex);
 835		}
 836
 837		if (url.empty())
 838		{
 839				url = url_resolver.resolveURL(
 840						mCOFWearables->getExpandedAccordionAssetType(), sex);
 841			}
 842		}
 843	}
 844	else
 845	{
 846		llwarns << "Agent avatar is invalid" << llendl;
 847
 848		// the second argument is not important in this case: generic market place will be opened
 849		url = url_resolver.resolveURL(LLWearableType::WT_NONE, SEX_FEMALE);
 850	}
 851
 852	LLWeb::loadURLExternal(url);
 853}
 854
 855LLWearableType::EType LLPanelOutfitEdit::getCOFWearablesSelectionType() const
 856{
 857	std::vector<LLPanel*> selected_items;
 858	LLWearableType::EType type = LLWearableType::WT_NONE;
 859
 860	mCOFWearables->getSelectedItems(selected_items);
 861
 862	if (selected_items.size() == 1)
 863	{
 864		LLPanel* item = selected_items.front();
 865
 866		// LLPanelDummyClothingListItem is lower then LLPanelInventoryListItemBase in hierarchy tree
 867		if (LLPanelDummyClothingListItem* dummy_item = dynamic_cast<LLPanelDummyClothingListItem*>(item))
 868		{
 869			type = dummy_item->getWearableType();
 870		}
 871		else if (LLPanelInventoryListItemBase* real_item = dynamic_cast<LLPanelInventoryListItemBase*>(item))
 872		{
 873			type = real_item->getWearableType();
 874		}
 875	}
 876
 877	return type;
 878}
 879
 880LLPanelOutfitEdit::selection_info_t LLPanelOutfitEdit::getAddMorePanelSelectionType() const
 881{
 882	selection_info_t result = std::make_pair(LLWearableType::WT_NONE, 0);
 883
 884	if (mAddWearablesPanel != NULL && mAddWearablesPanel->getVisible())
 885	{
 886		if (mInventoryItemsPanel != NULL && mInventoryItemsPanel->getVisible())
 887		{
 888			std::set<LLUUID> selected_uuids = mInventoryItemsPanel->getRootFolder()->getSelectionList();
 889
 890			result.second = selected_uuids.size();
 891
 892			if (result.second == 1)
 893			{
 894				result.first = getWearableTypeByItemUUID(*(selected_uuids.begin()));
 895			}
 896		}
 897		else if (mWearableItemsList != NULL && mWearableItemsList->getVisible())
 898		{
 899			std::vector<LLUUID> selected_uuids;
 900			mWearableItemsList->getSelectedUUIDs(selected_uuids);
 901
 902			result.second = selected_uuids.size();
 903
 904			if (result.second == 1)
 905			{
 906				result.first = getWearableTypeByItemUUID(selected_uuids.front());
 907			}
 908		}
 909	}
 910
 911	return result;
 912}
 913
 914LLWearableType::EType LLPanelOutfitEdit::getWearableTypeByItemUUID(const LLUUID& item_uuid) const
 915{
 916	LLViewerInventoryItem* item = gInventory.getLinkedItem(item_uuid);
 917	return (item != NULL) ? item->getWearableType() : LLWearableType::WT_NONE;
 918}
 919
 920void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
 921{
 922	LLUUID id_to_remove = mCOFWearables->getSelectedUUID();
 923	LLWearableType::EType type = getWearableTypeByItemUUID(id_to_remove);
 924	
 925	LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
 926
 927	if (!mCOFWearables->getSelectedItem())
 928	{
 929		mCOFWearables->selectClothing(type);
 930	}
 931}
 932
 933
 934void LLPanelOutfitEdit::onEditWearableClicked(void)
 935{
 936	LLUUID selected_item_id = mCOFWearables->getSelectedUUID();
 937	if (selected_item_id.notNull())
 938	{
 939		gAgentWearables.editWearable(selected_item_id);
 940	}
 941}
 942
 943void LLPanelOutfitEdit::updatePlusButton()
 944{
 945	uuid_vec_t selected_items;
 946	getSelectedItemsUUID(selected_items);
 947	if (selected_items.empty())
 948	{
 949		mPlusBtn->setEnabled(false);
 950		return;
 951	}
 952
 953	// If any of the selected items are not wearable (due to already being worn OR being of the wrong type), disable the add button.
 954	uuid_vec_t::iterator unwearable_item = std::find_if(selected_items.begin(), selected_items.end(), !boost::bind(&get_can_item_be_worn, _1));
 955	bool can_add = ( unwearable_item == selected_items.end() );
 956
 957	mPlusBtn->setEnabled(can_add);
 958
 959	LLViewerInventoryItem* first_item(gInventory.getItem(selected_items.front()));
 960
 961	if (can_add && 
 962		first_item &&
 963		selected_items.size() == 1 && 
 964		first_item->getType() == LLAssetType::AT_BODYPART)
 965	{
 966		mPlusBtn->setToolTip(getString("replace_body_part"));
 967	}
 968	else
 969	{
 970		mPlusBtn->setToolTip(LLStringUtil::null);
 971	}
 972
 973	/* Removing add to look inline button (not part of mvp for viewer 2)
 974	LLRect btn_rect(current_item->getLocalRect().mRight - 50,
 975					current_item->getLocalRect().mTop,
 976					current_item->getLocalRect().mRight - 30,
 977					current_item->getLocalRect().mBottom);
 978	
 979	mAddToLookBtn->setRect(btn_rect);
 980	mAddToLookBtn->setEnabled(TRUE);
 981	if (!mAddToLookBtn->getVisible())
 982	{
 983		mAddToLookBtn->setVisible(TRUE);
 984	}
 985	
 986	current_item->addChild(mAddToLookBtn); */
 987}
 988
 989
 990void LLPanelOutfitEdit::applyFolderViewFilter(EFolderViewItemType type)
 991{
 992	mFolderViewFilterCmbBox->setCurrentByIndex(type);
 993	mFolderViewFilterCmbBox->onCommit();
 994}
 995
 996void LLPanelOutfitEdit::applyListViewFilter(EListViewItemType type)
 997{
 998	mListViewFilterCmbBox->setCurrentByIndex(type);
 999	mListViewFilterCmbBox->onCommit();
1000}
1001
1002void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
1003{
1004	if (!mAddWearablesPanel->getVisible()) return;
1005	
1006	uuid_vec_t ids;
1007	mCOFWearables->getSelectedUUIDs(ids);
1008
1009	bool nothing_selected = ids.empty();
1010	bool one_selected = ids.size() == 1;
1011	bool more_than_one_selected = ids.size() > 1;
1012	bool is_dummy_item = (ids.size() && dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem()));
1013
1014	// selected, expanded accordion tabs and selection in flat list view determine filtering when no item is selected in COF
1015	// selection in flat list view participates in determining filtering because of EXT-7963
1016	// So the priority of criterions in is:
1017	//                   1. Selected accordion tab            |  IF (any accordion selected)
1018	//                                                        |     filter_type = selected_accordion_type
1019	//                   2. Selected item in flat list view   |  ELSEIF (any item in flat list view selected)
1020	//                                                        |     filter_type = selected_item_type
1021	//                   3. Expanded accordion tab            |  ELSEIF (any accordion expanded)
1022	//                                                        |      filter_type = expanded accordion_type
1023	if (nothing_selected)
1024	{
1025		if (mInventoryItemsPanel->getVisible())
1026		{
1027			return;
1028		}
1029		showWearablesListView();
1030
1031		//selected accordion tab is more priority than expanded tab
1032		//and selected item in flat list view of 'Add more' panel when
1033		//determining filtering
1034		LLAssetType::EType type = mCOFWearables->getSelectedAccordionAssetType();
1035		if (type == LLAssetType::AT_NONE)
1036		{ //no accordion selected
1037
1038			// when no accordion selected then selected item from flat list view
1039			// has more priority than expanded when determining filtering
1040			LLUUID selected_item_id = mWearableItemsList->getSelectedUUID();
1041			LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
1042			if(item)
1043		{
1044				showFilteredWearablesListView(item->getWearableType());
1045				return;
1046			}
1047
1048			// when no accordion selected and no selected items in flat list view
1049			// determine filtering according to expanded accordion
1050			type = mCOFWearables->getExpandedAccordionAssetType();
1051		}
1052
1053		switch (type)
1054		{
1055		case LLAssetType::AT_OBJECT:
1056			applyListViewFilter(LVIT_ATTACHMENT);
1057			break;
1058		case LLAssetType::AT_BODYPART:
1059			applyListViewFilter(LVIT_BODYPART);
1060			break;
1061		case LLAssetType::AT_CLOTHING:
1062		default:
1063			applyListViewFilter(LVIT_CLOTHING);
1064			break;
1065		}
1066
1067		return;
1068	}
1069
1070	//resetting selection if more than one item is selected
1071	if (more_than_one_selected)
1072	{
1073		if (mInventoryItemsPanel->getVisible())
1074		{
1075			applyFolderViewFilter(FVIT_ALL);
1076			return;
1077		}
1078
1079		showWearablesListView();
1080		applyListViewFilter(LVIT_ALL);
1081		return;
1082	}
1083
1084
1085	//filter wearables by a type represented by a dummy item
1086	if (one_selected && is_dummy_item)
1087	{
1088		if (mInventoryItemsPanel->getVisible())
1089		{
1090			applyFolderViewFilter(FVIT_WEARABLE);
1091			return;
1092		}
1093
1094		onAddWearableClicked();
1095		return;
1096	}
1097
1098	LLViewerInventoryItem* item = gInventory.getItem(ids[0]);
1099	if (!item && ids[0].notNull())
1100	{
1101		if (mInventoryItemsPanel->getVisible())
1102		{
1103			applyFolderViewFilter(FVIT_ALL);
1104			return;
1105		}
1106		//Inventory misses an item with non-zero id
1107		showWearablesListView();
1108		applyListViewFilter(LVIT_ALL);
1109		return;
1110	}
1111
1112	if (item && one_selected && !is_dummy_item)
1113	{
1114		if (item->isWearableType())
1115		{
1116			if (mInventoryItemsPanel->getVisible())
1117			{
1118				applyFolderViewFilter(FVIT_WEARABLE);
1119				return;
1120			}
1121			//single clothing or bodypart item is selected
1122			showFilteredWearablesListView(item->getWearableType());
1123			return;
1124		}
1125		else
1126		{
1127			if (mInventoryItemsPanel->getVisible())
1128			{
1129				applyFolderViewFilter(FVIT_ATTACHMENT);
1130				return;
1131			}
1132			//attachment is selected
1133			showWearablesListView();
1134			applyListViewFilter(LVIT_ATTACHMENT);
1135			return;
1136		}
1137	}
1138
1139}
1140
1141
1142
1143void LLPanelOutfitEdit::update()
1144{
1145	mCOFWearables->refresh();
1146
1147	updateVerbs();
1148}
1149
1150BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
1151										  EDragAndDropType cargo_type,
1152										  void* cargo_data,
1153										  EAcceptance* accept,
1154										  std::string& tooltip_msg)
1155{
1156	if (cargo_data == NULL)
1157	{
1158		llwarns << "cargo_data is NULL" << llendl;
1159		return TRUE;
1160	}
1161
1162	switch (cargo_type)
1163	{
1164	case DAD_BODYPART:
1165	case DAD_CLOTHING:
1166	case DAD_OBJECT:
1167	case DAD_LINK:
1168		*accept = ACCEPT_YES_MULTI;
1169		break;
1170	default:
1171		*accept = ACCEPT_NO;
1172	}
1173
1174	if (drop)
1175	{
1176		LLInventoryItem* item = static_cast<LLInventoryItem*>(cargo_data);
1177
1178		if (LLAssetType::lookupIsAssetIDKnowable(item->getType()))
1179		{
1180			mCOFDragAndDropObserver->watchAsset(item->getAssetUUID());
1181
1182			/*
1183			 * Adding request to wear item. If the item is a link, then getLinkedUUID() will
1184			 * return the ID of the linked item. Otherwise it will return the item's ID. The
1185			 * second argument is used to delay the appearance update until all dragged items
1186			 * are added to optimize user experience.
1187			 */
1188			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false);
1189		}
1190		else
1191		{
1192			// if asset id is not available for the item we must wear it immediately (attachments only)
1193			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true);
1194		}
1195	}
1196
1197	return TRUE;
1198}
1199
1200void LLPanelOutfitEdit::displayCurrentOutfit()
1201{
1202	if (!getVisible())
1203	{
1204		setVisible(TRUE);
1205	}
1206
1207	updateCurrentOutfitName();
1208
1209	update();
1210}
1211
1212void LLPanelOutfitEdit::updateCurrentOutfitName()
1213{
1214	std::string current_outfit_name;
1215	if (LLAppearanceMgr::getInstance()->getBaseOutfitName(current_outfit_name))
1216	{
1217		mCurrentOutfitName->setText(current_outfit_name);
1218	}
1219	else
1220	{
1221		mCurrentOutfitName->setText(getString("No Outfit"));
1222	}
1223}
1224
1225//private
1226void LLPanelOutfitEdit::updateVerbs()
1227{
1228	bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
1229	bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked();
1230	bool has_baseoutfit = LLAppearanceMgr::getInstance()->getBaseOutfitUUID().notNull();
1231
1232	mSaveComboBtn->setSaveBtnEnabled(!outfit_locked && outfit_is_dirty);
1233	getChildView(REVERT_BTN)->setEnabled(outfit_is_dirty && has_baseoutfit);
1234
1235	mSaveComboBtn->setMenuItemEnabled("save_outfit", !outfit_locked && outfit_is_dirty);
1236
1237	mStatus->setText(outfit_is_dirty ? getString("unsaved_changes") : getString("now_editing"));
1238
1239	updateCurrentOutfitName();
1240
1241	//updating state of "Wear Item" button previously known as "Plus" button
1242	updatePlusButton();
1243}
1244
1245bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch_to_panel)
1246{
1247	if(switch_from_panel && switch_to_panel && !switch_to_panel->getVisible())
1248	{
1249		switch_from_panel->setVisible(FALSE);
1250		switch_to_panel->setVisible(TRUE);
1251		return true;
1252	}
1253	return false;
1254}
1255
1256void LLPanelOutfitEdit::resetAccordionState()
1257{
1258	if (mCOFWearables != NULL)
1259	{
1260		mCOFWearables->expandDefaultAccordionTab();
1261	}
1262	else
1263	{
1264		llwarns << "mCOFWearables is NULL" << llendl;
1265	}
1266}
1267
1268void LLPanelOutfitEdit::onAddMoreButtonClicked()
1269{
1270	toggleAddWearablesPanel();
1271	filterWearablesBySelectedItem();
1272}
1273
1274void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type)
1275{
1276	showAddWearablesPanel(true);
1277	showWearablesListView();
1278
1279	//e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE
1280	applyListViewFilter((EListViewItemType) (LVIT_SHAPE + type));
1281}
1282
1283static void update_status_widget_rect(LLView * widget, S32 right_border)
1284{
1285	LLRect rect = widget->getRect();
1286	rect.mRight = right_border;
1287
1288	widget->setShape(rect);
1289}
1290
1291void LLPanelOutfitEdit::onOutfitChanging(bool started)
1292{
1293	static LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("edit_outfit_loading_indicator");
1294	static LLView* status_panel = getChild<LLView>("outfit_name_and_status");
1295	static S32 indicator_delta = status_panel->getRect().getWidth() - indicator->getRect().mLeft;
1296
1297	S32 delta = started ? indicator_delta : 0;
1298	S32 right_border = status_panel->getRect().getWidth() - delta;
1299
1300	update_status_widget_rect(mCurrentOutfitName, right_border);
1301	update_status_widget_rect(mStatus, right_border);
1302
1303	indicator->setVisible(started);
1304}
1305
1306void LLPanelOutfitEdit::getCurrentItemUUID(LLUUID& selected_id)
1307{
1308	if (mInventoryItemsPanel->getVisible())
1309	{
1310		LLFolderViewItem* curr_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
1311		if (!curr_item) return;
1312
1313		LLFolderViewEventListener* listenerp  = curr_item->getListener();
1314		if (!listenerp) return;
1315
1316		selected_id = listenerp->getUUID();
1317	}
1318	else if (mWearablesListViewPanel->getVisible())
1319	{
1320		selected_id = mWearableItemsList->getSelectedUUID();
1321	}
1322}
1323
1324
1325void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list)
1326{
1327	void (uuid_vec_t::* tmp)(LLUUID const &) = &uuid_vec_t::push_back;
1328	if (mInventoryItemsPanel->getVisible())
1329	{
1330		std::set<LLUUID> item_set = mInventoryItemsPanel->getRootFolder()->getSelectionList();
1331
1332		std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, _1));
1333	}
1334	else if (mWearablesListViewPanel->getVisible())
1335	{
1336		std::vector<LLSD> item_set;
1337		mWearableItemsList->getSelectedValues(item_set);
1338
1339		std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, boost::bind(&LLSD::asUUID, _1 )));
1340	}
1341
1342//	return selected_id;
1343}
1344
1345void LLPanelOutfitEdit::onCOFChanged()
1346{
1347	//the panel is only updated when is visible to a user
1348
1349	// BAP - this check has to be removed because otherwise item name
1350	// changes made when the panel is not visible will not be
1351	// propagated to the panel.
1352	// if (!isInVisibleChain()) return;
1353
1354	update();
1355}
1356
1357void LLPanelOutfitEdit::updateWearablesPanelVerbButtons()
1358{
1359	if(mWearablesListViewPanel->getVisible())
1360	{
1361		mFolderViewBtn->setToggleState(FALSE);
1362		mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign());
1363		mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign());
1364	}
1365	else if(mInventoryItemsPanel->getVisible())
1366	{
1367		mListViewBtn->setToggleState(FALSE);
1368		mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign());
1369		mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign());
1370	}
1371}
1372
1373void LLPanelOutfitEdit::saveListSelection()
1374{
1375	if(mWearablesListViewPanel->getVisible())
1376	{
1377		std::set<LLUUID> selected_ids = mInventoryItemsPanel->getRootFolder()->getSelectionList();
1378
1379		if(!selected_ids.size()) return;
1380
1381		for (std::set<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id)
1382		{
1383			mWearableItemsList->selectItemByUUID(*item_id, true);
1384		}
1385		mWearableItemsList->scrollToShowFirstSelectedItem();
1386	}
1387	else if(mInventoryItemsPanel->getVisible())
1388	{
1389		std::vector<LLUUID> selected_ids;
1390		mWearableItemsList->getSelectedUUIDs(selected_ids);
1391
1392		if(!selected_ids.size()) return;
1393
1394		mInventoryItemsPanel->clearSelection();
1395		LLFolderView* root = mInventoryItemsPanel->getRootFolder();
1396
1397		if(!root) return;
1398
1399		for(std::vector<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id)
1400		{
1401			LLFolderViewItem* item = root->getItemByID(*item_id);
1402			if (!item) continue;
1403
1404			LLFolderViewFolder* parent = item->getParentFolder();
1405			if(parent)
1406			{
1407				parent->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
1408			}
1409			mInventoryItemsPanel->getRootFolder()->changeSelection(item, TRUE);
1410		}
1411		mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
1412	}
1413}
1414
1415// EOF