PageRenderTime 916ms CodeModel.GetById 71ms app.highlight 665ms RepoModel.GetById 79ms app.codeStats 2ms

/indra/newview/llinventorybridge.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2423 lines | 1934 code | 297 blank | 192 comment | 447 complexity | 66041d855fcc39989ddec1ec50bf98f8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**
   2 * @file llinventorybridge.cpp
   3 * @brief Implementation of the Inventory-Folder-View-Bridge classes.
   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#include "llinventorybridge.h"
  29
  30// external projects
  31#include "lltransfersourceasset.h" 
  32#include "llavatarnamecache.h"	// IDEVO
  33
  34#include "llagent.h"
  35#include "llagentcamera.h"
  36#include "llagentwearables.h"
  37#include "llappearancemgr.h"
  38#include "llattachmentsmgr.h"
  39#include "llavataractions.h" 
  40#include "llfloateropenobject.h"
  41#include "llfloaterreg.h"
  42#include "llfloatersidepanelcontainer.h"
  43#include "llfloaterworldmap.h"
  44#include "llfolderview.h"
  45#include "llfriendcard.h"
  46#include "llgesturemgr.h"
  47#include "llgiveinventory.h" 
  48#include "llimfloater.h"
  49#include "llimview.h"
  50#include "llinventoryclipboard.h"
  51#include "llinventorydefines.h"
  52#include "llinventoryfunctions.h"
  53#include "llinventorymodel.h"
  54#include "llinventorymodelbackgroundfetch.h"
  55#include "llinventorypanel.h"
  56#include "llmarketplacefunctions.h"
  57#include "llnotifications.h"
  58#include "llnotificationsutil.h"
  59#include "llpreviewanim.h"
  60#include "llpreviewgesture.h"
  61#include "llpreviewtexture.h"
  62#include "llselectmgr.h"
  63#include "llsidepanelappearance.h"
  64#include "lltooldraganddrop.h"
  65#include "lltrans.h"
  66#include "llviewerassettype.h"
  67#include "llviewerfoldertype.h"
  68#include "llviewermenu.h"
  69#include "llviewermessage.h"
  70#include "llviewerobjectlist.h"
  71#include "llviewerwindow.h"
  72#include "llvoavatarself.h"
  73#include "llwearablelist.h"
  74
  75// Marketplace outbox current disabled
  76#define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU	1
  77#define ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU 0
  78#define BLOCK_WORN_ITEMS_IN_OUTBOX 1
  79
  80typedef std::pair<LLUUID, LLUUID> two_uuids_t;
  81typedef std::list<two_uuids_t> two_uuids_list_t;
  82
  83struct LLMoveInv
  84{
  85	LLUUID mObjectID;
  86	LLUUID mCategoryID;
  87	two_uuids_list_t mMoveList;
  88	void (*mCallback)(S32, void*);
  89	void* mUserData;
  90};
  91
  92using namespace LLOldEvents;
  93
  94// Helpers
  95// bug in busy count inc/dec right now, logic is complex... do we really need it?
  96void inc_busy_count()
  97{
  98// 	gViewerWindow->getWindow()->incBusyCount();
  99//  check balance of these calls if this code is changed to ever actually
 100//  *do* something!
 101}
 102void dec_busy_count()
 103{
 104// 	gViewerWindow->getWindow()->decBusyCount();
 105//  check balance of these calls if this code is changed to ever actually
 106//  *do* something!
 107}
 108
 109// Function declarations
 110void remove_inventory_category_from_avatar(LLInventoryCategory* category);
 111void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id);
 112bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
 113bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
 114void teleport_via_landmark(const LLUUID& asset_id);
 115static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
 116
 117// Helper functions
 118
 119bool isAddAction(const std::string& action)
 120{
 121	return ("wear" == action || "attach" == action || "activate" == action);
 122}
 123
 124bool isRemoveAction(const std::string& action)
 125{
 126	return ("take_off" == action || "detach" == action || "deactivate" == action);
 127}
 128
 129bool isMarketplaceCopyAction(const std::string& action)
 130{
 131	return (("copy_to_outbox" == action) || ("move_to_outbox" == action));
 132}
 133
 134bool isMarketplaceSendAction(const std::string& action)
 135{
 136	return ("send_to_marketplace" == action);
 137}
 138
 139// +=================================================+
 140// |        LLInvFVBridge                            |
 141// +=================================================+
 142
 143LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, 
 144							 LLFolderView* root,
 145							 const LLUUID& uuid) :
 146	mUUID(uuid), 
 147	mRoot(root),
 148	mInvType(LLInventoryType::IT_NONE),
 149	mIsLink(FALSE)
 150{
 151	mInventoryPanel = inventory->getHandle();
 152	const LLInventoryObject* obj = getInventoryObject();
 153	mIsLink = obj && obj->getIsLinkType();
 154}
 155
 156const std::string& LLInvFVBridge::getName() const
 157{
 158	const LLInventoryObject* obj = getInventoryObject();
 159	if(obj)
 160	{
 161		return obj->getName();
 162	}
 163	return LLStringUtil::null;
 164}
 165
 166const std::string& LLInvFVBridge::getDisplayName() const
 167{
 168	return getName();
 169}
 170
 171// Folders have full perms
 172PermissionMask LLInvFVBridge::getPermissionMask() const
 173{
 174	return PERM_ALL;
 175}
 176
 177// virtual
 178LLFolderType::EType LLInvFVBridge::getPreferredType() const
 179{
 180	return LLFolderType::FT_NONE;
 181}
 182
 183
 184// Folders don't have creation dates.
 185time_t LLInvFVBridge::getCreationDate() const
 186{
 187	return 0;
 188}
 189
 190// Can be destroyed (or moved to trash)
 191BOOL LLInvFVBridge::isItemRemovable() const
 192{
 193	return get_is_item_removable(getInventoryModel(), mUUID);
 194}
 195
 196// Can be moved to another folder
 197BOOL LLInvFVBridge::isItemMovable() const
 198{
 199	return TRUE;
 200}
 201
 202BOOL LLInvFVBridge::isLink() const
 203{
 204	return mIsLink;
 205}
 206
 207/*virtual*/
 208/**
 209 * @brief Adds this item into clipboard storage
 210 */
 211void LLInvFVBridge::cutToClipboard()
 212{
 213	if(isItemMovable())
 214	{
 215		LLInventoryClipboard::instance().cut(mUUID);
 216	}
 217}
 218// *TODO: make sure this does the right thing
 219void LLInvFVBridge::showProperties()
 220{
 221	show_item_profile(mUUID);
 222
 223	// Disable old properties floater; this is replaced by the sidepanel.
 224	/*
 225	  LLFloaterReg::showInstance("properties", mUUID);
 226	*/
 227}
 228
 229void LLInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch)
 230{
 231	// Deactivate gestures when moving them into Trash
 232	LLInvFVBridge* bridge;
 233	LLInventoryModel* model = getInventoryModel();
 234	LLViewerInventoryItem* item = NULL;
 235	LLViewerInventoryCategory* cat = NULL;
 236	LLInventoryModel::cat_array_t	descendent_categories;
 237	LLInventoryModel::item_array_t	descendent_items;
 238	S32 count = batch.count();
 239	S32 i,j;
 240	for(i = 0; i < count; ++i)
 241	{
 242		bridge = (LLInvFVBridge*)(batch.get(i));
 243		if(!bridge || !bridge->isItemRemovable()) continue;
 244		item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
 245		if (item)
 246		{
 247			if(LLAssetType::AT_GESTURE == item->getType())
 248			{
 249				LLGestureMgr::instance().deactivateGesture(item->getUUID());
 250			}
 251		}
 252	}
 253	for(i = 0; i < count; ++i)
 254	{
 255		bridge = (LLInvFVBridge*)(batch.get(i));
 256		if(!bridge || !bridge->isItemRemovable()) continue;
 257		cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
 258		if (cat)
 259		{
 260			gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, FALSE );
 261			for (j=0; j<descendent_items.count(); j++)
 262			{
 263				if(LLAssetType::AT_GESTURE == descendent_items[j]->getType())
 264				{
 265					LLGestureMgr::instance().deactivateGesture(descendent_items[j]->getUUID());
 266				}
 267			}
 268		}
 269	}
 270	removeBatchNoCheck(batch);
 271}
 272
 273void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*>& batch)
 274{
 275	// this method moves a bunch of items and folders to the trash. As
 276	// per design guidelines for the inventory model, the message is
 277	// built and the accounting is performed first. After all of that,
 278	// we call LLInventoryModel::moveObject() to move everything
 279	// around.
 280	LLInvFVBridge* bridge;
 281	LLInventoryModel* model = getInventoryModel();
 282	if(!model) return;
 283	LLMessageSystem* msg = gMessageSystem;
 284	const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
 285	LLViewerInventoryItem* item = NULL;
 286	uuid_vec_t move_ids;
 287	LLInventoryModel::update_map_t update;
 288	bool start_new_message = true;
 289	S32 count = batch.count();
 290	S32 i;
 291
 292	// first, hide any 'preview' floaters that correspond to the items
 293	// being deleted.
 294	for(i = 0; i < count; ++i)
 295	{
 296		bridge = (LLInvFVBridge*)(batch.get(i));
 297		if(!bridge || !bridge->isItemRemovable()) continue;
 298		item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
 299		if(item)
 300		{
 301			LLPreview::hide(item->getUUID());
 302		}
 303	}
 304
 305	// do the inventory move to trash
 306
 307	for(i = 0; i < count; ++i)
 308	{
 309		bridge = (LLInvFVBridge*)(batch.get(i));
 310		if(!bridge || !bridge->isItemRemovable()) continue;
 311		item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
 312		if(item)
 313		{
 314			if(item->getParentUUID() == trash_id) continue;
 315			move_ids.push_back(item->getUUID());
 316			--update[item->getParentUUID()];
 317			++update[trash_id];
 318			if(start_new_message)
 319			{
 320				start_new_message = false;
 321				msg->newMessageFast(_PREHASH_MoveInventoryItem);
 322				msg->nextBlockFast(_PREHASH_AgentData);
 323				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 324				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 325				msg->addBOOLFast(_PREHASH_Stamp, TRUE);
 326			}
 327			msg->nextBlockFast(_PREHASH_InventoryData);
 328			msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
 329			msg->addUUIDFast(_PREHASH_FolderID, trash_id);
 330			msg->addString("NewName", NULL);
 331			if(msg->isSendFullFast(_PREHASH_InventoryData))
 332			{
 333				start_new_message = true;
 334				gAgent.sendReliableMessage();
 335				gInventory.accountForUpdate(update);
 336				update.clear();
 337			}
 338		}
 339	}
 340	if(!start_new_message)
 341	{
 342		start_new_message = true;
 343		gAgent.sendReliableMessage();
 344		gInventory.accountForUpdate(update);
 345		update.clear();
 346	}
 347
 348	for(i = 0; i < count; ++i)
 349	{
 350		bridge = (LLInvFVBridge*)(batch.get(i));
 351		if(!bridge || !bridge->isItemRemovable()) continue;
 352		LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
 353		if(cat)
 354		{
 355			if(cat->getParentUUID() == trash_id) continue;
 356			move_ids.push_back(cat->getUUID());
 357			--update[cat->getParentUUID()];
 358			++update[trash_id];
 359			if(start_new_message)
 360			{
 361				start_new_message = false;
 362				msg->newMessageFast(_PREHASH_MoveInventoryFolder);
 363				msg->nextBlockFast(_PREHASH_AgentData);
 364				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 365				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 366				msg->addBOOL("Stamp", TRUE);
 367			}
 368			msg->nextBlockFast(_PREHASH_InventoryData);
 369			msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID());
 370			msg->addUUIDFast(_PREHASH_ParentID, trash_id);
 371			if(msg->isSendFullFast(_PREHASH_InventoryData))
 372			{
 373				start_new_message = true;
 374				gAgent.sendReliableMessage();
 375				gInventory.accountForUpdate(update);
 376				update.clear();
 377			}
 378		}
 379	}
 380	if(!start_new_message)
 381	{
 382		gAgent.sendReliableMessage();
 383		gInventory.accountForUpdate(update);
 384	}
 385
 386	// move everything.
 387	uuid_vec_t::iterator it = move_ids.begin();
 388	uuid_vec_t::iterator end = move_ids.end();
 389	for(; it != end; ++it)
 390	{
 391		gInventory.moveObject((*it), trash_id);
 392	}
 393
 394	// notify inventory observers.
 395	model->notifyObservers();
 396}
 397
 398BOOL LLInvFVBridge::isClipboardPasteable() const
 399{
 400	if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
 401	{
 402		return FALSE;
 403	}
 404	LLInventoryModel* model = getInventoryModel();
 405	if (!model)
 406	{
 407		return FALSE;
 408	}
 409
 410	const LLUUID &agent_id = gAgent.getID();
 411
 412	LLDynamicArray<LLUUID> objects;
 413	LLInventoryClipboard::instance().retrieve(objects);
 414	S32 count = objects.count();
 415	for(S32 i = 0; i < count; i++)
 416	{
 417		const LLUUID &item_id = objects.get(i);
 418
 419		// Can't paste folders
 420		const LLInventoryCategory *cat = model->getCategory(item_id);
 421		if (cat)
 422		{
 423			return FALSE;
 424		}
 425
 426		const LLInventoryItem *item = model->getItem(item_id);
 427		if (item)
 428		{
 429			if (!item->getPermissions().allowCopyBy(agent_id))
 430			{
 431				return FALSE;
 432			}
 433		}
 434	}
 435	return TRUE;
 436}
 437
 438BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
 439{
 440	if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
 441	{
 442		return FALSE;
 443	}
 444	const LLInventoryModel* model = getInventoryModel();
 445	if (!model)
 446	{
 447		return FALSE;
 448	}
 449
 450	LLDynamicArray<LLUUID> objects;
 451	LLInventoryClipboard::instance().retrieve(objects);
 452	S32 count = objects.count();
 453	for(S32 i = 0; i < count; i++)
 454	{
 455		const LLInventoryItem *item = model->getItem(objects.get(i));
 456		if (item)
 457		{
 458			if (!LLAssetType::lookupCanLink(item->getActualType()))
 459			{
 460				return FALSE;
 461			}
 462		}
 463		const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i));
 464		if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
 465		{
 466			return FALSE;
 467		}
 468	}
 469	return TRUE;
 470}
 471
 472void hide_context_entries(LLMenuGL& menu, 
 473						  const menuentry_vec_t &entries_to_show,
 474						  const menuentry_vec_t &disabled_entries)
 475{
 476	const LLView::child_list_t *list = menu.getChildList();
 477
 478	// For removing double separators or leading separator.  Start at true so that
 479	// if the first element is a separator, it will not be shown.
 480	bool is_previous_entry_separator = true;
 481
 482	for (LLView::child_list_t::const_iterator itor = list->begin(); 
 483		 itor != list->end(); 
 484		 ++itor)
 485	{
 486		LLView *menu_item = (*itor);
 487		std::string name = menu_item->getName();
 488
 489		// descend into split menus:
 490		LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item);
 491		if ((name == "More") && branchp)
 492		{
 493			hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries);
 494		}
 495
 496		bool found = false;
 497		menuentry_vec_t::const_iterator itor2;
 498		for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2)
 499		{
 500			if (*itor2 == name)
 501			{
 502				found = true;
 503				break;
 504			}
 505		}
 506
 507		// Don't allow multiple separators in a row (e.g. such as if there are no items
 508		// between two separators).
 509		if (found)
 510		{
 511			const bool is_entry_separator = (dynamic_cast<LLMenuItemSeparatorGL *>(menu_item) != NULL);
 512			found = !(is_entry_separator && is_previous_entry_separator);
 513			is_previous_entry_separator = is_entry_separator;
 514		}
 515		
 516		if (!found)
 517		{
 518			if (!menu_item->getLastVisible())
 519			{
 520				menu_item->setVisible(FALSE);
 521			}
 522
 523			menu_item->setEnabled(FALSE);
 524		}
 525		else
 526		{
 527			menu_item->setVisible(TRUE);
 528			// A bit of a hack so we can remember that some UI element explicitly set this to be visible
 529			// so that some other UI element from multi-select doesn't later set this invisible.
 530			menu_item->pushVisible(TRUE);
 531
 532			bool enabled = (menu_item->getEnabled() == TRUE);
 533			for (itor2 = disabled_entries.begin(); enabled && (itor2 != disabled_entries.end()); ++itor2)
 534			{
 535				enabled &= (*itor2 != name);
 536			}
 537
 538			menu_item->setEnabled(enabled);
 539		}
 540	}
 541}
 542
 543// Helper for commonly-used entries
 544void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
 545										menuentry_vec_t &items,
 546										menuentry_vec_t &disabled_items, U32 flags)
 547{
 548	const LLInventoryObject *obj = getInventoryObject();
 549
 550	if (obj)
 551	{
 552		if (obj->getIsLinkType())
 553		{
 554			items.push_back(std::string("Find Original"));
 555			if (isLinkedObjectMissing())
 556			{
 557				disabled_items.push_back(std::string("Find Original"));
 558			}
 559		}
 560		else
 561		{
 562			if (LLAssetType::lookupCanLink(obj->getType()))
 563			{
 564				items.push_back(std::string("Find Links"));
 565			}
 566
 567			if (!isInboxFolder())
 568			{
 569				items.push_back(std::string("Rename"));
 570				if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0)
 571				{
 572					disabled_items.push_back(std::string("Rename"));
 573				}
 574			}
 575			
 576			if (show_asset_id)
 577			{
 578				items.push_back(std::string("Copy Asset UUID"));
 579
 580				bool is_asset_knowable = false;
 581
 582				LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID);
 583				if (inv_item)
 584				{
 585					is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(inv_item->getType());
 586				}
 587				if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308
 588					 || (! ( isItemPermissive() || gAgent.isGodlike() ) )
 589					 || (flags & FIRST_SELECTED_ITEM) == 0)
 590				{
 591					disabled_items.push_back(std::string("Copy Asset UUID"));
 592				}
 593			}
 594			items.push_back(std::string("Copy Separator"));
 595			
 596			items.push_back(std::string("Copy"));
 597			if (!isItemCopyable())
 598			{
 599				disabled_items.push_back(std::string("Copy"));
 600			}
 601
 602			if (canListOnMarketplace())
 603			{
 604				items.push_back(std::string("Marketplace Separator"));
 605
 606				items.push_back(std::string("Merchant Copy"));
 607				if (!canListOnMarketplaceNow())
 608				{
 609					disabled_items.push_back(std::string("Merchant Copy"));
 610				}
 611			}
 612		}
 613	}
 614
 615	// Don't allow items to be pasted directly into the COF or the inbox/outbox
 616	if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder())
 617	{
 618		items.push_back(std::string("Paste"));
 619	}
 620	if (!isClipboardPasteable() || ((flags & FIRST_SELECTED_ITEM) == 0))
 621	{
 622		disabled_items.push_back(std::string("Paste"));
 623	}
 624
 625	if (gSavedSettings.getBOOL("InventoryLinking"))
 626	{
 627		items.push_back(std::string("Paste As Link"));
 628		if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0)
 629		{
 630			disabled_items.push_back(std::string("Paste As Link"));
 631		}
 632	}
 633
 634	items.push_back(std::string("Paste Separator"));
 635
 636	addDeleteContextMenuOptions(items, disabled_items);
 637
 638	// If multiple items are selected, disable properties (if it exists).
 639	if ((flags & FIRST_SELECTED_ITEM) == 0)
 640	{
 641		disabled_items.push_back(std::string("Properties"));
 642	}
 643}
 644
 645void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 646{
 647	lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl;
 648	menuentry_vec_t items;
 649	menuentry_vec_t disabled_items;
 650	if(isItemInTrash())
 651	{
 652		addTrashContextMenuOptions(items, disabled_items);
 653	}	
 654	else if(isOutboxFolder())
 655	{
 656		addOutboxContextMenuOptions(flags, items, disabled_items);
 657	}
 658	else
 659	{
 660		items.push_back(std::string("Share"));
 661		if (!canShare())
 662		{
 663			disabled_items.push_back(std::string("Share"));
 664		}
 665		
 666		addOpenRightClickMenuOption(items);
 667		items.push_back(std::string("Properties"));
 668
 669		getClipboardEntries(true, items, disabled_items, flags);
 670	}
 671	hide_context_entries(menu, items, disabled_items);
 672}
 673
 674void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items,
 675											   menuentry_vec_t &disabled_items)
 676{
 677	const LLInventoryObject *obj = getInventoryObject();
 678	if (obj && obj->getIsLinkType())
 679	{
 680		items.push_back(std::string("Find Original"));
 681		if (isLinkedObjectMissing())
 682		{
 683			disabled_items.push_back(std::string("Find Original"));
 684		}
 685	}
 686	items.push_back(std::string("Purge Item"));
 687	if (!isItemRemovable())
 688	{
 689		disabled_items.push_back(std::string("Purge Item"));
 690	}
 691	items.push_back(std::string("Restore Item"));
 692}
 693
 694void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
 695												menuentry_vec_t &disabled_items)
 696{
 697
 698	const LLInventoryObject *obj = getInventoryObject();
 699
 700	// Don't allow delete as a direct option from COF folder.
 701	if (obj && obj->getIsLinkType() && isCOFFolder() && get_is_item_worn(mUUID))
 702	{
 703		return;
 704	}
 705
 706	// "Remove link" and "Delete" are the same operation.
 707	if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID))
 708	{
 709		items.push_back(std::string("Remove Link"));
 710	}
 711	else
 712	{
 713		items.push_back(std::string("Delete"));
 714	}
 715
 716	if (!isItemRemovable())
 717	{
 718		disabled_items.push_back(std::string("Delete"));
 719	}
 720}
 721
 722void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items)
 723{
 724	const LLInventoryObject *obj = getInventoryObject();
 725	const BOOL is_link = (obj && obj->getIsLinkType());
 726
 727	if (is_link)
 728		items.push_back(std::string("Open Original"));
 729	else
 730		items.push_back(std::string("Open"));
 731}
 732
 733void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags,
 734												menuentry_vec_t &items,
 735												menuentry_vec_t &disabled_items)
 736{
 737	items.push_back(std::string("Rename"));
 738	items.push_back(std::string("Delete"));
 739	
 740	if ((flags & FIRST_SELECTED_ITEM) == 0)
 741	{
 742		disabled_items.push_back(std::string("Rename"));
 743	}
 744	
 745#if ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU
 746	if (isOutboxFolderDirectParent())
 747	{
 748		items.push_back(std::string("Marketplace Separator"));
 749		items.push_back(std::string("Marketplace Send"));
 750		
 751		if ((flags & FIRST_SELECTED_ITEM) == 0)
 752		{
 753			disabled_items.push_back(std::string("Marketplace Send"));
 754		}
 755	}
 756#endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU
 757}
 758
 759// *TODO: remove this
 760BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
 761{
 762	BOOL rv = FALSE;
 763
 764	const LLInventoryObject* obj = getInventoryObject();
 765
 766	if(obj)
 767	{
 768		*type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
 769		if(*type == DAD_NONE)
 770		{
 771			return FALSE;
 772		}
 773
 774		*id = obj->getUUID();
 775		//object_ids.put(obj->getUUID());
 776
 777		if (*type == DAD_CATEGORY)
 778		{
 779			LLInventoryModelBackgroundFetch::instance().start(obj->getUUID());
 780		}
 781
 782		rv = TRUE;
 783	}
 784
 785	return rv;
 786}
 787
 788LLInventoryObject* LLInvFVBridge::getInventoryObject() const
 789{
 790	LLInventoryObject* obj = NULL;
 791	LLInventoryModel* model = getInventoryModel();
 792	if(model)
 793	{
 794		obj = (LLInventoryObject*)model->getObject(mUUID);
 795	}
 796	return obj;
 797}
 798
 799LLInventoryModel* LLInvFVBridge::getInventoryModel() const
 800{
 801	LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
 802	return panel ? panel->getModel() : NULL;
 803}
 804
 805BOOL LLInvFVBridge::isItemInTrash() const
 806{
 807	LLInventoryModel* model = getInventoryModel();
 808	if(!model) return FALSE;
 809	const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
 810	return model->isObjectDescendentOf(mUUID, trash_id);
 811}
 812
 813BOOL LLInvFVBridge::isLinkedObjectInTrash() const
 814{
 815	if (isItemInTrash()) return TRUE;
 816
 817	const LLInventoryObject *obj = getInventoryObject();
 818	if (obj && obj->getIsLinkType())
 819	{
 820		LLInventoryModel* model = getInventoryModel();
 821		if(!model) return FALSE;
 822		const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
 823		return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id);
 824	}
 825	return FALSE;
 826}
 827
 828BOOL LLInvFVBridge::isLinkedObjectMissing() const
 829{
 830	const LLInventoryObject *obj = getInventoryObject();
 831	if (!obj)
 832	{
 833		return TRUE;
 834	}
 835	if (obj->getIsLinkType() && LLAssetType::lookupIsLinkType(obj->getType()))
 836	{
 837		return TRUE;
 838	}
 839	return FALSE;
 840}
 841
 842BOOL LLInvFVBridge::isAgentInventory() const
 843{
 844	const LLInventoryModel* model = getInventoryModel();
 845	if(!model) return FALSE;
 846	if(gInventory.getRootFolderID() == mUUID) return TRUE;
 847	return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
 848}
 849
 850BOOL LLInvFVBridge::isCOFFolder() const
 851{
 852	return LLAppearanceMgr::instance().getIsInCOF(mUUID);
 853}
 854
 855BOOL LLInvFVBridge::isInboxFolder() const
 856{
 857	const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false);
 858	
 859	if (inbox_id.isNull())
 860	{
 861		return FALSE;
 862	}
 863	
 864	return gInventory.isObjectDescendentOf(mUUID, inbox_id);
 865}
 866
 867BOOL LLInvFVBridge::isOutboxFolder() const
 868{
 869	const LLUUID outbox_id = getOutboxFolder();
 870
 871	if (outbox_id.isNull())
 872	{
 873		return FALSE;
 874	}
 875
 876	return gInventory.isObjectDescendentOf(mUUID, outbox_id);
 877}
 878
 879BOOL LLInvFVBridge::isOutboxFolderDirectParent() const
 880{
 881	BOOL outbox_is_parent = FALSE;
 882	
 883	const LLInventoryCategory *cat = gInventory.getCategory(mUUID);
 884
 885	if (cat)
 886	{
 887		const LLUUID outbox_id = getOutboxFolder();
 888		
 889		outbox_is_parent = (outbox_id.notNull() && (outbox_id == cat->getParentUUID()));
 890	}
 891	
 892	return outbox_is_parent;
 893}
 894
 895const LLUUID LLInvFVBridge::getOutboxFolder() const
 896{
 897	const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false);
 898
 899	return outbox_id;
 900}
 901
 902BOOL LLInvFVBridge::isItemPermissive() const
 903{
 904	return FALSE;
 905}
 906
 907// static
 908void LLInvFVBridge::changeItemParent(LLInventoryModel* model,
 909									 LLViewerInventoryItem* item,
 910									 const LLUUID& new_parent_id,
 911									 BOOL restamp)
 912{
 913	change_item_parent(model, item, new_parent_id, restamp);
 914}
 915
 916// static
 917void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
 918										 LLViewerInventoryCategory* cat,
 919										 const LLUUID& new_parent_id,
 920										 BOOL restamp)
 921{
 922	change_category_parent(model, cat, new_parent_id, restamp);
 923}
 924
 925LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
 926										   LLAssetType::EType actual_asset_type,
 927										   LLInventoryType::EType inv_type,
 928										   LLInventoryPanel* inventory,
 929										   LLFolderView* root,
 930										   const LLUUID& uuid,
 931										   U32 flags)
 932{
 933	LLInvFVBridge* new_listener = NULL;
 934	switch(asset_type)
 935	{
 936		case LLAssetType::AT_TEXTURE:
 937			if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
 938			{
 939				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 940			}
 941			new_listener = new LLTextureBridge(inventory, root, uuid, inv_type);
 942			break;
 943
 944		case LLAssetType::AT_SOUND:
 945			if(!(inv_type == LLInventoryType::IT_SOUND))
 946			{
 947				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 948			}
 949			new_listener = new LLSoundBridge(inventory, root, uuid);
 950			break;
 951
 952		case LLAssetType::AT_LANDMARK:
 953			if(!(inv_type == LLInventoryType::IT_LANDMARK))
 954			{
 955				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 956			}
 957			new_listener = new LLLandmarkBridge(inventory, root, uuid, flags);
 958			break;
 959
 960		case LLAssetType::AT_CALLINGCARD:
 961			if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
 962			{
 963				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 964			}
 965			new_listener = new LLCallingCardBridge(inventory, root, uuid);
 966			break;
 967
 968		case LLAssetType::AT_SCRIPT:
 969			if(!(inv_type == LLInventoryType::IT_LSL))
 970			{
 971				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 972			}
 973			new_listener = new LLItemBridge(inventory, root, uuid);
 974			break;
 975
 976		case LLAssetType::AT_OBJECT:
 977			if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
 978			{
 979				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 980			}
 981			new_listener = new LLObjectBridge(inventory, root, uuid, inv_type, flags);
 982			break;
 983
 984		case LLAssetType::AT_NOTECARD:
 985			if(!(inv_type == LLInventoryType::IT_NOTECARD))
 986			{
 987				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 988			}
 989			new_listener = new LLNotecardBridge(inventory, root, uuid);
 990			break;
 991
 992		case LLAssetType::AT_ANIMATION:
 993			if(!(inv_type == LLInventoryType::IT_ANIMATION))
 994			{
 995				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
 996			}
 997			new_listener = new LLAnimationBridge(inventory, root, uuid);
 998			break;
 999
1000		case LLAssetType::AT_GESTURE:
1001			if(!(inv_type == LLInventoryType::IT_GESTURE))
1002			{
1003				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
1004			}
1005			new_listener = new LLGestureBridge(inventory, root, uuid);
1006			break;
1007
1008		case LLAssetType::AT_LSL_TEXT:
1009			if(!(inv_type == LLInventoryType::IT_LSL))
1010			{
1011				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
1012			}
1013			new_listener = new LLLSLTextBridge(inventory, root, uuid);
1014			break;
1015
1016		case LLAssetType::AT_CLOTHING:
1017		case LLAssetType::AT_BODYPART:
1018			if(!(inv_type == LLInventoryType::IT_WEARABLE))
1019			{
1020				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
1021			}
1022			new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags);
1023			break;
1024		case LLAssetType::AT_CATEGORY:
1025			if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
1026			{
1027				// Create a link folder handler instead.
1028				new_listener = new LLLinkFolderBridge(inventory, root, uuid);
1029				break;
1030			}
1031			new_listener = new LLFolderBridge(inventory, root, uuid);
1032			break;
1033		case LLAssetType::AT_LINK:
1034		case LLAssetType::AT_LINK_FOLDER:
1035			// Only should happen for broken links.
1036			new_listener = new LLLinkItemBridge(inventory, root, uuid);
1037			break;
1038	    case LLAssetType::AT_MESH:
1039			if(!(inv_type == LLInventoryType::IT_MESH))
1040			{
1041				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
1042			}
1043			new_listener = new LLMeshBridge(inventory, root, uuid);
1044			break;
1045
1046		case LLAssetType::AT_IMAGE_TGA:
1047		case LLAssetType::AT_IMAGE_JPEG:
1048			//llwarns << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << llendl;
1049			break;
1050
1051		default:
1052			llinfos << "Unhandled asset type (llassetstorage.h): "
1053					<< (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << llendl;
1054			break;
1055	}
1056
1057	if (new_listener)
1058	{
1059		new_listener->mInvType = inv_type;
1060	}
1061
1062	return new_listener;
1063}
1064
1065void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
1066{
1067	LLInventoryCategory* cat = model->getCategory(uuid);
1068	if (cat)
1069	{
1070		model->purgeDescendentsOf(uuid);
1071		model->notifyObservers();
1072	}
1073	LLInventoryObject* obj = model->getObject(uuid);
1074	if (obj)
1075	{
1076		model->purgeObject(uuid);
1077		model->notifyObservers();
1078	}
1079}
1080
1081bool LLInvFVBridge::canShare() const
1082{
1083	bool can_share = false;
1084
1085	if (isAgentInventory())
1086	{
1087		const LLInventoryModel* model = getInventoryModel();
1088		if (model)
1089		{
1090			const LLViewerInventoryItem *item = model->getItem(mUUID);
1091			if (item)
1092			{
1093				if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item)) 
1094				{
1095					can_share = LLGiveInventory::isInventoryGiveAcceptable(item);
1096				}
1097			}
1098			else
1099			{
1100				// Categories can be given.
1101				can_share = (model->getCategory(mUUID) != NULL);
1102			}
1103		}
1104	}
1105
1106	return can_share;
1107}
1108
1109bool LLInvFVBridge::canListOnMarketplace() const
1110{
1111#if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU
1112
1113	LLInventoryModel * model = getInventoryModel();
1114
1115	const LLViewerInventoryCategory * cat = model->getCategory(mUUID);
1116	if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
1117	{
1118		return false;
1119	}
1120
1121	if (!isAgentInventory())
1122	{
1123		return false;
1124	}
1125	
1126	if (getOutboxFolder().isNull())
1127	{
1128		return false;
1129	}
1130
1131	if (isInboxFolder() || isOutboxFolder())
1132	{
1133		return false;
1134	}
1135	
1136	LLViewerInventoryItem * item = model->getItem(mUUID);
1137	if (item)
1138	{
1139		if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
1140		{
1141			return false;
1142		}
1143		
1144		if (LLAssetType::AT_CALLINGCARD == item->getType())
1145		{
1146			return false;
1147		}
1148	}
1149
1150	return true;
1151
1152#else
1153	return false;
1154#endif
1155}
1156
1157bool LLInvFVBridge::canListOnMarketplaceNow() const
1158{
1159#if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU
1160	
1161	bool can_list = true;
1162
1163	// Do not allow listing while import is in progress
1164	if (LLMarketplaceInventoryImporter::instanceExists())
1165	{
1166		can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress();
1167	}
1168	
1169	const LLInventoryObject* obj = getInventoryObject();
1170	can_list &= (obj != NULL);
1171
1172	if (can_list)
1173	{
1174		const LLUUID& object_id = obj->getLinkedUUID();
1175		can_list = object_id.notNull();
1176
1177		if (can_list)
1178		{
1179			LLFolderViewFolder * object_folderp = mRoot->getFolderByID(object_id);
1180			if (object_folderp)
1181			{
1182				can_list = !object_folderp->isLoading();
1183			}
1184		}
1185		
1186		if (can_list)
1187		{
1188			// Get outbox id
1189			const LLUUID & outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
1190			LLFolderViewItem * outbox_itemp = mRoot->getItemByID(outbox_id);
1191
1192			if (outbox_itemp)
1193			{
1194				MASK mask = 0x0;
1195				BOOL drop = FALSE;
1196				EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
1197				void * cargo_data = (void *) obj;
1198				std::string tooltip_msg;
1199				
1200				can_list = outbox_itemp->getListener()->dragOrDrop(mask, drop, cargo_type, cargo_data, tooltip_msg);
1201			}
1202		}
1203	}
1204	
1205	return can_list;
1206
1207#else
1208	return false;
1209#endif
1210}
1211
1212
1213// +=================================================+
1214// |        InventoryFVBridgeBuilder                 |
1215// +=================================================+
1216LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type,
1217														LLAssetType::EType actual_asset_type,
1218														LLInventoryType::EType inv_type,
1219														LLInventoryPanel* inventory,
1220														LLFolderView* root,
1221														const LLUUID& uuid,
1222														U32 flags /* = 0x00 */) const
1223{
1224	return LLInvFVBridge::createBridge(asset_type,
1225									   actual_asset_type,
1226									   inv_type,
1227									   inventory,
1228									   root,
1229									   uuid,
1230									   flags);
1231}
1232
1233// +=================================================+
1234// |        LLItemBridge                             |
1235// +=================================================+
1236
1237void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
1238{
1239	if ("goto" == action)
1240	{
1241		gotoItem();
1242	}
1243
1244	if ("open" == action || "open_original" == action)
1245	{
1246		openItem();
1247		return;
1248	}
1249	else if ("properties" == action)
1250	{
1251		showProperties();
1252		return;
1253	}
1254	else if ("purge" == action)
1255	{
1256		purgeItem(model, mUUID);
1257		return;
1258	}
1259	else if ("restoreToWorld" == action)
1260	{
1261		restoreToWorld();
1262		return;
1263	}
1264	else if ("restore" == action)
1265	{
1266		restoreItem();
1267		return;
1268	}
1269	else if ("copy_uuid" == action)
1270	{
1271		// Single item only
1272		LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
1273		if(!item) return;
1274		LLUUID asset_id = item->getProtectedAssetUUID();
1275		std::string buffer;
1276		asset_id.toString(buffer);
1277
1278		gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));
1279		return;
1280	}
1281	else if ("copy" == action)
1282	{
1283		copyToClipboard();
1284		return;
1285	}
1286	else if ("paste" == action)
1287	{
1288		// Single item only
1289		LLInventoryItem* itemp = model->getItem(mUUID);
1290		if (!itemp) return;
1291
1292		LLFolderViewItem* folder_view_itemp = mRoot->getItemByID(itemp->getParentUUID());
1293		if (!folder_view_itemp) return;
1294
1295		folder_view_itemp->getListener()->pasteFromClipboard();
1296		return;
1297	}
1298	else if ("paste_link" == action)
1299	{
1300		// Single item only
1301		LLInventoryItem* itemp = model->getItem(mUUID);
1302		if (!itemp) return;
1303
1304		LLFolderViewItem* folder_view_itemp = mRoot->getItemByID(itemp->getParentUUID());
1305		if (!folder_view_itemp) return;
1306
1307		folder_view_itemp->getListener()->pasteLinkFromClipboard();
1308		return;
1309	}
1310	else if (isMarketplaceCopyAction(action))
1311	{
1312		llinfos << "Copy item to marketplace action!" << llendl;
1313
1314		LLInventoryItem* itemp = model->getItem(mUUID);
1315		if (!itemp) return;
1316
1317		const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false);
1318		copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId());
1319	}
1320}
1321
1322void LLItemBridge::selectItem()
1323{
1324	LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
1325	if(item && !item->isFinished())
1326	{
1327		item->fetchFromServer();
1328		//LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false);
1329	}
1330}
1331
1332void LLItemBridge::restoreItem()
1333{
1334	LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
1335	if(item)
1336	{
1337		LLInventoryModel* model = getInventoryModel();
1338		const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType()));
1339		// do not restamp on restore.
1340		LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
1341	}
1342}
1343
1344void LLItemBridge::restoreToWorld()
1345{
1346	//Similar functionality to the drag and drop rez logic
1347	bool remove_from_inventory = false;
1348
1349	LLViewerInventoryItem* itemp = static_cast<LLViewerInventoryItem*>(getItem());
1350	if (itemp)
1351	{
1352		LLMessageSystem* msg = gMessageSystem;
1353		msg->newMessage("RezRestoreToWorld");
1354		msg->nextBlockFast(_PREHASH_AgentData);
1355		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1356		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1357
1358		msg->nextBlockFast(_PREHASH_InventoryData);
1359		itemp->packMessage(msg);
1360		msg->sendReliable(gAgent.getRegion()->getHost());
1361
1362		//remove local inventory copy, sim will deal with permissions and removing the item
1363		//from the actual inventory if its a no-copy etc
1364		if(!itemp->getPermissions().allowCopyBy(gAgent.getID()))
1365		{
1366			remove_from_inventory = true;
1367		}
1368		
1369		// Check if it's in the trash. (again similar to the normal rez logic)
1370		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
1371		if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id))
1372		{
1373			remove_from_inventory = true;
1374		}
1375	}
1376
1377	if(remove_from_inventory)
1378	{
1379		gInventory.deleteObject(itemp->getUUID());
1380		gInventory.notifyObservers();
1381	}
1382}
1383
1384void LLItemBridge::gotoItem()
1385{
1386	LLInventoryObject *obj = getInventoryObject();
1387	if (obj && obj->getIsLinkType())
1388	{
1389		LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
1390		if (active_panel)
1391		{
1392			active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO);
1393		}
1394	}
1395}
1396
1397LLUIImagePtr LLItemBridge::getIcon() const
1398{
1399	LLInventoryObject *obj = getInventoryObject();
1400	if (obj) 
1401	{
1402		return LLInventoryIcon::getIcon(obj->getType(),
1403										LLInventoryType::IT_NONE,
1404										mIsLink);
1405	}
1406	
1407	return LLInventoryIcon::getIcon(LLInventoryIcon::ICONNAME_OBJECT);
1408}
1409
1410PermissionMask LLItemBridge::getPermissionMask() const
1411{
1412	LLViewerInventoryItem* item = getItem();
1413	PermissionMask perm_mask = 0;
1414	if (item) perm_mask = item->getPermissionMask();
1415	return perm_mask;
1416}
1417
1418const std::string& LLItemBridge::getDisplayName() const
1419{
1420	if(mDisplayName.empty())
1421	{
1422		buildDisplayName(getItem(), mDisplayName);
1423	}
1424	return mDisplayName;
1425}
1426
1427void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name)
1428{
1429	if(item)
1430	{
1431		name.assign(item->getName());
1432	}
1433	else
1434	{
1435		name.assign(LLStringUtil::null);
1436	}
1437}
1438
1439LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
1440{
1441	U8 font = LLFontGL::NORMAL;
1442	const LLViewerInventoryItem* item = getItem();
1443
1444	if (get_is_item_worn(mUUID))
1445	{
1446		// llinfos << "BOLD" << llendl;
1447		font |= LLFontGL::BOLD;
1448	}
1449	else if(item && item->getIsLinkType())
1450	{
1451		font |= LLFontGL::ITALIC;
1452	}
1453
1454	return (LLFontGL::StyleFlags)font;
1455}
1456
1457std::string LLItemBridge::getLabelSuffix() const
1458{
1459	// String table is loaded before login screen and inventory items are
1460	// loaded after login, so LLTrans should be ready.
1461	static std::string NO_COPY = LLTrans::getString("no_copy");
1462	static std::string NO_MOD = LLTrans::getString("no_modify");
1463	static std::string NO_XFER = LLTrans::getString("no_transfer");
1464	static std::string LINK = LLTrans::getString("link");
1465	static std::string BROKEN_LINK = LLTrans::getString("broken_link");
1466	std::string suffix;
1467	LLInventoryItem* item = getItem();
1468	if(item)
1469	{
1470		// Any type can have the link suffix...
1471		BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType());
1472		if (broken_link) return BROKEN_LINK;
1473
1474		BOOL link = item->getIsLinkType();
1475		if (link) return LINK;
1476
1477		// ...but it's a bit confusing to put nocopy/nomod/etc suffixes on calling cards.
1478		if(LLAssetType::AT_CALLINGCARD != item->getType()
1479		   && item->getPermissions().getOwner() == gAgent.getID())
1480		{
1481			BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
1482			if (!copy)
1483			{
1484				suffix += NO_COPY;
1485			}
1486			BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
1487			if (!mod)
1488			{
1489				suffix += NO_MOD;
1490			}
1491			BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
1492																gAgent.getID());
1493			if (!xfer)
1494			{
1495				suffix += NO_XFER;
1496			}
1497		}
1498	}
1499	return suffix;
1500}
1501
1502time_t LLItemBridge::getCreationDate() const
1503{
1504	LLViewerInventoryItem* item = getItem();
1505	if (item)
1506	{
1507		return item->getCreationDate();
1508	}
1509	return 0;
1510}
1511
1512
1513BOOL LLItemBridge::isItemRenameable() const
1514{
1515	LLViewerInventoryItem* item = getItem();
1516	if(item)
1517	{
1518		// (For now) Don't allow calling card rename since that may confuse users as to
1519		// what the calling card points to.
1520		if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
1521		{
1522			return FALSE;
1523		}
1524
1525		if (!item->isFinished()) // EXT-8662
1526		{
1527			return FALSE;
1528		}
1529
1530		if (isInboxFolder())
1531		{
1532			return FALSE;
1533		}
1534
1535		return (item->getPermissions().allowModifyBy(gAgent.getID()));
1536	}
1537	return FALSE;
1538}
1539
1540BOOL LLItemBridge::renameItem(const std::string& new_name)
1541{
1542	if(!isItemRenameable())
1543		return FALSE;
1544	LLPreview::dirty(mUUID);
1545	LLInventoryModel* model = getInventoryModel();
1546	if(!model)
1547		return FALSE;
1548	LLViewerInventoryItem* item = getItem();
1549	if(item && (item->getName() != new_name))
1550	{
1551		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
1552		new_item->rename(new_name);
1553		buildDisplayName(new_item, mDisplayName);
1554		new_item->updateServer(FALSE);
1555		model->updateItem(new_item);
1556
1557		model->notifyObservers();
1558	}
1559	// return FALSE because we either notified observers (& therefore
1560	// rebuilt) or we didn't update.
1561	return FALSE;
1562}
1563
1564
1565BOOL LLItemBridge::removeItem()
1566{
1567	if(!isItemRemovable())
1568	{
1569		return FALSE;
1570	}
1571
1572	
1573	// move it to the trash
1574	LLPreview::hide(mUUID, TRUE);
1575	LLInventoryModel* model = getInventoryModel();
1576	if(!model) return FALSE;
1577	const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
1578	LLViewerInventoryItem* item = getItem();
1579	if (!item) return FALSE;
1580
1581	// Already in trash
1582	if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE;
1583
1584	LLNotification::Params params("ConfirmItemDeleteHasLinks");
1585	params.functor.function(boost::bind(&LLItemBridge::confirmRemoveItem, this, _1, _2));
1586	
1587	// Check if this item has any links.  If generic inventory linking is enabled,
1588	// we can't do this check because we may have items in a folder somewhere that is
1589	// not yet in memory, so we don't want false negatives.  (If disabled, then we 
1590	// know we only have links in the Outfits folder which we explicitly fetch.)
1591	if (!gSavedSettings.getBOOL("InventoryLinking"))
1592	{
1593		if (!item->getIsLinkType())
1594		{
1595			LLInventoryModel::cat_array_t cat_array;
1596			LLInventoryModel::item_array_t item_array;
1597			LLLinkedItemIDMatches is_linked_item_match(mUUID);
1598			gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
1599											cat_array,
1600											item_array,
1601											LLInventoryModel::INCLUDE_TRASH,
1602											is_linked_item_match);
1603
1604			const U32 num_links = cat_array.size() + item_array.size();
1605			if (num_links > 0)
1606			{
1607				// Warn if the user is will break any links when deleting this item.
1608				LLNotifications::instance().add(params);
1609				return FALSE;
1610			}
1611		}
1612	}
1613	
1614	LLNotifications::instance().forceResponse(params, 0);
1615	return TRUE;
1616}
1617
1618BOOL LLItemBridge::confirmRemoveItem(const LLSD& notification, const LLSD& response)
1619{
1620	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
1621	if (option != 0) return FALSE;
1622
1623	LLInventoryModel* model = getInventoryModel();
1624	if (!model) return FALSE;
1625
1626	LLViewerInventoryItem* item = getItem();
1627	if (!item) return FALSE;
1628
1629	const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
1630	// if item is not already in trash
1631	if(item && !model->isObjectDescendentOf(mUUID, trash_id))
1632	{
1633		// move to trash, and restamp
1634		LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE);
1635		// delete was successful
1636		return TRUE;
1637	}
1638	return FALSE;
1639}
1640
1641BOOL LLItemBridge::isItemCopyable() const
1642{
1643	LLViewerInventoryItem* item = getItem();
1644	if (item)
1645	{
1646		// Can't copy worn objects. DEV-15183
1647		if(get_is_item_worn(mUUID))
1648		{
1649			return FALSE;
1650		}
1651
1652		// You can never copy a link.
1653		if (item->getIsLinkType())
1654		{
1655			return FALSE;
1656		}
1657
1658		return item->getPermissions().allowCopyBy(gAgent.getID()) || gSavedSettings.getBOOL("InventoryLinking");
1659	}
1660	return FALSE;
1661}
1662
1663BOOL LLItemBridge::copyToClipboard() const
1664{
1665	if(isItemCopyable())
1666	{
1667		LLInventoryClipboard::instance().add(mUUID);
1668		return TRUE;
1669	}
1670	return FALSE;
1671}
1672
1673LLViewerInventoryItem* LLItemBridge::getItem() const
1674{
1675	LLViewerInventoryItem* item = NULL;
1676	LLInventoryModel* model = getInventoryModel();
1677	if(model)
1678	{
1679		item = (LLViewerInventoryItem*)model->getItem(mUUID);
1680	}
1681	return item;
1682}
1683
1684BOOL LLItemBridge::isItemPermissive() const
1685{
1686	LLViewerInventoryItem* item = getItem();
1687	if(item)
1688	{
1689		return item->getIsFullPerm();
1690	}
1691	return FALSE;
1692}
1693
1694// +=================================================+
1695// |        LLFolderBridge                           |
1696// +=================================================+
1697
1698LLHandle<LLFolderBridge> LLFolderBridge::sSelf;
1699
1700// Can be moved to another folder
1701BOOL LLFolderBridge::isItemMovable() const
1702{
1703	LLInventoryObject* obj = getInventoryObject();
1704	if(obj)
1705	{
1706		return (!LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType()));
1707	}
1708	return FALSE;
1709}
1710
1711void LLFolderBridge::selectItem()
1712{
1713}
1714
1715
1716// Iterate through a folder's children to determine if
1717// all the children are removable.
1718class LLIsItemRemovable : public LLFolderViewFunctor
1719{
1720public:
1721	LLIsItemRemovable() : mPassed(TRUE) {}
1722	virtual void doFolder(LLFolderViewFolder* folder)
1723	{
1724		mPassed &= folder->getListener()->isItemRemovable();
1725	}
1726	virtual void doItem(LLFolderViewItem* item)
1727	{
1728		mPassed &= item->getListener()->isItemRemovable();
1729	}
1730	BOOL mPassed;
1731};
1732
1733// Can be destroyed (or moved to trash)
1734BOOL LLFolderBridge::isItemRemovable() const
1735{
1736	if (!get_is_category_removable(getInventoryModel(), mUUID))
1737	{
1738		return FALSE;
1739	}
1740
1741	LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
1742	LLFolderViewFolder* folderp = dynamic_cast<LLFolderViewFolder*>(panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL);
1743	if (folderp)
1744	{
1745		LLIsItemRemovable folder_test;
1746		folderp->applyFunctorToChildren(folder_test);
1747		if (!folder_test.mPassed)
1748		{
1749			return FALSE;
1750		}
1751	}
1752
1753	return TRUE;
1754}
1755
1756BOOL LLFolderBridge::isUpToDate() const
1757{
1758	LLInventoryModel* model = getInventoryModel();
1759	if(!model) return FALSE;
1760	LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
1761	if( !category )
1762	{
1763		return FALSE;
1764	}
1765
1766	return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;
1767}
1768
1769BOOL LLFolderBridge::isItemCopyable() const
1770{
1771	// Can copy folders to paste-as-link, but not for straight paste.
1772	return gSavedSettings.getBOOL("InventoryLinking");
1773}
1774
1775BOOL LLFolderBridge::copyToClipboard() const
1776{
1777	if(isItemCopyable())
1778	{
1779		LLInventoryClipboard::instance().add(mUUID);
1780		return TRUE;
1781	}
1782	return FALSE;
1783}
1784
1785BOOL LLFolderBridge::isClipboardPasteable() const
1786{
1787	if ( ! LLInvFVBridge::isClipboardPasteable() )
1788		return FALSE;
1789
1790	// Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
1791	if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) )
1792	{
1793		LLInventoryModel* model = getInventoryModel();
1794		if ( !model )
1795		{
1796			return FALSE;
1797		}
1798
1799		LLDynamicArray<LLUUID> objects;
1800		LLInventoryClipboard::instance().retrieve(objects);
1801		const LLViewerInventoryCategory *current_cat = getCategory();
1802
1803		// Search for the direct descendent of current Friends subfolder among all pasted items,
1804		// and return false if is found.
1805		for(S32 i = objects.count() - 1; i >= 0; --i)
1806		{
1807			const LLUUID &obj_id = objects.get(i);
1808			if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
1809			{
1810				return FALSE;
1811			}
1812		}
1813
1814	}
1815	return TRUE;
1816}
1817
1818BOOL LLFolderBridge::isClipboardPasteableAsLink() const
1819{
1820	// Check normal paste-as-link permissions
1821	if (!LLInvFVBridge::isClipboardPasteableAsLink())
1822	{
1823		return FALSE;
1824	}
1825
1826	const LLInventoryModel* model = getInventoryModel();
1827	if (!model)
1828	{
1829		return FALSE;
1830	}
1831
1832	const LLViewerInventoryCategory *current_cat = getCategory();
1833	if (current_cat)
1834	{
1835		const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat );
1836		const LLUUID &current_cat_id = current_cat->getUUID();
1837		LLDynamicArray<LLUUID> objects;
1838		LLInventoryClipboard::instance().retrieve(objects);
1839		S32 count = objects.count();
1840		for(S32 i = 0; i < count; i++)
1841		{
1842			const LLUUID &obj_id = objects.get(i);
1843			const LLInventoryCategory *cat = model->getCategory(obj_id);
1844			if (cat)
1845			{
1846				const LLUUID &cat_id = cat->getUUID();
1847				// Don't allow recursive pasting
1848				if ((cat_id == current_cat_id) ||
1849					model->isObjectDescendentOf(current_cat_id, cat_id))
1850				{
1851					return FALSE;
1852				}
1853			}
1854			// Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
1855			if ( is_in_friend_folder )
1856			{
1857				// If object is direct descendent of current Friends subfolder than return false.
1858				// Note: We can't use 'const LLInventoryCategory *cat', because it may be null
1859				// in case type of obj_id is LLInventoryItem.
1860				if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
1861				{
1862					return FALSE;
1863				}
1864			}
1865		}
1866	}
1867	return TRUE;
1868
1869}
1870
1871static BOOL can_move_to_outbox(LLInventoryItem* inv_item, std::string& tooltip_msg)
1872{
1873	// Collapse links directly to items/folders
1874	LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
1875	LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem();
1876	if (linked_item != NULL)
1877	{
1878		inv_item = linked_item;
1879	}
1880	
1881	bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID());
1882	if (!allow_transfer)
1883	{
1884		tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer");
1885		return false;
1886	}
1887
1888#if BLOCK_WORN_ITEMS_IN_OUTBOX
1889	bool worn = get_is_item_worn(inv_item->getUUID());
1890	if (worn)
1891	{
1892		tooltip_msg = LLTrans::getString("TooltipOutboxWorn");
1893		return false;
1894	}
1895#endif
1896	
1897	bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType());
1898	if (calling_card)
1899	{
1900		tooltip_msg = LLTrans::getString("T…

Large files files are truncated, but you can click here to view the full file