PageRenderTime 119ms CodeModel.GetById 32ms app.highlight 79ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/newview/llcofwearables.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 759 lines | 542 code | 146 blank | 71 comment | 110 complexity | fcea02d4ac7c59e3d7757b1c26dcd66b MD5 | raw file
  1/** 
  2 * @file llcofwearables.cpp
  3 * @brief LLCOFWearables displayes wearables from the current outfit split into three lists (attachments, clothing and body parts)
  4 *
  5 * $LicenseInfo:firstyear=2010&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 "llcofwearables.h"
 30
 31#include "llaccordionctrl.h"
 32#include "llaccordionctrltab.h"
 33#include "llagentdata.h"
 34#include "llagentwearables.h"
 35#include "llappearancemgr.h"
 36#include "llfloatersidepanelcontainer.h"
 37#include "llinventory.h"
 38#include "llinventoryfunctions.h"
 39#include "lllistcontextmenu.h"
 40#include "llmenugl.h"
 41#include "llviewermenu.h"
 42#include "llwearableitemslist.h"
 43#include "llpaneloutfitedit.h"
 44#include "lltrans.h"
 45
 46static LLRegisterPanelClassWrapper<LLCOFWearables> t_cof_wearables("cof_wearables");
 47
 48const LLSD REARRANGE = LLSD().with("rearrange", LLSD());
 49
 50static const LLWearableItemNameComparator WEARABLE_NAME_COMPARATOR;
 51
 52//////////////////////////////////////////////////////////////////////////
 53
 54class CofContextMenu : public LLListContextMenu
 55{
 56protected:
 57	CofContextMenu(LLCOFWearables* cof_wearables)
 58	:	mCOFWearables(cof_wearables)
 59	{
 60		llassert(mCOFWearables);
 61	}
 62
 63	void updateCreateWearableLabel(LLMenuGL* menu, const LLUUID& item_id)
 64	{
 65		LLMenuItemGL* menu_item = menu->getChild<LLMenuItemGL>("create_new");
 66		LLWearableType::EType w_type = getWearableType(item_id);
 67
 68		// Hide the "Create new <WEARABLE_TYPE>" if it's irrelevant.
 69		if (w_type == LLWearableType::WT_NONE)
 70		{
 71			menu_item->setVisible(FALSE);
 72			return;
 73		}
 74
 75		// Set proper label for the "Create new <WEARABLE_TYPE>" menu item.
 76		std::string new_label = LLTrans::getString("create_new_" + LLWearableType::getTypeName(w_type));
 77		menu_item->setLabel(new_label);
 78	}
 79
 80	void createNew(const LLUUID& item_id)
 81	{
 82		LLAgentWearables::createWearable(getWearableType(item_id), true);
 83	}
 84
 85	// Get wearable type of the given item.
 86	//
 87	// There is a special case: so-called "dummy items"
 88	// (i.e. the ones that are there just to indicate that you're not wearing
 89	// any wearables of the corresponding type. They are currently grayed out
 90	// and suffixed with "not worn").
 91	// Those items don't have an UUID, but they do have an associated wearable type.
 92	// If the user has invoked context menu for such item,
 93	// we ignore the passed item_id and retrieve wearable type from the item.
 94	LLWearableType::EType getWearableType(const LLUUID& item_id)
 95	{
 96		if (!isDummyItem(item_id))
 97		{
 98			LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id);
 99			if (item && item->isWearableType())
100			{
101				return item->getWearableType();
102			}
103		}
104		else if (mCOFWearables) // dummy item selected
105		{
106			LLPanelDummyClothingListItem* item;
107
108			item = dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem());
109			if (item)
110			{
111				return item->getWearableType();
112			}
113		}
114
115		return LLWearableType::WT_NONE;
116	}
117
118	static bool isDummyItem(const LLUUID& item_id)
119	{
120		return item_id.isNull();
121	}
122
123	LLCOFWearables* mCOFWearables;
124};
125
126//////////////////////////////////////////////////////////////////////////
127
128class CofAttachmentContextMenu : public CofContextMenu
129{
130public:
131	CofAttachmentContextMenu(LLCOFWearables* cof_wearables)
132	:	CofContextMenu(cof_wearables)
133	{
134	}
135
136protected:
137
138	/*virtual*/ LLContextMenu* createMenu()
139	{
140		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
141
142		functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1);
143		registrar.add("Attachment.Detach", boost::bind(handleMultiple, take_off, mUUIDs));
144
145		return createFromFile("menu_cof_attachment.xml");
146	}
147};
148
149//////////////////////////////////////////////////////////////////////////
150
151class CofClothingContextMenu : public CofContextMenu
152{
153public:
154	CofClothingContextMenu(LLCOFWearables* cof_wearables)
155	:	CofContextMenu(cof_wearables)
156	{
157	}
158
159protected:
160	static void replaceWearable(const LLUUID& item_id)
161	{
162		LLPanelOutfitEdit	* panel_outfit_edit =
163						dynamic_cast<LLPanelOutfitEdit*> (LLFloaterSidePanelContainer::getPanel("appearance",
164								"panel_outfit_edit"));
165		if (panel_outfit_edit != NULL)
166		{
167			panel_outfit_edit->onReplaceMenuItemClicked(item_id);
168		}
169	}
170
171	/*virtual*/ LLContextMenu* createMenu()
172	{
173		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
174		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
175		LLUUID selected_id = mUUIDs.back();
176		functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1);
177
178		registrar.add("Clothing.TakeOff", boost::bind(handleMultiple, take_off, mUUIDs));
179		registrar.add("Clothing.Replace", boost::bind(replaceWearable, selected_id));
180		registrar.add("Clothing.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
181		registrar.add("Clothing.Create", boost::bind(&CofClothingContextMenu::createNew, this, selected_id));
182
183		enable_registrar.add("Clothing.OnEnable", boost::bind(&CofClothingContextMenu::onEnable, this, _2));
184
185		LLContextMenu* menu = createFromFile("menu_cof_clothing.xml");
186		llassert(menu);
187		if (menu)
188		{
189			updateCreateWearableLabel(menu, selected_id);
190		}
191		return menu;
192	}
193
194	bool onEnable(const LLSD& data)
195	{
196		std::string param = data.asString();
197		LLUUID selected_id = mUUIDs.back();
198
199		if ("take_off" == param)
200		{
201			return get_is_item_worn(selected_id);
202		}
203		else if ("edit" == param)
204		{
205			return mUUIDs.size() == 1 && gAgentWearables.isWearableModifiable(selected_id);
206		}
207		else if ("replace" == param)
208		{
209			return get_is_item_worn(selected_id) && mUUIDs.size() == 1;
210		}
211
212		return true;
213	}
214};
215
216//////////////////////////////////////////////////////////////////////////
217
218class CofBodyPartContextMenu : public CofContextMenu
219{
220public:
221	CofBodyPartContextMenu(LLCOFWearables* cof_wearables)
222	:	CofContextMenu(cof_wearables)
223	{
224	}
225
226protected:
227	/*virtual*/ LLContextMenu* createMenu()
228	{
229		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
230		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
231		LLUUID selected_id = mUUIDs.back();
232
233		LLPanelOutfitEdit* panel_oe = dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit"));
234		registrar.add("BodyPart.Replace", boost::bind(&LLPanelOutfitEdit::onReplaceMenuItemClicked, panel_oe, selected_id));
235		registrar.add("BodyPart.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
236		registrar.add("BodyPart.Create", boost::bind(&CofBodyPartContextMenu::createNew, this, selected_id));
237
238		enable_registrar.add("BodyPart.OnEnable", boost::bind(&CofBodyPartContextMenu::onEnable, this, _2));
239
240		LLContextMenu* menu = createFromFile("menu_cof_body_part.xml");
241		llassert(menu);
242		if (menu)
243		{
244			updateCreateWearableLabel(menu, selected_id);
245		}
246		return menu;
247	}
248
249	bool onEnable(const LLSD& data)
250	{
251		std::string param = data.asString();
252		LLUUID selected_id = mUUIDs.back();
253
254		if ("edit" == param)
255		{
256			return mUUIDs.size() == 1 && gAgentWearables.isWearableModifiable(selected_id);
257		}
258
259		return true;
260	}
261};
262
263//////////////////////////////////////////////////////////////////////////
264
265LLCOFWearables::LLCOFWearables() : LLPanel(),
266	mAttachments(NULL),
267	mClothing(NULL),
268	mBodyParts(NULL),
269	mLastSelectedList(NULL),
270	mClothingTab(NULL),
271	mAttachmentsTab(NULL),
272	mBodyPartsTab(NULL),
273	mLastSelectedTab(NULL),
274	mAccordionCtrl(NULL),
275	mCOFVersion(-1)
276{
277	mClothingMenu = new CofClothingContextMenu(this);
278	mAttachmentMenu = new CofAttachmentContextMenu(this);
279	mBodyPartMenu = new CofBodyPartContextMenu(this);
280};
281
282LLCOFWearables::~LLCOFWearables()
283{
284	delete mClothingMenu;
285	delete mAttachmentMenu;
286	delete mBodyPartMenu;
287}
288
289// virtual
290BOOL LLCOFWearables::postBuild()
291{
292	mAttachments = getChild<LLFlatListView>("list_attachments");
293	mClothing = getChild<LLFlatListView>("list_clothing");
294	mBodyParts = getChild<LLFlatListView>("list_body_parts");
295
296	mClothing->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mClothingMenu));
297	mAttachments->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mAttachmentMenu));
298	mBodyParts->setRightMouseDownCallback(boost::bind(&LLCOFWearables::onListRightClick, this, _1, _2, _3, mBodyPartMenu));
299
300	//selection across different list/tabs is not supported
301	mAttachments->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mAttachments));
302	mClothing->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mClothing));
303	mBodyParts->setCommitCallback(boost::bind(&LLCOFWearables::onSelectionChange, this, mBodyParts));
304	
305	mAttachments->setCommitOnSelectionChange(true);
306	mClothing->setCommitOnSelectionChange(true);
307	mBodyParts->setCommitOnSelectionChange(true);
308
309	//clothing is sorted according to its position relatively to the body
310	mAttachments->setComparator(&WEARABLE_NAME_COMPARATOR);
311	mBodyParts->setComparator(&WEARABLE_NAME_COMPARATOR);
312
313	mClothingTab = getChild<LLAccordionCtrlTab>("tab_clothing");
314	mClothingTab->setDropDownStateChangedCallback(boost::bind(&LLCOFWearables::onAccordionTabStateChanged, this, _1, _2));
315
316	mAttachmentsTab = getChild<LLAccordionCtrlTab>("tab_attachments");
317	mAttachmentsTab->setDropDownStateChangedCallback(boost::bind(&LLCOFWearables::onAccordionTabStateChanged, this, _1, _2));
318
319	mBodyPartsTab = getChild<LLAccordionCtrlTab>("tab_body_parts");
320	mBodyPartsTab->setDropDownStateChangedCallback(boost::bind(&LLCOFWearables::onAccordionTabStateChanged, this, _1, _2));
321
322	mTab2AssetType[mClothingTab] = LLAssetType::AT_CLOTHING;
323	mTab2AssetType[mAttachmentsTab] = LLAssetType::AT_OBJECT;
324	mTab2AssetType[mBodyPartsTab] = LLAssetType::AT_BODYPART;
325
326	mAccordionCtrl = getChild<LLAccordionCtrl>("cof_wearables_accordion");
327
328	return LLPanel::postBuild();
329}
330
331void LLCOFWearables::setAttachmentsTitle()
332{
333	if (mAttachmentsTab)
334	{
335		U32 free_slots = MAX_AGENT_ATTACHMENTS - mAttachments->size();
336
337		LLStringUtil::format_map_t args_attachments;
338		args_attachments["[COUNT]"] = llformat ("%d", free_slots);
339		std::string attachments_title = LLTrans::getString("Attachments remain", args_attachments);
340		mAttachmentsTab->setTitle(attachments_title);
341	}
342}
343
344void LLCOFWearables::onSelectionChange(LLFlatListView* selected_list)
345{
346	if (!selected_list) return;
347
348	if (selected_list != mLastSelectedList)
349	{
350		if (selected_list != mAttachments) mAttachments->resetSelection(true);
351		if (selected_list != mClothing) mClothing->resetSelection(true);
352		if (selected_list != mBodyParts) mBodyParts->resetSelection(true);
353
354		mLastSelectedList = selected_list;
355	}
356
357	onCommit();
358}
359
360void LLCOFWearables::onAccordionTabStateChanged(LLUICtrl* ctrl, const LLSD& expanded)
361{
362	bool had_selected_items = mClothing->numSelected() || mAttachments->numSelected() || mBodyParts->numSelected();
363	mClothing->resetSelection(true);
364	mAttachments->resetSelection(true);
365	mBodyParts->resetSelection(true);
366
367	bool tab_selection_changed = false;
368	LLAccordionCtrlTab* tab = dynamic_cast<LLAccordionCtrlTab*>(ctrl);
369	if (tab && tab != mLastSelectedTab)
370	{
371		mLastSelectedTab = tab;
372		tab_selection_changed = true;
373	}
374
375	if (had_selected_items || tab_selection_changed)
376	{
377		//sending commit signal to indicate selection changes
378		onCommit();
379	}
380}
381
382void LLCOFWearables::refresh()
383{
384	const LLUUID cof_id = LLAppearanceMgr::instance().getCOF();
385	if (cof_id.isNull())
386	{
387		llwarns << "COF ID cannot be NULL" << llendl;
388		return;
389	}
390
391	LLViewerInventoryCategory* catp = gInventory.getCategory(cof_id);
392	if (!catp)
393	{
394		llwarns << "COF category cannot be NULL" << llendl;
395		return;
396	}
397
398	// BAP - this check has to be removed because an item name change does not
399	// change cat version - ie, checking version is not a complete way
400	// of finding out whether anything has changed in this category.
401	//if (mCOFVersion == catp->getVersion()) return;
402
403	mCOFVersion = catp->getVersion();
404
405	// Save current scrollbar position.
406	typedef std::map<LLFlatListView*, LLRect> scroll_pos_map_t;
407	scroll_pos_map_t saved_scroll_pos;
408
409	saved_scroll_pos[mAttachments] = mAttachments->getVisibleContentRect();
410	saved_scroll_pos[mClothing] = mClothing->getVisibleContentRect();
411	saved_scroll_pos[mBodyParts] = mBodyParts->getVisibleContentRect();
412
413	// Save current selection.
414	typedef std::vector<LLSD> values_vector_t;
415	typedef std::map<LLFlatListView*, values_vector_t> selection_map_t;
416
417	selection_map_t preserve_selection;
418
419	mAttachments->getSelectedValues(preserve_selection[mAttachments]);
420	mClothing->getSelectedValues(preserve_selection[mClothing]);
421	mBodyParts->getSelectedValues(preserve_selection[mBodyParts]);
422
423	clear();
424
425	LLInventoryModel::cat_array_t cats;
426	LLInventoryModel::item_array_t cof_items;
427
428	gInventory.collectDescendents(cof_id, cats, cof_items, LLInventoryModel::EXCLUDE_TRASH);
429
430	populateAttachmentsAndBodypartsLists(cof_items);
431
432
433	LLAppearanceMgr::wearables_by_type_t clothing_by_type(LLWearableType::WT_COUNT);
434	LLAppearanceMgr::getInstance()->divvyWearablesByType(cof_items, clothing_by_type);
435	
436	populateClothingList(clothing_by_type);
437
438	// Restore previous selection
439	for (selection_map_t::iterator
440			 iter = preserve_selection.begin(),
441			 iter_end = preserve_selection.end();
442		 iter != iter_end; ++iter)
443	{
444		LLFlatListView* list = iter->first;
445		if (!list) continue;
446
447		//restoring selection should not fire commit callbacks
448		list->setCommitOnSelectionChange(false);
449
450		const values_vector_t& values = iter->second;
451		for (values_vector_t::const_iterator
452				 value_it = values.begin(),
453				 value_it_end = values.end();
454			 value_it != value_it_end; ++value_it)
455		{
456			// value_it may be null because of dummy items
457			// Dummy items have no ID
458			if(value_it->asUUID().notNull())
459			{
460				list->selectItemByValue(*value_it);
461			}
462		}
463
464		list->setCommitOnSelectionChange(true);
465	}
466
467	// Restore previous scrollbar position.
468	for (scroll_pos_map_t::const_iterator it = saved_scroll_pos.begin(); it != saved_scroll_pos.end(); ++it)
469	{
470		LLFlatListView* list = it->first;
471		LLRect scroll_pos = it->second;
472
473		list->scrollToShowRect(scroll_pos);
474	}
475}
476
477
478void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items)
479{
480	for (U32 i = 0; i < cof_items.size(); ++i)
481	{
482		LLViewerInventoryItem* item = cof_items.get(i);
483		if (!item) continue;
484
485		const LLAssetType::EType item_type = item->getType();
486		if (item_type == LLAssetType::AT_CLOTHING) continue;
487		LLPanelInventoryListItemBase* item_panel = NULL;
488		if (item_type == LLAssetType::AT_OBJECT)
489		{
490			item_panel = buildAttachemntListItem(item);
491			mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
492		}
493		else if (item_type == LLAssetType::AT_BODYPART)
494		{
495			item_panel = buildBodypartListItem(item);
496			if (!item_panel) continue;
497
498			mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
499		}
500	}
501
502	if (mAttachments->size())
503	{
504		mAttachments->sort();
505		mAttachments->notify(REARRANGE); //notifying the parent about the list's size change (cause items were added with rearrange=false)
506		setAttachmentsTitle();
507	}
508	else
509	{
510		mAttachments->setNoItemsCommentText(LLTrans::getString("no_attachments"));
511	}
512
513	if (mBodyParts->size())
514	{
515		mBodyParts->sort();
516		mBodyParts->notify(REARRANGE);
517	}
518}
519
520//create a clothing list item, update verbs and show/hide line separator
521LLPanelClothingListItem* LLCOFWearables::buildClothingListItem(LLViewerInventoryItem* item, bool first, bool last)
522{
523	llassert(item);
524	if (!item) return NULL;
525	LLPanelClothingListItem* item_panel = LLPanelClothingListItem::create(item);
526	if (!item_panel) return NULL;
527
528	//updating verbs
529	//we don't need to use permissions of a link but of an actual/linked item
530	if (item->getLinkedItem()) item = item->getLinkedItem();
531	llassert(item);
532	if (!item) return NULL;
533
534	bool allow_modify = item->getPermissions().allowModifyBy(gAgentID);
535	
536	item_panel->setShowLockButton(!allow_modify);
537	item_panel->setShowEditButton(allow_modify);
538
539	item_panel->setShowMoveUpButton(!first);
540	item_panel->setShowMoveDownButton(!last);
541
542	//setting callbacks
543	//*TODO move that item panel's inner structure disclosing stuff into the panels
544	item_panel->childSetAction("btn_delete", boost::bind(mCOFCallbacks.mDeleteWearable));
545	item_panel->childSetAction("btn_move_up", boost::bind(mCOFCallbacks.mMoveWearableFurther));
546	item_panel->childSetAction("btn_move_down", boost::bind(mCOFCallbacks.mMoveWearableCloser));
547	item_panel->childSetAction("btn_edit", boost::bind(mCOFCallbacks.mEditWearable));
548	
549	//turning on gray separator line for the last item in the items group of the same wearable type
550	item_panel->setSeparatorVisible(last);
551
552	return item_panel;
553}
554
555LLPanelBodyPartsListItem* LLCOFWearables::buildBodypartListItem(LLViewerInventoryItem* item)
556{
557	llassert(item);
558	if (!item) return NULL;
559	LLPanelBodyPartsListItem* item_panel = LLPanelBodyPartsListItem::create(item);
560	if (!item_panel) return NULL;
561
562	//updating verbs
563	//we don't need to use permissions of a link but of an actual/linked item
564	if (item->getLinkedItem()) item = item->getLinkedItem();
565	llassert(item);
566	if (!item) return NULL;
567	bool allow_modify = item->getPermissions().allowModifyBy(gAgentID);
568	item_panel->setShowLockButton(!allow_modify);
569	item_panel->setShowEditButton(allow_modify);
570
571	//setting callbacks
572	//*TODO move that item panel's inner structure disclosing stuff into the panels
573	item_panel->childSetAction("btn_delete", boost::bind(mCOFCallbacks.mDeleteWearable));
574	item_panel->childSetAction("btn_edit", boost::bind(mCOFCallbacks.mEditWearable));
575
576	return item_panel;
577}
578
579LLPanelDeletableWearableListItem* LLCOFWearables::buildAttachemntListItem(LLViewerInventoryItem* item)
580{
581	llassert(item);
582	if (!item) return NULL;
583
584	LLPanelAttachmentListItem* item_panel = LLPanelAttachmentListItem::create(item);
585	if (!item_panel) return NULL;
586
587	//setting callbacks
588	//*TODO move that item panel's inner structure disclosing stuff into the panels
589	item_panel->childSetAction("btn_delete", boost::bind(mCOFCallbacks.mDeleteWearable));
590
591	return item_panel;
592}
593
594void LLCOFWearables::populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
595{
596	llassert(clothing_by_type.size() == LLWearableType::WT_COUNT);
597
598	for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; ++type)
599	{
600		U32 size = clothing_by_type[type].size();
601		if (!size) continue;
602
603		LLAppearanceMgr::sortItemsByActualDescription(clothing_by_type[type]);
604
605		//clothing items are displayed in reverse order, from furthest ones to closest ones (relatively to the body)
606		for (U32 i = size; i != 0; --i)
607		{
608			LLViewerInventoryItem* item = clothing_by_type[type][i-1];
609
610			LLPanelClothingListItem* item_panel = buildClothingListItem(item, i == size, i == 1);
611			if (!item_panel) continue;
612
613			mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
614		}
615	}
616
617	addClothingTypesDummies(clothing_by_type);
618
619	mClothing->notify(REARRANGE);
620}
621
622//adding dummy items for missing wearable types
623void LLCOFWearables::addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
624{
625	llassert(clothing_by_type.size() == LLWearableType::WT_COUNT);
626	
627	for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)
628	{
629		U32 size = clothing_by_type[type].size();
630		if (size) continue;
631
632		LLWearableType::EType w_type = static_cast<LLWearableType::EType>(type);
633		LLPanelInventoryListItemBase* item_panel = LLPanelDummyClothingListItem::create(w_type);
634		if(!item_panel) continue;
635		item_panel->childSetAction("btn_add", boost::bind(mCOFCallbacks.mAddWearable));
636		mClothing->addItem(item_panel, LLUUID::null, ADD_BOTTOM, false);
637	}
638}
639
640LLUUID LLCOFWearables::getSelectedUUID()
641{
642	if (!mLastSelectedList) return LLUUID::null;
643	
644	return mLastSelectedList->getSelectedUUID();
645}
646
647bool LLCOFWearables::getSelectedUUIDs(uuid_vec_t& selected_ids)
648{
649	if (!mLastSelectedList) return false;
650
651	mLastSelectedList->getSelectedUUIDs(selected_ids);
652	return selected_ids.size() != 0;
653}
654
655LLPanel* LLCOFWearables::getSelectedItem()
656{
657	if (!mLastSelectedList) return NULL;
658
659	return mLastSelectedList->getSelectedItem();
660}
661
662void LLCOFWearables::getSelectedItems(std::vector<LLPanel*>& selected_items) const
663{
664	if (mLastSelectedList)
665	{
666		mLastSelectedList->getSelectedItems(selected_items);
667	}
668}
669
670void LLCOFWearables::clear()
671{
672	mAttachments->clear();
673	mClothing->clear();
674	mBodyParts->clear();
675}
676
677LLAssetType::EType LLCOFWearables::getExpandedAccordionAssetType()
678{
679	typedef std::map<std::string, LLAssetType::EType> type_map_t;
680
681	static type_map_t type_map;
682
683	if (mAccordionCtrl != NULL)
684	{
685		const LLAccordionCtrlTab* expanded_tab = mAccordionCtrl->getExpandedTab();
686
687	return get_if_there(mTab2AssetType, expanded_tab, LLAssetType::AT_NONE);
688	}
689
690	return LLAssetType::AT_NONE;
691}
692
693LLAssetType::EType LLCOFWearables::getSelectedAccordionAssetType()
694	{
695	if (mAccordionCtrl != NULL)
696	{
697		const LLAccordionCtrlTab* selected_tab = mAccordionCtrl->getSelectedTab();
698
699	return get_if_there(mTab2AssetType, selected_tab, LLAssetType::AT_NONE);
700}
701
702	return LLAssetType::AT_NONE;
703}
704
705void LLCOFWearables::expandDefaultAccordionTab()
706{
707	if (mAccordionCtrl != NULL)
708	{
709		mAccordionCtrl->expandDefaultTab();
710	}
711}
712
713void LLCOFWearables::onListRightClick(LLUICtrl* ctrl, S32 x, S32 y, LLListContextMenu* menu)
714{
715	if(menu)
716	{
717		uuid_vec_t selected_uuids;
718		if(getSelectedUUIDs(selected_uuids))
719		{
720			bool show_menu = false;
721			for(uuid_vec_t::iterator it = selected_uuids.begin();it!=selected_uuids.end();++it)
722			{
723				if ((*it).notNull())
724				{
725					show_menu = true;
726					break;
727				}
728			}
729
730			if(show_menu)
731			{
732				menu->show(ctrl, selected_uuids, x, y);
733			}
734		}
735	}
736}
737
738void LLCOFWearables::selectClothing(LLWearableType::EType clothing_type)
739{
740	std::vector<LLPanel*> clothing_items;
741
742	mClothing->getItems(clothing_items);
743
744	std::vector<LLPanel*>::iterator it;
745
746	for (it = clothing_items.begin(); it != clothing_items.end(); ++it )
747	{
748		LLPanelClothingListItem* clothing_item = dynamic_cast<LLPanelClothingListItem*>(*it);
749
750		if (clothing_item && clothing_item->getWearableType() == clothing_type)
751		{ // clothing item has specified LLWearableType::EType. Select it and exit.
752
753			mClothing->selectItem(clothing_item);
754			break;
755		}
756	}
757}
758
759//EOF