PageRenderTime 96ms CodeModel.GetById 10ms app.highlight 78ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llinventoryfunctions.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1090 lines | 864 code | 146 blank | 80 comment | 198 complexity | 68ddf5bc43f3beb3fda5bc436f51f25b MD5 | raw file
   1/** 
   2 * @file llinventoryfunctions.cpp
   3 * @brief Implementation of the inventory view and associated stuff.
   4 *
   5 * $LicenseInfo:firstyear=2001&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 <utility> // for std::pair<>
  30
  31#include "llinventoryfunctions.h"
  32
  33// library includes
  34#include "llagent.h"
  35#include "llagentwearables.h"
  36#include "llcallingcard.h"
  37#include "llfloaterreg.h"
  38#include "llinventorydefines.h"
  39#include "llsdserialize.h"
  40#include "llfiltereditor.h"
  41#include "llspinctrl.h"
  42#include "llui.h"
  43#include "message.h"
  44
  45// newview includes
  46#include "llappearancemgr.h"
  47#include "llappviewer.h"
  48//#include "llfirstuse.h"
  49#include "llfloaterinventory.h"
  50#include "llfloatersidepanelcontainer.h"
  51#include "llfocusmgr.h"
  52#include "llfolderview.h"
  53#include "llgesturemgr.h"
  54#include "lliconctrl.h"
  55#include "llimview.h"
  56#include "llinventorybridge.h"
  57#include "llinventoryclipboard.h"
  58#include "llinventorymodel.h"
  59#include "llinventorypanel.h"
  60#include "lllineeditor.h"
  61#include "llmarketplacenotifications.h"
  62#include "llmenugl.h"
  63#include "llnotificationsutil.h"
  64#include "llpanelmaininventory.h"
  65#include "llpreviewanim.h"
  66#include "llpreviewgesture.h"
  67#include "llpreviewnotecard.h"
  68#include "llpreviewscript.h"
  69#include "llpreviewsound.h"
  70#include "llpreviewtexture.h"
  71#include "llresmgr.h"
  72#include "llscrollbar.h"
  73#include "llscrollcontainer.h"
  74#include "llselectmgr.h"
  75#include "llsidepanelinventory.h"
  76#include "lltabcontainer.h"
  77#include "lltooldraganddrop.h"
  78#include "lluictrlfactory.h"
  79#include "llviewermessage.h"
  80#include "llviewerobjectlist.h"
  81#include "llviewerregion.h"
  82#include "llviewerwindow.h"
  83#include "llvoavatarself.h"
  84#include "llwearablelist.h"
  85
  86#include <boost/foreach.hpp>
  87
  88BOOL LLInventoryState::sWearNewClothing = FALSE;
  89LLUUID LLInventoryState::sWearNewClothingTransactionID;
  90
  91// Generates a string containing the path to the item specified by
  92// item_id.
  93void append_path(const LLUUID& id, std::string& path)
  94{
  95	std::string temp;
  96	const LLInventoryObject* obj = gInventory.getObject(id);
  97	LLUUID parent_id;
  98	if(obj) parent_id = obj->getParentUUID();
  99	std::string forward_slash("/");
 100	while(obj)
 101	{
 102		obj = gInventory.getCategory(parent_id);
 103		if(obj)
 104		{
 105			temp.assign(forward_slash + obj->getName() + temp);
 106			parent_id = obj->getParentUUID();
 107		}
 108	}
 109	path.append(temp);
 110}
 111
 112void change_item_parent(LLInventoryModel* model,
 113						LLViewerInventoryItem* item,
 114						const LLUUID& new_parent_id,
 115						BOOL restamp)
 116{
 117	if (item->getParentUUID() != new_parent_id)
 118	{
 119		LLInventoryModel::update_list_t update;
 120		LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
 121		update.push_back(old_folder);
 122		LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
 123		update.push_back(new_folder);
 124		gInventory.accountForUpdate(update);
 125
 126		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
 127		new_item->setParent(new_parent_id);
 128		new_item->updateParentOnServer(restamp);
 129		model->updateItem(new_item);
 130		model->notifyObservers();
 131	}
 132}
 133
 134void change_category_parent(LLInventoryModel* model,
 135	LLViewerInventoryCategory* cat,
 136	const LLUUID& new_parent_id,
 137	BOOL restamp)
 138{
 139	if (!model || !cat)
 140	{
 141		return;
 142	}
 143
 144	// Can't move a folder into a child of itself.
 145	if (model->isObjectDescendentOf(new_parent_id, cat->getUUID()))
 146	{
 147		return;
 148	}
 149
 150	LLInventoryModel::update_list_t update;
 151	LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
 152	update.push_back(old_folder);
 153	LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
 154	update.push_back(new_folder);
 155	model->accountForUpdate(update);
 156
 157	LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
 158	new_cat->setParent(new_parent_id);
 159	new_cat->updateParentOnServer(restamp);
 160	model->updateCategory(new_cat);
 161	model->notifyObservers();
 162}
 163
 164void remove_category(LLInventoryModel* model, const LLUUID& cat_id)
 165{
 166	if (!model || !get_is_category_removable(model, cat_id))
 167	{
 168		return;
 169	}
 170
 171	// Look for any gestures and deactivate them
 172	LLInventoryModel::cat_array_t	descendent_categories;
 173	LLInventoryModel::item_array_t	descendent_items;
 174	gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE);
 175
 176	for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin();
 177		 iter != descendent_items.end();
 178		 ++iter)
 179	{
 180		const LLViewerInventoryItem* item = (*iter);
 181		const LLUUID& item_id = item->getUUID();
 182		if (item->getType() == LLAssetType::AT_GESTURE
 183			&& LLGestureMgr::instance().isGestureActive(item_id))
 184		{
 185			LLGestureMgr::instance().deactivateGesture(item_id);
 186		}
 187	}
 188
 189	LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
 190	if (cat)
 191	{
 192		const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
 193		change_category_parent(model, cat, trash_id, TRUE);
 194	}
 195}
 196
 197void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name)
 198{
 199	LLViewerInventoryCategory* cat;
 200
 201	if (!model ||
 202		!get_is_category_renameable(model, cat_id) ||
 203		(cat = model->getCategory(cat_id)) == NULL ||
 204		cat->getName() == new_name)
 205	{
 206		return;
 207	}
 208
 209	LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
 210	new_cat->rename(new_name);
 211	new_cat->updateServer(FALSE);
 212	model->updateCategory(new_cat);
 213
 214	model->notifyObservers();
 215}
 216
 217class LLInventoryCollectAllItems : public LLInventoryCollectFunctor
 218{
 219public:
 220	virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 221	{
 222		return true;
 223	}
 224};
 225
 226BOOL get_is_parent_to_worn_item(const LLUUID& id)
 227{
 228	const LLViewerInventoryCategory* cat = gInventory.getCategory(id);
 229	if (!cat)
 230	{
 231		return FALSE;
 232	}
 233
 234	LLInventoryModel::cat_array_t cats;
 235	LLInventoryModel::item_array_t items;
 236	LLInventoryCollectAllItems collect_all;
 237	gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all);
 238
 239	for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it)
 240	{
 241		const LLViewerInventoryItem * const item = *it;
 242
 243		llassert(item->getIsLinkType());
 244
 245		LLUUID linked_id = item->getLinkedUUID();
 246		const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id);
 247
 248		if (linked_item)
 249		{
 250			LLUUID parent_id = linked_item->getParentUUID();
 251
 252			while (!parent_id.isNull())
 253			{
 254				LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id);
 255
 256				if (cat == parent_cat)
 257				{
 258					return TRUE;
 259				}
 260
 261				parent_id = parent_cat->getParentUUID();
 262			}
 263		}
 264	}
 265
 266	return FALSE;
 267}
 268
 269BOOL get_is_item_worn(const LLUUID& id)
 270{
 271	const LLViewerInventoryItem* item = gInventory.getItem(id);
 272	if (!item)
 273		return FALSE;
 274
 275	// Consider the item as worn if it has links in COF.
 276	if (LLAppearanceMgr::instance().isLinkInCOF(id))
 277	{
 278		return TRUE;
 279	}
 280
 281	switch(item->getType())
 282	{
 283		case LLAssetType::AT_OBJECT:
 284		{
 285			if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID()))
 286				return TRUE;
 287			break;
 288		}
 289		case LLAssetType::AT_BODYPART:
 290		case LLAssetType::AT_CLOTHING:
 291			if(gAgentWearables.isWearingItem(item->getLinkedUUID()))
 292				return TRUE;
 293			break;
 294		case LLAssetType::AT_GESTURE:
 295			if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID()))
 296				return TRUE;
 297			break;
 298		default:
 299			break;
 300	}
 301	return FALSE;
 302}
 303
 304BOOL get_can_item_be_worn(const LLUUID& id)
 305{
 306	const LLViewerInventoryItem* item = gInventory.getItem(id);
 307	if (!item)
 308		return FALSE;
 309
 310	if (LLAppearanceMgr::isLinkInCOF(item->getLinkedUUID()))
 311	{
 312		// an item having links in COF (i.e. a worn item)
 313		return FALSE;
 314	}
 315
 316	if (gInventory.isObjectDescendentOf(id, LLAppearanceMgr::instance().getCOF()))
 317	{
 318		// a non-link object in COF (should not normally happen)
 319		return FALSE;
 320	}
 321	
 322	const LLUUID trash_id = gInventory.findCategoryUUIDForType(
 323			LLFolderType::FT_TRASH);
 324
 325	// item can't be worn if base obj in trash, see EXT-7015
 326	if (gInventory.isObjectDescendentOf(item->getLinkedUUID(),
 327			trash_id))
 328	{
 329		return false;
 330	}
 331
 332	switch(item->getType())
 333	{
 334		case LLAssetType::AT_OBJECT:
 335		{
 336			if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID()))
 337			{
 338				// Already being worn
 339				return FALSE;
 340			}
 341			else
 342			{
 343				// Not being worn yet.
 344				return TRUE;
 345			}
 346			break;
 347		}
 348		case LLAssetType::AT_BODYPART:
 349		case LLAssetType::AT_CLOTHING:
 350			if(gAgentWearables.isWearingItem(item->getLinkedUUID()))
 351			{
 352				// Already being worn
 353				return FALSE;
 354			}
 355			else
 356			{
 357				// Not being worn yet.
 358				return TRUE;
 359			}
 360			break;
 361		default:
 362			break;
 363	}
 364	return FALSE;
 365}
 366
 367BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id)
 368{
 369	if (!model)
 370	{
 371		return FALSE;
 372	}
 373
 374	// Can't delete an item that's in the library.
 375	if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
 376	{
 377		return FALSE;
 378	}
 379
 380	// Disable delete from COF folder; have users explicitly choose "detach/take off",
 381	// unless the item is not worn but in the COF (i.e. is bugged).
 382	if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id))
 383	{
 384		if (get_is_item_worn(id))
 385		{
 386			return FALSE;
 387		}
 388	}
 389
 390	const LLInventoryObject *obj = model->getItem(id);
 391	if (obj && obj->getIsLinkType())
 392	{
 393		return TRUE;
 394	}
 395	if (get_is_item_worn(id))
 396	{
 397		return FALSE;
 398	}
 399	return TRUE;
 400}
 401
 402BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id)
 403{
 404	// NOTE: This function doesn't check the folder's children.
 405	// See LLFolderBridge::isItemRemovable for a function that does
 406	// consider the children.
 407
 408	if (!model)
 409	{
 410		return FALSE;
 411	}
 412
 413	if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
 414	{
 415		return FALSE;
 416	}
 417
 418	if (!isAgentAvatarValid()) return FALSE;
 419
 420	const LLInventoryCategory* category = model->getCategory(id);
 421	if (!category)
 422	{
 423		return FALSE;
 424	}
 425
 426	const LLFolderType::EType folder_type = category->getPreferredType();
 427	
 428	if (LLFolderType::lookupIsProtectedType(folder_type))
 429	{
 430		return FALSE;
 431	}
 432
 433	// Can't delete the outfit that is currently being worn.
 434	if (folder_type == LLFolderType::FT_OUTFIT)
 435	{
 436		const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
 437		if (base_outfit_link && (category == base_outfit_link->getLinkedCategory()))
 438		{
 439			return FALSE;
 440		}
 441	}
 442
 443	return TRUE;
 444}
 445
 446BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
 447{
 448	if (!model)
 449	{
 450		return FALSE;
 451	}
 452
 453	LLViewerInventoryCategory* cat = model->getCategory(id);
 454
 455	if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) &&
 456		cat->getOwnerID() == gAgent.getID())
 457	{
 458		return TRUE;
 459	}
 460	return FALSE;
 461}
 462
 463void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id)
 464{
 465	LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", item_uuid).with("object", object_id));
 466}
 467
 468void show_item_profile(const LLUUID& item_uuid)
 469{
 470	LLUUID linked_uuid = gInventory.getLinkedItemID(item_uuid);
 471	LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", linked_uuid));
 472}
 473
 474void show_item_original(const LLUUID& item_uuid)
 475{
 476	LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
 477	if (!floater_inventory)
 478	{
 479		llwarns << "Could not find My Inventory floater" << llendl;
 480		return;
 481	}
 482
 483	//sidetray inventory panel
 484	LLSidepanelInventory *sidepanel_inventory =	LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
 485
 486	bool reset_inventory_filter = !floater_inventory->isInVisibleChain();
 487
 488	LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel();
 489	if (!active_panel) 
 490	{
 491		//this may happen when there is no floatera and other panel is active in inventory tab
 492
 493		if	(sidepanel_inventory)
 494		{
 495			sidepanel_inventory->showInventoryPanel();
 496		}
 497	}
 498	
 499	active_panel = LLInventoryPanel::getActiveInventoryPanel();
 500	if (!active_panel) 
 501	{
 502		return;
 503	}
 504	active_panel->setSelection(gInventory.getLinkedItemID(item_uuid), TAKE_FOCUS_NO);
 505	
 506	if(reset_inventory_filter)
 507	{
 508		//inventory floater
 509		bool floater_inventory_visible = false;
 510
 511		LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
 512		for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
 513		{
 514			LLFloaterInventory* floater_inventory = dynamic_cast<LLFloaterInventory*>(*iter);
 515			if (floater_inventory)
 516			{
 517				LLPanelMainInventory* main_inventory = floater_inventory->getMainInventoryPanel();
 518
 519				main_inventory->onFilterEdit("");
 520
 521				if(floater_inventory->getVisible())
 522				{
 523					floater_inventory_visible = true;
 524				}
 525			}
 526		}
 527		if(sidepanel_inventory && !floater_inventory_visible)
 528		{
 529			LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
 530
 531			main_inventory->onFilterEdit("");
 532		}
 533	}
 534}
 535
 536
 537void open_outbox()
 538{
 539	LLFloaterReg::showInstance("outbox");
 540}
 541
 542LLUUID create_folder_in_outbox_for_item(LLInventoryItem* item, const LLUUID& destFolderId, S32 operation_id)
 543{
 544	llassert(item);
 545	llassert(destFolderId.notNull());
 546
 547	LLUUID created_folder_id = gInventory.createNewCategory(destFolderId, LLFolderType::FT_NONE, item->getName());
 548	gInventory.notifyObservers();
 549
 550	LLNotificationsUtil::add("OutboxFolderCreated");
 551
 552	return created_folder_id;
 553}
 554
 555void move_to_outbox_cb_action(const LLSD& payload)
 556{
 557	LLViewerInventoryItem * viitem = gInventory.getItem(payload["item_id"].asUUID());
 558	LLUUID dest_folder_id = payload["dest_folder_id"].asUUID();
 559
 560	if (viitem)
 561	{	
 562		// when moving item directly into outbox create folder with that name
 563		if (dest_folder_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
 564		{
 565			S32 operation_id = payload["operation_id"].asInteger();
 566			dest_folder_id = create_folder_in_outbox_for_item(viitem, dest_folder_id, operation_id);
 567		}
 568
 569		LLUUID parent = viitem->getParentUUID();
 570
 571		change_item_parent(
 572			&gInventory,
 573			viitem,
 574			dest_folder_id,
 575			false);
 576
 577		LLUUID top_level_folder = payload["top_level_folder"].asUUID();
 578
 579		if (top_level_folder != LLUUID::null)
 580		{
 581			LLViewerInventoryCategory* category;
 582
 583			while (parent.notNull())
 584			{
 585				LLInventoryModel::cat_array_t* cat_array;
 586				LLInventoryModel::item_array_t* item_array;
 587				gInventory.getDirectDescendentsOf(parent,cat_array,item_array);
 588
 589				LLUUID next_parent;
 590
 591				category = gInventory.getCategory(parent);
 592
 593				if (!category) break;
 594
 595				next_parent = category->getParentUUID();
 596
 597				if (cat_array->empty() && item_array->empty())
 598				{
 599					remove_category(&gInventory, parent);
 600				}
 601
 602				if (parent == top_level_folder)
 603				{
 604					break;
 605				}
 606
 607				parent = next_parent;
 608			}
 609		}
 610
 611		open_outbox();
 612	}
 613}
 614
 615void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id)
 616{
 617	// Collapse links directly to items/folders
 618	LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
 619	LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory();
 620	if (linked_category != NULL)
 621	{
 622		copy_folder_to_outbox(linked_category, dest_folder, top_level_folder, operation_id);
 623	}
 624	else
 625	{
 626		LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem();
 627		if (linked_item != NULL)
 628		{
 629			inv_item = (LLInventoryItem *) linked_item;
 630		}
 631		
 632		// Check for copy permissions
 633		if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
 634		{
 635			// when moving item directly into outbox create folder with that name
 636			if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
 637			{
 638				dest_folder = create_folder_in_outbox_for_item(inv_item, dest_folder, operation_id);
 639			}
 640			
 641			copy_inventory_item(gAgent.getID(),
 642								inv_item->getPermissions().getOwner(),
 643								inv_item->getUUID(),
 644								dest_folder,
 645								inv_item->getName(),
 646								LLPointer<LLInventoryCallback>(NULL));
 647
 648			open_outbox();
 649		}
 650		else
 651		{
 652			LLSD payload;
 653			payload["item_id"] = inv_item->getUUID();
 654			payload["dest_folder_id"] = dest_folder;
 655			payload["top_level_folder"] = top_level_folder;
 656			payload["operation_id"] = operation_id;
 657			
 658			LLMarketplaceInventoryNotifications::addNoCopyNotification(payload, move_to_outbox_cb_action);
 659		}
 660	}
 661}
 662
 663void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id)
 664{
 665	// when moving item directly into outbox create folder with that name
 666	if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
 667	{
 668		dest_folder = create_folder_in_outbox_for_item(inv_item, dest_folder, operation_id);
 669	}
 670	
 671	LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
 672
 673	change_item_parent(&gInventory,
 674					   viewer_inv_item,
 675					   dest_folder,
 676					   false);
 677}
 678
 679void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id)
 680{
 681	LLUUID new_folder_id = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_cat->getName());
 682	gInventory.notifyObservers();
 683
 684	LLInventoryModel::cat_array_t* cat_array;
 685	LLInventoryModel::item_array_t* item_array;
 686	gInventory.getDirectDescendentsOf(inv_cat->getUUID(),cat_array,item_array);
 687
 688	// copy the vector because otherwise the iterator won't be happy if we delete from it
 689	LLInventoryModel::item_array_t item_array_copy = *item_array;
 690
 691	for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
 692	{
 693		LLInventoryItem* item = *iter;
 694		copy_item_to_outbox(item, new_folder_id, top_level_folder, operation_id);
 695	}
 696
 697	LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
 698
 699	for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
 700	{
 701		LLViewerInventoryCategory* category = *iter;
 702		copy_folder_to_outbox(category, new_folder_id, top_level_folder, operation_id);
 703	}
 704
 705	open_outbox();
 706}
 707
 708///----------------------------------------------------------------------------
 709/// LLInventoryCollectFunctor implementations
 710///----------------------------------------------------------------------------
 711
 712// static
 713bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryItem* item)
 714{
 715	if (!item)
 716		return false;
 717
 718	switch(item->getType())
 719	{
 720		case LLAssetType::AT_OBJECT:
 721		case LLAssetType::AT_BODYPART:
 722		case LLAssetType::AT_CLOTHING:
 723			if (!get_is_item_worn(item->getUUID()))
 724				return true;
 725			break;
 726		default:
 727			return true;
 728			break;
 729	}
 730	return false;
 731}
 732
 733bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 734{
 735	if(mType == LLAssetType::AT_CATEGORY)
 736	{
 737		if(cat) return TRUE;
 738	}
 739	if(item)
 740	{
 741		if(item->getType() == mType) return TRUE;
 742	}
 743	return FALSE;
 744}
 745
 746bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 747{
 748	if(mType == LLAssetType::AT_CATEGORY)
 749	{
 750		if(cat) return FALSE;
 751	}
 752	if(item)
 753	{
 754		if(item->getType() == mType) return FALSE;
 755		else return TRUE;
 756	}
 757	return TRUE;
 758}
 759
 760bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 761{
 762	if(mType == LLAssetType::AT_CATEGORY)
 763	{
 764		if(cat) return TRUE;
 765	}
 766	if(item)
 767	{
 768		if(item->getActualType() == mType) return TRUE;
 769	}
 770	return FALSE;
 771}
 772
 773bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 774{
 775	if(mType == LLAssetType::AT_CATEGORY)
 776	{
 777		if(cat) 
 778		{
 779			return TRUE;
 780		}
 781	}
 782	if(item)
 783	{
 784		if(item->getType() == mType)
 785		{
 786			LLPermissions perm = item->getPermissions();
 787			if ((perm.getMaskBase() & mPerm) == mPerm)
 788			{
 789				return TRUE;
 790			}
 791		}
 792	}
 793	return FALSE;
 794}
 795
 796bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
 797								  LLInventoryItem* item)
 798{
 799	if(item)
 800	{
 801		if((LLAssetType::AT_CALLINGCARD == item->getType())
 802		   && (!item->getCreatorUUID().isNull())
 803		   && (item->getCreatorUUID() != gAgent.getID()))
 804		{
 805			return true;
 806		}
 807	}
 808	return false;
 809}
 810
 811
 812bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat,
 813										LLInventoryItem* item)
 814{
 815	if(item)
 816	{
 817		if((LLAssetType::AT_CALLINGCARD == item->getType())
 818 		   && (item->getCreatorUUID().notNull())
 819 		   && (item->getCreatorUUID() != gAgent.getID()))
 820		{
 821			mSeen.insert(item->getCreatorUUID());
 822			return true;
 823		}
 824	}
 825	return false;
 826}
 827
 828
 829bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat,
 830											LLInventoryItem* item)
 831{
 832	if(item)
 833	{
 834		if((LLAssetType::AT_CALLINGCARD == item->getType())
 835		   && (item->getCreatorUUID() == mBuddyID))
 836		{
 837			return TRUE;
 838		}
 839	}
 840	return FALSE;
 841}
 842
 843
 844bool LLNameCategoryCollector::operator()(
 845	LLInventoryCategory* cat, LLInventoryItem* item)
 846{
 847	if(cat)
 848	{
 849		if (!LLStringUtil::compareInsensitive(mName, cat->getName()))
 850		{
 851			return true;
 852		}
 853	}
 854	return false;
 855}
 856
 857bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat,
 858									 LLInventoryItem* item)
 859{
 860	// Valid COF items are:
 861	// - links to wearables (body parts or clothing)
 862	// - links to attachments
 863	// - links to gestures
 864	// - links to ensemble folders
 865	LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem();
 866	if (linked_item)
 867	{
 868		LLAssetType::EType type = linked_item->getType();
 869		return (type == LLAssetType::AT_CLOTHING ||
 870				type == LLAssetType::AT_BODYPART ||
 871				type == LLAssetType::AT_GESTURE ||
 872				type == LLAssetType::AT_OBJECT);
 873	}
 874	else
 875	{
 876		LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory();
 877		// BAP remove AT_NONE support after ensembles are fully working?
 878		return (linked_category &&
 879				((linked_category->getPreferredType() == LLFolderType::FT_NONE) ||
 880				 (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType()))));
 881	}
 882}
 883
 884bool LLFindWearables::operator()(LLInventoryCategory* cat,
 885								 LLInventoryItem* item)
 886{
 887	if(item)
 888	{
 889		if((item->getType() == LLAssetType::AT_CLOTHING)
 890		   || (item->getType() == LLAssetType::AT_BODYPART))
 891		{
 892			return TRUE;
 893		}
 894	}
 895	return FALSE;
 896}
 897
 898LLFindWearablesEx::LLFindWearablesEx(bool is_worn, bool include_body_parts)
 899:	mIsWorn(is_worn)
 900,	mIncludeBodyParts(include_body_parts)
 901{}
 902
 903bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 904{
 905	LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item);
 906	if (!vitem) return false;
 907
 908	// Skip non-wearables.
 909	if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT)
 910	{
 911		return false;
 912	}
 913
 914	// Skip body parts if requested.
 915	if (!mIncludeBodyParts && vitem->getType() == LLAssetType::AT_BODYPART)
 916	{
 917		return false;
 918	}
 919
 920	// Skip broken links.
 921	if (vitem->getIsBrokenLink())
 922	{
 923		return false;
 924	}
 925
 926	return (bool) get_is_item_worn(item->getUUID()) == mIsWorn;
 927}
 928
 929bool LLFindWearablesOfType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 930{
 931	if (!item) return false;
 932	if (item->getType() != LLAssetType::AT_CLOTHING &&
 933		item->getType() != LLAssetType::AT_BODYPART)
 934	{
 935		return false;
 936	}
 937
 938	LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item);
 939	if (!vitem || vitem->getWearableType() != mWearableType) return false;
 940
 941	return true;
 942}
 943
 944void LLFindWearablesOfType::setType(LLWearableType::EType type)
 945{
 946	mWearableType = type;
 947}
 948
 949bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 950{
 951	if (item)
 952	{
 953		return !get_is_item_removable(&gInventory, item->getUUID());
 954	}
 955	if (cat)
 956	{
 957		return !get_is_category_removable(&gInventory, cat->getUUID());
 958	}
 959
 960	llwarns << "Not a category and not an item?" << llendl;
 961	return false;
 962}
 963
 964///----------------------------------------------------------------------------
 965/// LLAssetIDMatches 
 966///----------------------------------------------------------------------------
 967bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 968{
 969	return (item && item->getAssetUUID() == mAssetID);
 970}
 971
 972///----------------------------------------------------------------------------
 973/// LLLinkedItemIDMatches 
 974///----------------------------------------------------------------------------
 975bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 976{
 977	return (item && 
 978			(item->getIsLinkType()) &&
 979			(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
 980}
 981
 982void LLSaveFolderState::setApply(BOOL apply)
 983{
 984	mApply = apply; 
 985	// before generating new list of open folders, clear the old one
 986	if(!apply) 
 987	{
 988		clearOpenFolders(); 
 989	}
 990}
 991
 992void LLSaveFolderState::doFolder(LLFolderViewFolder* folder)
 993{
 994	LLMemType mt(LLMemType::MTYPE_INVENTORY_DO_FOLDER);
 995	if(mApply)
 996	{
 997		// we're applying the open state
 998		LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener();
 999		if(!bridge) return;
1000		LLUUID id(bridge->getUUID());
1001		if(mOpenFolders.find(id) != mOpenFolders.end())
1002		{
1003			folder->setOpen(TRUE);
1004		}
1005		else
1006		{
1007			// keep selected filter in its current state, this is less jarring to user
1008			if (!folder->isSelected())
1009			{
1010				folder->setOpen(FALSE);
1011			}
1012		}
1013	}
1014	else
1015	{
1016		// we're recording state at this point
1017		if(folder->isOpen())
1018		{
1019			LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener();
1020			if(!bridge) return;
1021			mOpenFolders.insert(bridge->getUUID());
1022		}
1023	}
1024}
1025
1026void LLOpenFilteredFolders::doItem(LLFolderViewItem *item)
1027{
1028	if (item->getFiltered())
1029	{
1030		item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
1031	}
1032}
1033
1034void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder)
1035{
1036	if (folder->getFiltered() && folder->getParentFolder())
1037	{
1038		folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
1039	}
1040	// if this folder didn't pass the filter, and none of its descendants did
1041	else if (!folder->getFiltered() && !folder->hasFilteredDescendants())
1042	{
1043		folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO);
1044	}
1045}
1046
1047void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item)
1048{
1049	if (item->getFiltered() && !mItemSelected)
1050	{
1051		item->getRoot()->setSelection(item, FALSE, FALSE);
1052		if (item->getParentFolder())
1053		{
1054			item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
1055		}
1056		item->getRoot()->scrollToShowSelection();
1057		mItemSelected = TRUE;
1058	}
1059}
1060
1061void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder)
1062{
1063	if (folder->getFiltered() && !mItemSelected)
1064	{
1065		folder->getRoot()->setSelection(folder, FALSE, FALSE);
1066		if (folder->getParentFolder())
1067		{
1068			folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
1069		}
1070		folder->getRoot()->scrollToShowSelection();
1071		mItemSelected = TRUE;
1072	}
1073}
1074
1075void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item)
1076{
1077	if (item->getParentFolder() && item->isSelected())
1078	{
1079		item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
1080	}
1081}
1082
1083void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder)
1084{
1085	if (folder->getParentFolder() && folder->isSelected())
1086	{
1087		folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
1088	}
1089}
1090