PageRenderTime 123ms CodeModel.GetById 25ms app.highlight 87ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/newview/lltooldraganddrop.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2332 lines | 1792 code | 213 blank | 327 comment | 371 complexity | 15e4b703e8f763512171ef56912241da MD5 | raw file
Possible License(s): LGPL-2.1
   1/** 
   2 * @file lltooldraganddrop.cpp
   3 * @brief LLToolDragAndDrop class implementation
   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 "lltooldraganddrop.h"
  29
  30// library headers
  31#include "llnotificationsutil.h"
  32// project headers
  33#include "llagent.h"
  34#include "llagentcamera.h"
  35#include "llagentwearables.h"
  36#include "llappearancemgr.h"
  37#include "lldictionary.h"
  38#include "llfloaterreg.h"
  39#include "llfloatertools.h"
  40#include "llgesturemgr.h"
  41#include "llgiveinventory.h"
  42#include "llhudmanager.h"
  43#include "llhudeffecttrail.h"
  44#include "llimview.h"
  45#include "llinventorybridge.h"
  46#include "llinventorydefines.h"
  47#include "llinventoryfunctions.h"
  48#include "llpreviewnotecard.h"
  49#include "llrootview.h"
  50#include "llselectmgr.h"
  51#include "lltoolmgr.h"
  52#include "lltooltip.h"
  53#include "lltrans.h"
  54#include "llviewerobjectlist.h"
  55#include "llviewerregion.h"
  56#include "llviewerstats.h"
  57#include "llviewerwindow.h"
  58#include "llvoavatarself.h"
  59#include "llworld.h"
  60#include "llclipboard.h"
  61
  62// syntactic sugar
  63#define callMemberFunction(object,ptrToMember)  ((object).*(ptrToMember))
  64
  65class LLNoPreferredType : public LLInventoryCollectFunctor
  66{
  67public:
  68	LLNoPreferredType() {}
  69	virtual ~LLNoPreferredType() {}
  70	virtual bool operator()(LLInventoryCategory* cat,
  71							LLInventoryItem* item)
  72	{
  73		if (cat && (cat->getPreferredType() == LLFolderType::FT_NONE))
  74		{
  75			return true;
  76		}
  77		return false;
  78	}
  79};
  80
  81class LLNoPreferredTypeOrItem : public LLInventoryCollectFunctor
  82{
  83public:
  84	LLNoPreferredTypeOrItem() {}
  85	virtual ~LLNoPreferredTypeOrItem() {}
  86	virtual bool operator()(LLInventoryCategory* cat,
  87							LLInventoryItem* item)
  88	{
  89		if (item) return true;
  90		if (cat && (cat->getPreferredType() == LLFolderType::FT_NONE))
  91		{
  92			return true;
  93		}
  94		return false;
  95	}
  96};
  97
  98class LLDroppableItem : public LLInventoryCollectFunctor
  99{
 100public:
 101	LLDroppableItem(BOOL is_transfer) :
 102		mCountLosing(0), mIsTransfer(is_transfer) {}
 103	virtual ~LLDroppableItem() {}
 104	virtual bool operator()(LLInventoryCategory* cat,
 105							LLInventoryItem* item);
 106	S32 countNoCopy() const { return mCountLosing; }
 107
 108protected:
 109	S32 mCountLosing;
 110	BOOL mIsTransfer;
 111};
 112
 113bool LLDroppableItem::operator()(LLInventoryCategory* cat,
 114				 LLInventoryItem* item)
 115{
 116	bool allowed = false;
 117	if (item)
 118	{
 119		allowed = itemTransferCommonlyAllowed(item);
 120
 121		if (allowed
 122		   && mIsTransfer
 123		   && !item->getPermissions().allowOperationBy(PERM_TRANSFER,
 124							       gAgent.getID()))
 125		{
 126			allowed = false;
 127		}
 128		if (allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
 129		{
 130			++mCountLosing;
 131		}
 132	}
 133	return allowed;
 134}
 135
 136class LLDropCopyableItems : public LLInventoryCollectFunctor
 137{
 138public:
 139	LLDropCopyableItems() {}
 140	virtual ~LLDropCopyableItems() {}
 141	virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
 142};
 143
 144
 145bool LLDropCopyableItems::operator()(
 146	LLInventoryCategory* cat,
 147	LLInventoryItem* item)
 148{
 149	bool allowed = false;
 150	if (item)
 151	{
 152		allowed = itemTransferCommonlyAllowed(item);
 153		if (allowed &&
 154		   !item->getPermissions().allowCopyBy(gAgent.getID()))
 155		{
 156			// whoops, can't copy it - don't allow it.
 157			allowed = false;
 158		}
 159	}
 160	return allowed;
 161}
 162
 163// Starts a fetch on folders and items.  This is really not used 
 164// as an observer in the traditional sense; we're just using it to
 165// request a fetch and we don't care about when/if the response arrives.
 166class LLCategoryFireAndForget : public LLInventoryFetchComboObserver
 167{
 168public:
 169	LLCategoryFireAndForget(const uuid_vec_t& folder_ids,
 170							const uuid_vec_t& item_ids) :
 171		LLInventoryFetchComboObserver(folder_ids, item_ids)
 172	{}
 173	~LLCategoryFireAndForget() {}
 174	virtual void done()
 175	{
 176		/* no-op: it's fire n forget right? */
 177		lldebugs << "LLCategoryFireAndForget::done()" << llendl;
 178	}
 179};
 180
 181class LLCategoryDropObserver : public LLInventoryFetchItemsObserver
 182{
 183public:
 184	LLCategoryDropObserver(
 185		const uuid_vec_t& ids,
 186		const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
 187		LLInventoryFetchItemsObserver(ids),
 188		mObjectID(obj_id),
 189		mSource(src)
 190	{}
 191	~LLCategoryDropObserver() {}
 192	virtual void done();
 193
 194protected:
 195	LLUUID mObjectID;
 196	LLToolDragAndDrop::ESource mSource;
 197};
 198
 199void LLCategoryDropObserver::done()
 200{
 201	gInventory.removeObserver(this);
 202	LLViewerObject* dst_obj = gObjectList.findObject(mObjectID);
 203	if (dst_obj)
 204	{
 205		// *FIX: coalesce these...
 206 		LLInventoryItem* item = NULL;
 207  		uuid_vec_t::iterator it = mComplete.begin();
 208  		uuid_vec_t::iterator end = mComplete.end();
 209  		for(; it < end; ++it)
 210  		{
 211 			item = gInventory.getItem(*it);
 212 			if (item)
 213 			{
 214 				LLToolDragAndDrop::dropInventory(
 215 					dst_obj,
 216 					item,
 217 					mSource,
 218 					LLUUID::null);
 219 			}
 220  		}
 221	}
 222	delete this;
 223}
 224/* Doesn't seem to be used anymore.
 225class LLCategoryDropDescendentsObserver : public LLInventoryFetchDescendentsObserver
 226{
 227public:
 228	LLCategoryDropDescendentsObserver(
 229		const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
 230		mObjectID(obj_id),
 231		mSource(src)
 232	{}
 233	~LLCategoryDropDescendentsObserver() {}
 234	virtual void done();
 235
 236protected:
 237	LLUUID mObjectID;
 238	LLToolDragAndDrop::ESource mSource;
 239};
 240
 241void LLCategoryDropDescendentsObserver::done()
 242{
 243
 244	gInventory.removeObserver(this);
 245	uuid_vec_t::iterator it = mComplete.begin();
 246	uuid_vec_t::iterator end = mComplete.end();
 247	LLViewerInventoryCategory::cat_array_t cats;
 248	LLViewerInventoryItem::item_array_t items;
 249	for(; it != end; ++it)
 250	{
 251		gInventory.collectDescendents(
 252			(*it),
 253			cats,
 254			items,
 255			LLInventoryModel::EXCLUDE_TRASH);
 256	}
 257
 258	S32 count = items.count();
 259	if (count)
 260	{
 261		std::set<LLUUID> unique_ids;
 262		for(S32 i = 0; i < count; ++i)
 263		{
 264			unique_ids.insert(items.get(i)->getUUID());
 265		}
 266		uuid_vec_t ids;
 267		std::back_insert_iterator<uuid_vec_t> copier(ids);
 268		std::copy(unique_ids.begin(), unique_ids.end(), copier);
 269		LLCategoryDropObserver* dropper;
 270		dropper = new LLCategoryDropObserver(ids, mObjectID, mSource);
 271		dropper->startFetch();
 272		if (dropper->isDone())
 273		{
 274			dropper->done();
 275		}
 276		else
 277		{
 278			gInventory.addObserver(dropper);
 279		}
 280	}
 281	delete this;
 282}
 283*/
 284
 285S32 LLToolDragAndDrop::sOperationId = 0;
 286
 287LLToolDragAndDrop::DragAndDropEntry::DragAndDropEntry(dragOrDrop3dImpl f_none,
 288													  dragOrDrop3dImpl f_self,
 289													  dragOrDrop3dImpl f_avatar,
 290													  dragOrDrop3dImpl f_object,
 291													  dragOrDrop3dImpl f_land) :
 292	LLDictionaryEntry("")
 293{
 294	mFunctions[DT_NONE] = f_none;
 295	mFunctions[DT_SELF] = f_self;
 296	mFunctions[DT_AVATAR] = f_avatar;
 297	mFunctions[DT_OBJECT] = f_object;
 298	mFunctions[DT_LAND] = f_land;
 299}
 300
 301LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::LLDragAndDropDictionary::get(EDragAndDropType dad_type, LLToolDragAndDrop::EDropTarget drop_target)
 302{
 303	const DragAndDropEntry *entry = lookup(dad_type);
 304	if (entry)
 305	{
 306		return (entry->mFunctions[(U8)drop_target]);
 307	}
 308	return &LLToolDragAndDrop::dad3dNULL;
 309}
 310
 311LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary()
 312{
 313 	//       										 DT_NONE                         DT_SELF                                        DT_AVATAR                   					DT_OBJECT                       					DT_LAND		
 314	//      										|-------------------------------|----------------------------------------------|-----------------------------------------------|---------------------------------------------------|--------------------------------|
 315	addEntry(DAD_NONE, 			new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,						&LLToolDragAndDrop::dad3dNULL));
 316	addEntry(DAD_TEXTURE, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory,			&LLToolDragAndDrop::dad3dTextureObject,				&LLToolDragAndDrop::dad3dNULL));
 317	addEntry(DAD_SOUND, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory,			&LLToolDragAndDrop::dad3dUpdateInventory,			&LLToolDragAndDrop::dad3dNULL));
 318	addEntry(DAD_CALLINGCARD, 	new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory, 		&LLToolDragAndDrop::dad3dUpdateInventory, 			&LLToolDragAndDrop::dad3dNULL));
 319	addEntry(DAD_LANDMARK, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, 					&LLToolDragAndDrop::dad3dGiveInventory, 		&LLToolDragAndDrop::dad3dUpdateInventory, 			&LLToolDragAndDrop::dad3dNULL));
 320	addEntry(DAD_SCRIPT, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, 					&LLToolDragAndDrop::dad3dGiveInventory, 		&LLToolDragAndDrop::dad3dRezScript, 				&LLToolDragAndDrop::dad3dNULL));
 321	addEntry(DAD_CLOTHING, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, 				&LLToolDragAndDrop::dad3dGiveInventory, 		&LLToolDragAndDrop::dad3dUpdateInventory, 			&LLToolDragAndDrop::dad3dNULL));
 322	addEntry(DAD_OBJECT, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dRezAttachmentFromInv,	&LLToolDragAndDrop::dad3dGiveInventoryObject,	&LLToolDragAndDrop::dad3dRezObjectOnObject, 		&LLToolDragAndDrop::dad3dRezObjectOnLand));
 323	addEntry(DAD_NOTECARD, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, 					&LLToolDragAndDrop::dad3dGiveInventory, 		&LLToolDragAndDrop::dad3dUpdateInventory, 			&LLToolDragAndDrop::dad3dNULL));
 324	addEntry(DAD_CATEGORY, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory,			&LLToolDragAndDrop::dad3dGiveInventoryCategory,	&LLToolDragAndDrop::dad3dUpdateInventoryCategory,	&LLToolDragAndDrop::dad3dNULL));
 325	addEntry(DAD_ROOT_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,						&LLToolDragAndDrop::dad3dNULL));
 326	addEntry(DAD_BODYPART, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dWearItem,				&LLToolDragAndDrop::dad3dGiveInventory,			&LLToolDragAndDrop::dad3dUpdateInventory,			&LLToolDragAndDrop::dad3dNULL));
 327	addEntry(DAD_ANIMATION, 	new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory,			&LLToolDragAndDrop::dad3dUpdateInventory,			&LLToolDragAndDrop::dad3dNULL));
 328	addEntry(DAD_GESTURE, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dActivateGesture,		&LLToolDragAndDrop::dad3dGiveInventory,			&LLToolDragAndDrop::dad3dUpdateInventory,			&LLToolDragAndDrop::dad3dNULL));
 329	addEntry(DAD_LINK, 			new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,						&LLToolDragAndDrop::dad3dNULL));
 330	addEntry(DAD_MESH, 			new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory,			&LLToolDragAndDrop::dad3dMeshObject,				&LLToolDragAndDrop::dad3dNULL));
 331	// TODO: animation on self could play it?  edit it?
 332	// TODO: gesture on self could play it?  edit it?
 333};
 334
 335LLToolDragAndDrop::LLToolDragAndDrop()
 336:	 LLTool(std::string("draganddrop"), NULL),
 337	 mDragStartX(0),
 338	 mDragStartY(0),
 339	 mSource(SOURCE_AGENT),
 340	 mCursor(UI_CURSOR_NO),
 341	 mLastAccept(ACCEPT_NO),
 342	 mDrop(FALSE),
 343	 mCurItemIndex(0)
 344{
 345
 346}
 347
 348void LLToolDragAndDrop::setDragStart(S32 x, S32 y)
 349{
 350	mDragStartX = x;
 351	mDragStartY = y;
 352}
 353
 354BOOL LLToolDragAndDrop::isOverThreshold(S32 x,S32 y)
 355{
 356	static LLCachedControl<S32> drag_and_drop_threshold(gSavedSettings,"DragAndDropDistanceThreshold");
 357	
 358	S32 mouse_delta_x = x - mDragStartX;
 359	S32 mouse_delta_y = y - mDragStartY;
 360	
 361	return (mouse_delta_x * mouse_delta_x) + (mouse_delta_y * mouse_delta_y) > drag_and_drop_threshold * drag_and_drop_threshold;
 362}
 363
 364void LLToolDragAndDrop::beginDrag(EDragAndDropType type,
 365								  const LLUUID& cargo_id,
 366								  ESource source,
 367								  const LLUUID& source_id,
 368								  const LLUUID& object_id)
 369{
 370	if (type == DAD_NONE)
 371	{
 372		llwarns << "Attempted to start drag without a cargo type" << llendl;
 373		return;
 374	}
 375	mCargoTypes.clear();
 376	mCargoTypes.push_back(type);
 377	mCargoIDs.clear();
 378	mCargoIDs.push_back(cargo_id);
 379	mSource = source;
 380	mSourceID = source_id;
 381	mObjectID = object_id;
 382
 383	setMouseCapture( TRUE );
 384	LLToolMgr::getInstance()->setTransientTool( this );
 385	mCursor = UI_CURSOR_NO;
 386	if ((mCargoTypes[0] == DAD_CATEGORY)
 387	   && ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)))
 388	{
 389		LLInventoryCategory* cat = gInventory.getCategory(cargo_id);
 390		// go ahead and fire & forget the descendents if we are not
 391		// dragging a protected folder.
 392		if (cat)
 393		{
 394			LLViewerInventoryCategory::cat_array_t cats;
 395			LLViewerInventoryItem::item_array_t items;
 396			LLNoPreferredTypeOrItem is_not_preferred;
 397			uuid_vec_t folder_ids;
 398			uuid_vec_t item_ids;
 399			if (is_not_preferred(cat, NULL))
 400			{
 401				folder_ids.push_back(cargo_id);
 402			}
 403			gInventory.collectDescendentsIf(
 404				cargo_id,
 405				cats,
 406				items,
 407				LLInventoryModel::EXCLUDE_TRASH,
 408				is_not_preferred);
 409			S32 count = cats.count();
 410			S32 i;
 411			for(i = 0; i < count; ++i)
 412			{
 413				folder_ids.push_back(cats.get(i)->getUUID());
 414			}
 415			count = items.count();
 416			for(i = 0; i < count; ++i)
 417			{
 418				item_ids.push_back(items.get(i)->getUUID());
 419			}
 420			if (!folder_ids.empty() || !item_ids.empty())
 421			{
 422				LLCategoryFireAndForget *fetcher = new LLCategoryFireAndForget(folder_ids, item_ids);
 423				fetcher->startFetch();
 424				delete fetcher;
 425			}
 426		}
 427	}
 428}
 429
 430void LLToolDragAndDrop::beginMultiDrag(
 431	const std::vector<EDragAndDropType> types,
 432	const uuid_vec_t& cargo_ids,
 433	ESource source,
 434	const LLUUID& source_id)
 435{
 436	// assert on public api is evil
 437	//llassert( type != DAD_NONE );
 438
 439	std::vector<EDragAndDropType>::const_iterator types_it;
 440	for (types_it = types.begin(); types_it != types.end(); ++types_it)
 441	{
 442		if (DAD_NONE == *types_it)
 443		{
 444			llwarns << "Attempted to start drag without a cargo type" << llendl;
 445			return;
 446		}
 447	}
 448	mCargoTypes = types;
 449	mCargoIDs = cargo_ids;
 450	mSource = source;
 451	mSourceID = source_id;
 452
 453	setMouseCapture( TRUE );
 454	LLToolMgr::getInstance()->setTransientTool( this );
 455	mCursor = UI_CURSOR_NO;
 456	if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
 457	{
 458		// find categories (i.e. inventory folders) in the cargo.
 459		LLInventoryCategory* cat = NULL;
 460		S32 count = llmin(cargo_ids.size(), types.size());
 461		std::set<LLUUID> cat_ids;
 462		for(S32 i = 0; i < count; ++i)
 463		{
 464			cat = gInventory.getCategory(cargo_ids[i]);
 465			if (cat)
 466			{
 467				LLViewerInventoryCategory::cat_array_t cats;
 468				LLViewerInventoryItem::item_array_t items;
 469				LLNoPreferredType is_not_preferred;
 470				if (is_not_preferred(cat, NULL))
 471				{
 472					cat_ids.insert(cat->getUUID());
 473				}
 474				gInventory.collectDescendentsIf(
 475					cat->getUUID(),
 476					cats,
 477					items,
 478					LLInventoryModel::EXCLUDE_TRASH,
 479					is_not_preferred);
 480				S32 cat_count = cats.count();
 481				for(S32 i = 0; i < cat_count; ++i)
 482				{
 483					cat_ids.insert(cat->getUUID());
 484				}
 485			}
 486		}
 487		if (!cat_ids.empty())
 488		{
 489			uuid_vec_t folder_ids;
 490			uuid_vec_t item_ids;
 491			std::back_insert_iterator<uuid_vec_t> copier(folder_ids);
 492			std::copy(cat_ids.begin(), cat_ids.end(), copier);
 493			LLCategoryFireAndForget fetcher(folder_ids, item_ids);
 494		}
 495	}
 496}
 497
 498void LLToolDragAndDrop::endDrag()
 499{
 500	mEndDragSignal();
 501	LLSelectMgr::getInstance()->unhighlightAll();
 502	setMouseCapture(FALSE);
 503}
 504
 505void LLToolDragAndDrop::onMouseCaptureLost()
 506{
 507	// Called whenever the drag ends or if mouse capture is simply lost
 508	LLToolMgr::getInstance()->clearTransientTool();
 509	mCargoTypes.clear();
 510	mCargoIDs.clear();
 511	mSource = SOURCE_AGENT;
 512	mSourceID.setNull();
 513	mObjectID.setNull();
 514}
 515
 516BOOL LLToolDragAndDrop::handleMouseUp( S32 x, S32 y, MASK mask )
 517{
 518	if (hasMouseCapture())
 519	{
 520		EAcceptance acceptance = ACCEPT_NO;
 521		dragOrDrop( x, y, mask, TRUE, &acceptance );
 522		endDrag();
 523	}
 524	return TRUE;
 525}
 526
 527ECursorType LLToolDragAndDrop::acceptanceToCursor( EAcceptance acceptance )
 528{
 529	switch (acceptance)
 530	{
 531	case ACCEPT_YES_MULTI:
 532		if (mCargoIDs.size() > 1)
 533		{
 534			mCursor = UI_CURSOR_ARROWDRAGMULTI;
 535		}
 536		else
 537		{
 538			mCursor = UI_CURSOR_ARROWDRAG;
 539		}
 540		break;
 541	case ACCEPT_YES_SINGLE:
 542		if (mCargoIDs.size() > 1)
 543		{
 544			mToolTipMsg = LLTrans::getString("TooltipMustSingleDrop");
 545			mCursor = UI_CURSOR_NO;
 546		}
 547		else
 548		{
 549			mCursor = UI_CURSOR_ARROWDRAG;
 550		}
 551		break;
 552
 553	case ACCEPT_NO_LOCKED:
 554		mCursor = UI_CURSOR_NOLOCKED;
 555		break;
 556
 557	case ACCEPT_NO:
 558		mCursor = UI_CURSOR_NO;
 559		break;
 560
 561	case ACCEPT_YES_COPY_MULTI:
 562		if (mCargoIDs.size() > 1)
 563		{
 564			mCursor = UI_CURSOR_ARROWCOPYMULTI;
 565		}
 566		else
 567		{
 568			mCursor = UI_CURSOR_ARROWCOPY;
 569		}
 570		break;
 571	case ACCEPT_YES_COPY_SINGLE:
 572		if (mCargoIDs.size() > 1)
 573		{
 574			mToolTipMsg = LLTrans::getString("TooltipMustSingleDrop");
 575			mCursor = UI_CURSOR_NO;
 576		}
 577		else
 578		{
 579			mCursor = UI_CURSOR_ARROWCOPY;
 580		}
 581		break;
 582	case ACCEPT_POSTPONED:
 583		break;
 584	default:
 585		llassert( FALSE );
 586	}
 587
 588	return mCursor;
 589}
 590
 591BOOL LLToolDragAndDrop::handleHover( S32 x, S32 y, MASK mask )
 592{
 593	EAcceptance acceptance = ACCEPT_NO;
 594	dragOrDrop( x, y, mask, FALSE, &acceptance );
 595
 596	ECursorType cursor = acceptanceToCursor(acceptance);
 597	gViewerWindow->getWindow()->setCursor( cursor );
 598
 599	lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolDragAndDrop" << llendl;
 600	return TRUE;
 601}
 602
 603BOOL LLToolDragAndDrop::handleKey(KEY key, MASK mask)
 604{
 605	if (key == KEY_ESCAPE)
 606	{
 607		// cancel drag and drop operation
 608		endDrag();
 609		return TRUE;
 610	}
 611
 612	return FALSE;
 613}
 614
 615BOOL LLToolDragAndDrop::handleToolTip(S32 x, S32 y, MASK mask)
 616{
 617	if (!mToolTipMsg.empty())
 618	{
 619		LLToolTipMgr::instance().unblockToolTips();
 620		LLToolTipMgr::instance().show(LLToolTip::Params()
 621			.message(mToolTipMsg)
 622			.delay_time(gSavedSettings.getF32( "DragAndDropToolTipDelay" )));
 623		return TRUE;
 624	}
 625	return FALSE;
 626}
 627
 628void LLToolDragAndDrop::handleDeselect()
 629{
 630	mToolTipMsg.clear();
 631
 632	LLToolTipMgr::instance().blockToolTips();
 633}
 634
 635// protected
 636void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, 
 637								   EAcceptance* acceptance)
 638{
 639	*acceptance = ACCEPT_YES_MULTI;
 640
 641	BOOL handled = FALSE;
 642
 643	LLView* top_view = gFocusMgr.getTopCtrl();
 644	LLViewerInventoryItem* item;
 645	LLViewerInventoryCategory* cat;
 646
 647	mToolTipMsg.clear();
 648
 649	// Increment the operation id for every drop
 650	if (drop)
 651	{
 652		sOperationId++;
 653	}
 654
 655	if (top_view)
 656	{
 657		handled = TRUE;
 658
 659		for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
 660		{
 661			LLInventoryObject* cargo = locateInventory(item, cat);
 662
 663			if (cargo)
 664			{
 665				S32 local_x, local_y;
 666				top_view->screenPointToLocal( x, y, &local_x, &local_y );
 667				EAcceptance item_acceptance = ACCEPT_NO;
 668				handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE,
 669													mCargoTypes[mCurItemIndex],
 670													(void*)cargo,
 671													&item_acceptance,
 672													mToolTipMsg);
 673				if (handled)
 674				{
 675					// use sort order to determine priority of acceptance
 676					*acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
 677				}
 678			}
 679			else
 680			{
 681				return;		
 682			}
 683		}
 684
 685		// all objects passed, go ahead and perform drop if necessary
 686		if (handled && drop && (U32)*acceptance >= ACCEPT_YES_COPY_SINGLE)
 687		{
 688			if ((U32)*acceptance < ACCEPT_YES_COPY_MULTI &&
 689			    mCargoIDs.size() > 1)
 690			{
 691				// tried to give multi-cargo to a single-acceptor - refuse and return.
 692				*acceptance = ACCEPT_NO;
 693				return;
 694			}
 695
 696			for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
 697			{
 698				LLInventoryObject* cargo = locateInventory(item, cat);
 699
 700				if (cargo)
 701				{
 702					S32 local_x, local_y;
 703
 704					EAcceptance item_acceptance;
 705					top_view->screenPointToLocal( x, y, &local_x, &local_y );
 706					handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, TRUE,
 707														mCargoTypes[mCurItemIndex],
 708														(void*)cargo,
 709														&item_acceptance,
 710														mToolTipMsg);
 711				}
 712			}
 713		}
 714		if (handled)
 715		{
 716			mLastAccept = (EAcceptance)*acceptance;
 717		}
 718	}
 719
 720	if (!handled)
 721	{
 722		handled = TRUE;
 723
 724		LLRootView* root_view = gViewerWindow->getRootView();
 725
 726		for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
 727		{
 728			LLInventoryObject* cargo = locateInventory(item, cat);
 729
 730			// fix for EXT-3191
 731			if (NULL == cargo) return;
 732
 733			EAcceptance item_acceptance = ACCEPT_NO;
 734			handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE,
 735												mCargoTypes[mCurItemIndex],
 736												(void*)cargo,
 737												&item_acceptance,
 738												mToolTipMsg);
 739			if (handled)
 740			{
 741				// use sort order to determine priority of acceptance
 742				*acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
 743			}
 744		}
 745		// all objects passed, go ahead and perform drop if necessary
 746		if (handled && drop && (U32)*acceptance > ACCEPT_NO_LOCKED)
 747		{	
 748			if ((U32)*acceptance < ACCEPT_YES_COPY_MULTI &&
 749			    mCargoIDs.size() > 1)
 750			{
 751				// tried to give multi-cargo to a single-acceptor - refuse and return.
 752				*acceptance = ACCEPT_NO;
 753				return;
 754			}
 755
 756			for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
 757			{
 758				LLInventoryObject* cargo = locateInventory(item, cat);
 759
 760				if (cargo)
 761				{
 762					EAcceptance item_acceptance;
 763					handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE,
 764											  mCargoTypes[mCurItemIndex],
 765											  (void*)cargo,
 766											  &item_acceptance,
 767											  mToolTipMsg);
 768				}
 769			}
 770		}
 771
 772		if (handled)
 773		{
 774			mLastAccept = (EAcceptance)*acceptance;
 775		}
 776	}
 777
 778	if (!handled)
 779	{
 780		// Disallow drag and drop to 3D from the outbox
 781		const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false);
 782		if (outbox_id.notNull())
 783		{
 784			for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
 785			{
 786				if (gInventory.isObjectDescendentOf(mCargoIDs[item_index], outbox_id))
 787				{
 788					*acceptance = ACCEPT_NO;
 789					mToolTipMsg = LLTrans::getString("TooltipOutboxDragToWorld");
 790					return;
 791				}
 792			}
 793		}
 794		
 795		dragOrDrop3D( x, y, mask, drop, acceptance );
 796	}
 797}
 798
 799void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* acceptance )
 800{
 801	mDrop = drop;
 802	if (mDrop)
 803	{
 804		// don't allow drag and drop onto transparent objects
 805		pick(gViewerWindow->pickImmediate(x, y, FALSE));
 806	}
 807	else
 808	{
 809		// don't allow drag and drop onto transparent objects
 810		gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE);
 811	}
 812
 813	*acceptance = mLastAccept;
 814}
 815
 816void LLToolDragAndDrop::pickCallback(const LLPickInfo& pick_info)
 817{
 818	if (getInstance() != NULL)
 819	{
 820		getInstance()->pick(pick_info);
 821	}
 822}
 823
 824void LLToolDragAndDrop::pick(const LLPickInfo& pick_info)
 825{
 826	EDropTarget target = DT_NONE;
 827	S32	hit_face = -1;
 828
 829	LLViewerObject* hit_obj = pick_info.getObject();
 830	LLSelectMgr::getInstance()->unhighlightAll();
 831	bool highlight_object = false;
 832	// Treat attachments as part of the avatar they are attached to.
 833	if (hit_obj != NULL)
 834	{
 835		// don't allow drag and drop on grass, trees, etc.
 836		if (pick_info.mPickType == LLPickInfo::PICK_FLORA)
 837		{
 838			mCursor = UI_CURSOR_NO;
 839			gViewerWindow->getWindow()->setCursor( mCursor );
 840			return;
 841		}
 842
 843		if (hit_obj->isAttachment() && !hit_obj->isHUDAttachment())
 844		{
 845			LLVOAvatar* avatar = LLVOAvatar::findAvatarFromAttachment( hit_obj );
 846			if (!avatar)
 847			{
 848				mLastAccept = ACCEPT_NO;
 849				mCursor = UI_CURSOR_NO;
 850				gViewerWindow->getWindow()->setCursor( mCursor );
 851				return;
 852			}
 853			hit_obj = avatar;
 854		}
 855
 856		if (hit_obj->isAvatar())
 857		{
 858			if (((LLVOAvatar*) hit_obj)->isSelf())
 859			{
 860				target = DT_SELF;
 861				hit_face = -1;
 862			}
 863			else
 864			{
 865				target = DT_AVATAR;
 866				hit_face = -1;
 867			}
 868		}
 869		else
 870		{
 871			target = DT_OBJECT;
 872			hit_face = pick_info.mObjectFace;
 873			highlight_object = true;
 874		}
 875	}
 876	else if (pick_info.mPickType == LLPickInfo::PICK_LAND)
 877	{
 878		target = DT_LAND;
 879		hit_face = -1;
 880	}
 881
 882	mLastAccept = ACCEPT_YES_MULTI;
 883
 884	for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
 885	{
 886		const S32 item_index = mCurItemIndex;
 887		const EDragAndDropType dad_type = mCargoTypes[item_index];
 888		// Call the right implementation function
 889		mLastAccept = (EAcceptance)llmin(
 890			(U32)mLastAccept,
 891			(U32)callMemberFunction(*this, 
 892									LLDragAndDropDictionary::instance().get(dad_type, target))
 893				(hit_obj, hit_face, pick_info.mKeyMask, FALSE));
 894	}
 895
 896	if (mDrop && ((U32)mLastAccept >= ACCEPT_YES_COPY_SINGLE))
 897	{
 898		// if target allows multi-drop or there is only one item being dropped, go ahead
 899		if ((mLastAccept >= ACCEPT_YES_COPY_MULTI) || (mCargoIDs.size() == 1))
 900		{
 901			// Target accepts multi, or cargo is a single-drop
 902			for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
 903			{
 904				const S32 item_index = mCurItemIndex;
 905				const EDragAndDropType dad_type = mCargoTypes[item_index];
 906				// Call the right implementation function
 907				(U32)callMemberFunction(*this,
 908										LLDragAndDropDictionary::instance().get(dad_type, target))
 909					(hit_obj, hit_face, pick_info.mKeyMask, TRUE);
 910			}
 911		}
 912		else
 913		{
 914			// Target does not accept multi, but cargo is multi
 915			mLastAccept = ACCEPT_NO;
 916		}
 917	}
 918
 919	if (highlight_object && mLastAccept > ACCEPT_NO_LOCKED)
 920	{
 921		// if any item being dragged will be applied to the object under our cursor
 922		// highlight that object
 923		for (S32 i = 0; i < (S32)mCargoIDs.size(); i++)
 924		{
 925			if (mCargoTypes[i] != DAD_OBJECT || (pick_info.mKeyMask & MASK_CONTROL))
 926			{
 927				LLSelectMgr::getInstance()->highlightObjectAndFamily(hit_obj);
 928				break;
 929			}
 930		}
 931	}
 932	ECursorType cursor = acceptanceToCursor( mLastAccept );
 933	gViewerWindow->getWindow()->setCursor( cursor );
 934
 935	mLastHitPos = pick_info.mPosGlobal;
 936	mLastCameraPos = gAgentCamera.getCameraPositionGlobal();
 937}
 938
 939// static
 940BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
 941													 LLInventoryItem* item,
 942													 LLToolDragAndDrop::ESource source,
 943													 const LLUUID& src_id)
 944{
 945	// Always succeed if....
 946	// texture is from the library 
 947	// or already in the contents of the object
 948	if (SOURCE_LIBRARY == source)
 949	{
 950		// dropping a texture from the library always just works.
 951		return TRUE;
 952	}
 953
 954	// In case the inventory has not been updated (e.g. due to some recent operation
 955	// causing a dirty inventory), stall the user while fetching the inventory.
 956	if (hit_obj->isInventoryDirty())
 957	{
 958		hit_obj->fetchInventoryFromServer();
 959		LLSD args;
 960		args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again.";
 961		LLNotificationsUtil::add("ErrorMessage", args);
 962		return FALSE;
 963	}
 964	if (hit_obj->getInventoryItemByAsset(item->getAssetUUID()))
 965	{
 966		// if the asset is already in the object's inventory 
 967		// then it can always be added to a side.
 968		// This saves some work if the task's inventory is already loaded
 969		// and ensures that the texture item is only added once.
 970		return TRUE;
 971	}
 972
 973	if (!item) return FALSE;
 974	
 975	LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
 976	if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
 977	{
 978		// Check that we can add the texture as inventory to the object
 979		if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
 980		{
 981			return FALSE;
 982		}
 983		// make sure the object has the texture in it's inventory.
 984		if (SOURCE_AGENT == source)
 985		{
 986			// Remove the texture from local inventory. The server
 987			// will actually remove the item from agent inventory.
 988			gInventory.deleteObject(item->getUUID());
 989			gInventory.notifyObservers();
 990		}
 991		else if (SOURCE_WORLD == source)
 992		{
 993			// *FIX: if the objects are in different regions, and the
 994			// source region has crashed, you can bypass these
 995			// permissions.
 996			LLViewerObject* src_obj = gObjectList.findObject(src_id);
 997			if (src_obj)
 998			{
 999				src_obj->removeInventory(item->getUUID());
1000			}
1001			else
1002			{
1003				llwarns << "Unable to find source object." << llendl;
1004				return FALSE;
1005			}
1006		}
1007		// Add the texture item to the target object's inventory.
1008		hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
1009 		// TODO: Check to see if adding the item was successful; if not, then
1010		// we should return false here.
1011	}
1012	else if (!item->getPermissions().allowOperationBy(PERM_TRANSFER,
1013													 gAgent.getID()))
1014	{
1015		// Check that we can add the texture as inventory to the object
1016		if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
1017		{
1018			return FALSE;
1019		}
1020		// *FIX: may want to make sure agent can paint hit_obj.
1021
1022		// Add the texture item to the target object's inventory.
1023		hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
1024		// Force the object to update its refetch its inventory so it has this texture.
1025		hit_obj->fetchInventoryFromServer();
1026 		// TODO: Check to see if adding the item was successful; if not, then
1027		// we should return false here.
1028	}
1029	return TRUE;
1030}
1031
1032void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
1033											LLInventoryItem* item,
1034											LLToolDragAndDrop::ESource source,
1035											const LLUUID& src_id)
1036{
1037	if (!item)
1038	{
1039		llwarns << "LLToolDragAndDrop::dropTextureAllFaces no texture item." << llendl;
1040		return;
1041	}
1042	LLUUID asset_id = item->getAssetUUID();
1043	BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
1044	if (!success)
1045	{
1046		return;
1047	}
1048	LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id);
1049	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
1050	S32 num_faces = hit_obj->getNumTEs();
1051	for( S32 face = 0; face < num_faces; face++ )
1052	{
1053
1054		// update viewer side image in anticipation of update from simulator
1055		hit_obj->setTEImage(face, image);
1056		dialog_refresh_all();
1057	}
1058	// send the update to the simulator
1059	hit_obj->sendTEUpdate();
1060}
1061
1062void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
1063								 LLInventoryItem* item,
1064								 LLToolDragAndDrop::ESource source,
1065								 const LLUUID& src_id)
1066{
1067	if (!item)
1068	{
1069		llwarns << "no inventory item." << llendl;
1070		return;
1071	}
1072	LLUUID asset_id = item->getAssetUUID();
1073	BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
1074	if(!success)
1075	{
1076		return;
1077	}
1078
1079	LLSculptParams sculpt_params;
1080	sculpt_params.setSculptTexture(asset_id);
1081	sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
1082	hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
1083	
1084	dialog_refresh_all();
1085}
1086
1087/*
1088void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
1089{
1090	if (hit_face == -1) return;
1091	LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID());
1092	
1093	avatar->userSetOptionalTE( hit_face, image);
1094}
1095*/
1096
1097void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
1098										   S32 hit_face,
1099										   LLInventoryItem* item,
1100										   LLToolDragAndDrop::ESource source,
1101										   const LLUUID& src_id)
1102{
1103	if (hit_face == -1) return;
1104	if (!item)
1105	{
1106		llwarns << "LLToolDragAndDrop::dropTextureOneFace no texture item." << llendl;
1107		return;
1108	}
1109	LLUUID asset_id = item->getAssetUUID();
1110	BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
1111	if (!success)
1112	{
1113		return;
1114	}
1115	// update viewer side image in anticipation of update from simulator
1116	LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id);
1117	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
1118	hit_obj->setTEImage(hit_face, image);
1119	dialog_refresh_all();
1120
1121	// send the update to the simulator
1122	hit_obj->sendTEUpdate();
1123}
1124
1125
1126void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj,
1127								   LLInventoryItem* item,
1128								   BOOL active,
1129								   ESource source,
1130								   const LLUUID& src_id)
1131{
1132	// *HACK: In order to resolve SL-22177, we need to block drags
1133	// from notecards and objects onto other objects.
1134	if ((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource)
1135	   || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource))
1136	{
1137		llwarns << "Call to LLToolDragAndDrop::dropScript() from world"
1138			<< " or notecard." << llendl;
1139		return;
1140	}
1141	if (hit_obj && item)
1142	{
1143		LLPointer<LLViewerInventoryItem> new_script = new LLViewerInventoryItem(item);
1144		if (!item->getPermissions().allowCopyBy(gAgent.getID()))
1145		{
1146			if (SOURCE_AGENT == source)
1147			{
1148				// Remove the script from local inventory. The server
1149				// will actually remove the item from agent inventory.
1150				gInventory.deleteObject(item->getUUID());
1151				gInventory.notifyObservers();
1152			}
1153			else if (SOURCE_WORLD == source)
1154			{
1155				// *FIX: if the objects are in different regions, and
1156				// the source region has crashed, you can bypass
1157				// these permissions.
1158				LLViewerObject* src_obj = gObjectList.findObject(src_id);
1159				if (src_obj)
1160				{
1161					src_obj->removeInventory(item->getUUID());
1162				}
1163				else
1164				{
1165					llwarns << "Unable to find source object." << llendl;
1166					return;
1167				}
1168			}
1169		}
1170		hit_obj->saveScript(new_script, active, true);
1171		gFloaterTools->dirty();
1172
1173		// VEFFECT: SetScript
1174		LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1175		effectp->setSourceObject(gAgentAvatarp);
1176		effectp->setTargetObject(hit_obj);
1177		effectp->setDuration(LL_HUD_DUR_SHORT);
1178		effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1179	}
1180}
1181
1182void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
1183				   BOOL bypass_sim_raycast,
1184				   BOOL from_task_inventory,
1185				   BOOL remove_from_inventory)
1186{
1187	LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mLastHitPos);
1188	if (!regionp)
1189	{
1190		llwarns << "Couldn't find region to rez object" << llendl;
1191		return;
1192	}
1193
1194	//llinfos << "Rezzing object" << llendl;
1195	make_ui_sound("UISndObjectRezIn");
1196	LLViewerInventoryItem* item;
1197	LLViewerInventoryCategory* cat;
1198	locateInventory(item, cat);
1199	if (!item || !item->isFinished()) return;
1200	
1201	//if (regionp
1202	//	&& (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
1203	//{
1204	//	LLFirstUse::useSandbox();
1205	//}
1206	// check if it cannot be copied, and mark as remove if it is -
1207	// this will remove the object from inventory after rez. Only
1208	// bother with this check if we would not normally remove from
1209	// inventory.
1210	if (!remove_from_inventory
1211		&& !item->getPermissions().allowCopyBy(gAgent.getID()))
1212	{
1213		remove_from_inventory = TRUE;
1214	}
1215
1216	// Limit raycast to a single object.  
1217	// Speeds up server raycast + avoid problems with server ray
1218	// hitting objects that were clipped by the near plane or culled
1219	// on the viewer.
1220	LLUUID ray_target_id;
1221	if (raycast_target)
1222	{
1223		ray_target_id = raycast_target->getID();
1224	}
1225	else
1226	{
1227		ray_target_id.setNull();
1228	}
1229
1230	// Check if it's in the trash.
1231	bool is_in_trash = false;
1232	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
1233	if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
1234	{
1235		is_in_trash = true;
1236		remove_from_inventory = TRUE;
1237	}
1238
1239	LLUUID source_id = from_task_inventory ? mSourceID : LLUUID::null;
1240
1241	// Select the object only if we're editing.
1242	BOOL rez_selected = LLToolMgr::getInstance()->inEdit();
1243
1244
1245	LLVector3 ray_start = regionp->getPosRegionFromGlobal(mLastCameraPos);
1246	LLVector3 ray_end   = regionp->getPosRegionFromGlobal(mLastHitPos);
1247	// currently the ray's end point is an approximation,
1248	// and is sometimes too short (causing failure.)  so we
1249	// double the ray's length:
1250	if (bypass_sim_raycast == FALSE)
1251	{
1252		LLVector3 ray_direction = ray_start - ray_end;
1253		ray_end = ray_end - ray_direction;
1254	}
1255	
1256	
1257	// Message packing code should be it's own uninterrupted block
1258	LLMessageSystem* msg = gMessageSystem;
1259	if (mSource == SOURCE_NOTECARD)
1260	{
1261		msg->newMessageFast(_PREHASH_RezObjectFromNotecard);
1262	}
1263	else
1264	{
1265		msg->newMessageFast(_PREHASH_RezObject);
1266	}
1267	msg->nextBlockFast(_PREHASH_AgentData);
1268	msg->addUUIDFast(_PREHASH_AgentID,  gAgent.getID());
1269	msg->addUUIDFast(_PREHASH_SessionID,  gAgent.getSessionID());
1270	msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
1271
1272	msg->nextBlock("RezData");
1273	// if it's being rezzed from task inventory, we need to enable
1274	// saving it back into the task inventory.
1275	// *FIX: We can probably compress this to a single byte, since I
1276	// think folderid == mSourceID. This will be a later
1277	// optimization.
1278	msg->addUUIDFast(_PREHASH_FromTaskID, source_id);
1279	msg->addU8Fast(_PREHASH_BypassRaycast, (U8) bypass_sim_raycast);
1280	msg->addVector3Fast(_PREHASH_RayStart, ray_start);
1281	msg->addVector3Fast(_PREHASH_RayEnd, ray_end);
1282	msg->addUUIDFast(_PREHASH_RayTargetID, ray_target_id );
1283	msg->addBOOLFast(_PREHASH_RayEndIsIntersection, FALSE);
1284	msg->addBOOLFast(_PREHASH_RezSelected, rez_selected);
1285	msg->addBOOLFast(_PREHASH_RemoveItem, remove_from_inventory);
1286
1287	// deal with permissions slam logic
1288	pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
1289
1290	LLUUID folder_id = item->getParentUUID();
1291	if ((SOURCE_LIBRARY == mSource) || (is_in_trash))
1292	{
1293		// since it's coming from the library or trash, we want to not
1294		// 'take' it back to the same place.
1295		item->setParent(LLUUID::null);
1296		// *TODO this code isn't working - the parent (FolderID) is still
1297		// set when the object is "taken".  so code on the "take" side is
1298		// checking for trash and library as well (llviewermenu.cpp)
1299	}
1300	if (mSource == SOURCE_NOTECARD)
1301	{
1302		msg->nextBlockFast(_PREHASH_NotecardData);
1303		msg->addUUIDFast(_PREHASH_NotecardItemID, mSourceID);
1304		msg->addUUIDFast(_PREHASH_ObjectID, mObjectID);
1305		msg->nextBlockFast(_PREHASH_InventoryData);
1306		msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
1307	}
1308	else
1309	{
1310		msg->nextBlockFast(_PREHASH_InventoryData);
1311		item->packMessage(msg);
1312	}
1313	msg->sendReliable(regionp->getHost());
1314	// back out the change. no actual internal changes take place.
1315	item->setParent(folder_id); 
1316
1317	// If we're going to select it, get ready for the incoming
1318	// selected object.
1319	if (rez_selected)
1320	{
1321		LLSelectMgr::getInstance()->deselectAll();
1322		gViewerWindow->getWindow()->incBusyCount();
1323	}
1324
1325	if (remove_from_inventory)
1326	{
1327		// Delete it from inventory immediately so that users cannot
1328		// easily bypass copy protection in laggy situations. If the
1329		// rez fails, we will put it back on the server.
1330		gInventory.deleteObject(item->getUUID());
1331		gInventory.notifyObservers();
1332	}
1333
1334	// VEFFECT: DropObject
1335	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1336	effectp->setSourceObject(gAgentAvatarp);
1337	effectp->setPositionGlobal(mLastHitPos);
1338	effectp->setDuration(LL_HUD_DUR_SHORT);
1339	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1340
1341	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_REZ_COUNT);
1342}
1343
1344void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj,
1345									  LLInventoryItem* item,
1346									  LLToolDragAndDrop::ESource source,
1347									  const LLUUID& src_id)
1348{
1349	// *HACK: In order to resolve SL-22177, we need to block drags
1350	// from notecards and objects onto other objects.
1351	if ((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource)
1352	   || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource))
1353	{
1354		llwarns << "Call to LLToolDragAndDrop::dropInventory() from world"
1355			<< " or notecard." << llendl;
1356		return;
1357	}
1358
1359	LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
1360	time_t creation_date = time_corrected();
1361	new_item->setCreationDate(creation_date);
1362
1363	if (!item->getPermissions().allowCopyBy(gAgent.getID()))
1364	{
1365		if (SOURCE_AGENT == source)
1366		{
1367			// Remove the inventory item from local inventory. The
1368			// server will actually remove the item from agent
1369			// inventory.
1370			gInventory.deleteObject(item->getUUID());
1371			gInventory.notifyObservers();
1372		}
1373		else if (SOURCE_WORLD == source)
1374		{
1375			// *FIX: if the objects are in different regions, and the
1376			// source region has crashed, you can bypass these
1377			// permissions.
1378			LLViewerObject* src_obj = gObjectList.findObject(src_id);
1379			if (src_obj)
1380			{
1381				src_obj->removeInventory(item->getUUID());
1382			}
1383			else
1384			{
1385				llwarns << "Unable to find source object." << llendl;
1386				return;
1387			}
1388		}
1389	}
1390	hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
1391	if (LLFloaterReg::instanceVisible("build"))
1392	{
1393		// *FIX: only show this if panel not expanded?
1394		LLFloaterReg::showInstance("build", "Content");
1395	}
1396
1397	// VEFFECT: AddToInventory
1398	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1399	effectp->setSourceObject(gAgentAvatarp);
1400	effectp->setTargetObject(hit_obj);
1401	effectp->setDuration(LL_HUD_DUR_SHORT);
1402	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1403	gFloaterTools->dirty();
1404}
1405
1406// accessor that looks at permissions, copyability, and names of
1407// inventory items to determine if a drop would be ok.
1408EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item)
1409{
1410	// check the basics
1411	if (!item || !obj) return ACCEPT_NO;
1412	// HACK: downcast
1413	LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item;
1414	if (!vitem->isFinished()) return ACCEPT_NO;
1415	if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links
1416
1417	// deny attempts to drop from an object onto itself. This is to
1418	// help make sure that drops that are from an object to an object
1419	// don't have to worry about order of evaluation. Think of this
1420	// like check for self in assignment.
1421	if(obj->getID() == item->getParentUUID())
1422	{
1423		return ACCEPT_NO;
1424	}
1425	
1426	//BOOL copy = (perm.allowCopyBy(gAgent.getID(),
1427	//							  gAgent.getGroupID())
1428	//			 && (obj->mPermModify || obj->mFlagAllowInventoryAdd));
1429	BOOL worn = FALSE;
1430	LLVOAvatarSelf* my_avatar = NULL;
1431	switch(item->getType())
1432	{
1433	case LLAssetType::AT_OBJECT:
1434		my_avatar = gAgentAvatarp;
1435		if(my_avatar && my_avatar->isWearingAttachment(item->getUUID()))
1436		{
1437				worn = TRUE;
1438		}
1439		break;
1440	case LLAssetType::AT_BODYPART:
1441	case LLAssetType::AT_CLOTHING:
1442		if(gAgentWearables.isWearingItem(item->getUUID()))
1443		{
1444			worn = TRUE;
1445		}
1446		break;
1447	case LLAssetType::AT_CALLINGCARD:
1448		// Calling Cards in object are disabled for now
1449		// because of incomplete LSL support. See STORM-1117.
1450		return ACCEPT_NO;
1451	default:
1452			break;
1453	}
1454	const LLPermissions& perm = item->getPermissions();
1455	BOOL modify = (obj->permModify() || obj->flagAllowInventoryAdd());
1456	BOOL transfer = FALSE;
1457	if((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
1458	   || perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
1459	{
1460		transfer = TRUE;
1461	}
1462	BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
1463	BOOL attached = obj->isAttachment();
1464	BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
1465	if(attached && !unrestricted)
1466	{
1467		return ACCEPT_NO_LOCKED;
1468	}
1469	else if(modify && transfer && volume && !worn)
1470	{
1471		return ACCEPT_YES_MULTI;
1472	}
1473	else if(!modify)
1474	{
1475		return ACCEPT_NO_LOCKED;
1476	}
1477	return ACCEPT_NO;
1478}
1479
1480
1481static void give_inventory_cb(const LLSD& notification, const LLSD& response)
1482{
1483	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
1484	// if Cancel pressed
1485	if (option == 1)
1486	{
1487		return;
1488	}
1489
1490	LLSD payload = notification["payload"];
1491	const LLUUID& session_id = payload["session_id"];
1492	const LLUUID& agent_id = payload["agent_id"];
1493	LLViewerInventoryItem * inv_item =  gInventory.getItem(payload["item_id"]);
1494	if (NULL == inv_item)
1495	{
1496		llassert(NULL != inv_item);
1497		return;
1498	}
1499
1500	if (LLGiveInventory::doGiveInventoryItem(agent_id, inv_item, session_id))
1501	{
1502		if ("avatarpicker" == payload["d&d_dest"].asString())
1503		{
1504			LLFloaterReg::hideInstance("avatar_picker");
1505		}
1506		LLNotificationsUtil::add("ItemsShared");
1507	}
1508}
1509
1510static void show_item_sharing_confirmation(const std::string name,
1511					   LLViewerInventoryItem* inv_item,
1512					   const LLSD& dest,
1513					   const LLUUID& dest_agent,
1514					   const LLUUID& session_id = LLUUID::null)
1515{
1516	if (!inv_item)
1517	{
1518		llassert(NULL != inv_item);
1519		return;
1520	}
1521
1522	LLSD substitutions;
1523	substitutions["RESIDENTS"] = name;
1524	substitutions["ITEMS"] = inv_item->getName();
1525	LLSD payload;
1526	payload["agent_id"] = dest_agent;
1527	payload["item_id"] = inv_item->getUUID();
1528	payload["session_id"] = session_id;
1529	payload["d&d_dest"] = dest.asString();
1530	LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, payload, &give_inventory_cb);
1531}
1532
1533static void get_name_cb(const LLUUID& id,
1534						const std::string& full_name,
1535						LLViewerInventoryItem* inv_item,
1536						const LLSD& dest,
1537						const LLUUID& dest_agent)
1538{
1539	show_item_sharing_confirmation(full_name,
1540								   inv_item,
1541								   dest,
1542								   id,
1543								   LLUUID::null);
1544}
1545
1546// function used as drag-and-drop handler for simple agent give inventory requests
1547//static
1548bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_id, BOOL drop,
1549											  EDragAndDropType cargo_type,
1550											  void* cargo_data,
1551											  EAcceptance* accept,
1552											  const LLSD& dest)
1553{
1554	// check the type
1555	switch(cargo_type)
1556	{
1557	case DAD_TEXTURE:
1558	case DAD_SOUND:
1559	case DAD_LANDMARK:
1560	case DAD_SCRIPT:
1561	case DAD_OBJECT:
1562	case DAD_NOTECARD:
1563	case DAD_CLOTHING:
1564	case DAD_BODYPART:
1565	case DAD_ANIMATION:
1566	case DAD_GESTURE:
1567	case DAD_CALLINGCARD:
1568	case DAD_MESH:
1569	{
1570		LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
1571		if(gInventory.getItem(inv_item->getUUID())
1572			&& LLGiveInventory::isInventoryGiveAcceptable(inv_item))
1573		{
1574			// *TODO: get multiple object transfers working
1575			*accept = ACCEPT_YES_COPY_SINGLE;
1576			if(drop)
1577			{
1578				LLIMModel::LLIMSession * session = LLIMModel::instance().findIMSession(session_id);
1579
1580				// If no IM session found get the destination agent's name by id.
1581				if (NULL == session)
1582				{
1583					std::string fullname;
1584
1585					// If destination agent's name is found in cash proceed to showing the confirmation dialog.
1586					// Otherwise set up a callback to show the dialog when the name arrives.
1587					if (gCacheName->getFullName(dest_agent, fullname))
1588					{
1589						show_item_sharing_confirmation(fullname, inv_item, dest, dest_agent, LLUUID::null);
1590					}
1591					else
1592					{
1593						gCacheName->get(dest_agent, false, boost::bind(&get_name_cb, _1, _2, inv_item, dest, dest_agent));
1594					}
1595
1596					return true;
1597				}
1598
1599				// If an IM session with destination agent is found item offer will be logged in this session.
1600				show_item_sharing_confirmation(session->mName, inv_item, dest, dest_agent, session_id);
1601			}
1602		}
1603		else
1604		{
1605			// It's not in the user's inventory (it's probably
1606			// in an object's contents), so disallow dragging
1607			// it here.  You can't give something you don't
1608			// yet have.
1609			*accept = ACCEPT_NO;
1610		}
1611		break;
1612	}
1613	case DAD_CATEGORY:
1614	{
1615		LLViewerInventoryCategory* inv_cat = (LLViewerInventoryCategory*)cargo_data;
1616		if( gInventory.getCategory( inv_cat->getUUID() ) )
1617		{
1618			// *TODO: get multiple object transfers working
1619			*accept = ACCEPT_YES_COPY_SINGLE;
1620			if(drop)
1621			{
1622				LLGiveInventory::doGiveInventoryCategory(dest_agent, inv_cat, session_id);
1623			}
1624		}
1625		else
1626		{
1627			// It's not in the user's inventory (it's probably
1628			// in an object's contents), so disallow dragging
1629			// it here.  You can't give something you don't
1630			// yet have.
1631			*accept = ACCEPT_NO;
1632		}
1633		break;
1634	}
1635	default:
1636		*accept = ACCEPT_NO;
1637		break;
1638	}
1639
1640	return TRUE;
1641}
1642
1643
1644
1645///
1646/// Methods called in the drag & drop array
1647///
1648
1649EAcceptance LLToolDragAndDrop::dad3dNULL(
1650	LLViewerObject*, S32, MASK, BOOL)
1651{
1652	lldebugs << "LLToolDragAndDrop::dad3dNULL()" << llendl;
1653	return ACCEPT_NO;
1654}
1655
1656EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
1657	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1658{
1659	lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl;
1660	// must be in the user's inventory
1661	if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
1662	{
1663		return ACCEPT_NO;
1664	}
1665
1666	LLViewerInventoryItem* item;
1667	LLViewerInventoryCategory* cat;
1668	locateInventory(item, cat);
1669	if (!item || !item->isFinished()) return ACCEPT_NO;
1670
1671	// must not be in the trash
1672	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
1673	if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
1674	{
1675		return ACCEPT_NO;
1676	}
1677
1678	// must not be already wearing it
1679	LLVOAvatarSelf* avatar = gAgentAvatarp;
1680	if( !avatar || avatar->isWearingAttachment(item->getUUID()) )
1681	{
1682		return ACCEPT_NO;
1683	}
1684
1685	const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
1686	if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id))
1687	{
1688		return ACCEPT_NO;
1689	}
1690
1691
1692	if( drop )
1693	{
1694		if(mSource == SOURCE_LIBRARY)
1695		{
1696			LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
1697			copy_inventory_item(
1698				gAgent.getID(),
1699				item->getPermissions().getOwner(),
1700				item->getUUID(),
1701				LLUUID::null,
1702				std::string(),
1703				cb);
1704		}
1705		else
1706		{
1707			rez_attachment(item, 0);
1708		}
1709	}
1710	return ACCEPT_YES_SINGLE;
1711}
1712
1713
1714EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
1715	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1716{
1717	if (mSource == SOURCE_WORLD)
1718	{
1719		return dad3dRezFromObjectOnLand(obj, face, mask, drop);
1720	}
1721
1722	lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnLand()" << llendl;
1723	LLViewerInventoryItem* item;
1724	LLViewerInventoryCategory* cat;
1725	locateInventory(item, cat);
1726	if (!item || !item->isFinished()) return ACCEPT_NO;
1727
1728	LLVOAvatarSelf* my_avatar = gAgentAvatarp;
1729	if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
1730	{
1731		return ACCEPT_NO;
1732	}
1733
1734	EAcceptance accept;
1735	BOOL remove_inventory;
1736
1737	// Get initial settings based on shift key
1738	if (mask & MASK_SHIFT)
1739	{
1740		// For now, always make copy
1741		//accept = ACCEPT_YES_SINGLE;
1742		//remove_inventory = TRUE;
1743		accept = ACCEPT_YES_COPY_SINGLE;
1744		remove_inventory = FALSE;
1745	}
1746	else
1747	{
1748		accept = ACCEPT_YES_COPY_SINGLE;
1749		remove_inventory = FALSE;
1750	}
1751
1752	// check if the item can be copied. If not, send that to the sim
1753	// which will remove the inventory item.
1754	if(!item->getPermissions().allowCopyBy(gAgent.getID()))
1755	{
1756		accept = ACCEPT_YES_SINGLE;
1757		remove_inventory = TRUE;
1758	}
1759
1760	// Check if it's in the trash.
1761	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
1762	if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
1763	{
1764		accept = ACCEPT_YES_SINGLE;
1765		remove_inventory = TRUE;
1766	}
1767
1768	if(drop)
1769	{
1770		dropObject(obj, TRUE, FALSE, remove_inventory);
1771	}
1772
1773	return accept;
1774}
1775
1776EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
1777	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1778{
1779	// handle objects coming from object inventory
1780	if (mSource == SOURCE_WORLD)
1781	{
1782		return dad3dRezFromObjectOnObject(obj, face, mask, drop);
1783	}
1784
1785	lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnObject()" << llendl;
1786	LLViewerInventoryItem* item;
1787	LLViewerInventoryCategory* cat;
1788	locateInventory(item, cat);
1789	if (!item || !item->isFinished()) return ACCEPT_NO;
1790	LLVOAvatarSelf* my_avatar = gAgentAvatarp;
1791	if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
1792	{
1793		return ACCEPT_NO;
1794	}
1795
1796	if((mask & MASK_CONTROL))
1797	{
1798		// *HACK: In order to resolve SL-22177, we need to block drags
1799		// from notecards and objects onto other objects.
1800		if(mSource == SOURCE_NOTECARD)
1801		{
1802			return ACCEPT_NO;
1803		}
1804
1805		EAcceptance rv = willObjectAcceptInventory(obj, item);
1806		if(drop && (ACCEPT_YES_SINGLE <= rv))
1807		{
1808			dropInventory(obj, item, mSource, mSourceID);
1809		}
1810		return rv;
1811	}
1812	
1813	EAcceptance accept;
1814	BOOL remove_inventory;
1815
1816	if (mask & MASK_SHIFT)
1817	{
1818		// For now, always make copy
1819		//accept = ACCEPT_YES_SINGLE;
1820		//remove_inventory = TRUE;
1821		accept = ACCEPT_YES_COPY_SINGLE;
1822		remove_inventory = FALSE;
1823	}
1824	else
1825	{
1826		accept = ACCEPT_YES_COPY_SINGLE;
1827		remove_inventory = FALSE;
1828	}
1829	
1830	// check if the item can be copied. If not, send that to the sim
1831	// which will remove the inventory item.
1832	if(!item->getPermissions().allowCopyBy(gAgent.getID()))
1833	{
1834		accept = ACCEPT_YES_SINGLE;
1835		remove_inventory = TRUE;
1836	}
1837
1838	// Check if it's in the trash.
1839	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
1840	if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
1841	{
1842		accept = ACCEPT_YES_SINGLE;
1843		remove_inventory = TRUE;
1844	}
1845
1846	if(drop)
1847	{
1848		dropObject(obj, FALSE, FALSE, remove_inventory);
1849	}
1850
1851	return accept;
1852}
1853
1854EAcceptance LLToolDragAndDrop::dad3dRezScript(
1855	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1856{
1857	lldebugs << "LLToolDragAndDrop::dad3dRezScript()" << llendl;
1858
1859	// *HACK: In order to resolve SL-22177, we need to block drags
1860	// from notecards and objects onto other objects.
1861	if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
1862	{
1863		return ACCEPT_NO;
1864	}
1865
1866	LLViewerInventoryItem* item;
1867	LLViewerInventoryCategory* cat;
1868	locateInventory(item, cat);
1869	if (!item || !item->isFinished()) return ACCEPT_NO;
1870	EAcceptance rv = willObjectAcceptInventory(obj, item);
1871	if(drop && (ACCEPT_YES_SINGLE <= rv))
1872	{
1873		// rez in the script active by default, rez in inactive if the
1874		// control key is being held down.
1875		BOOL active = ((mask & MASK_CONTROL) == 0);
1876	
1877		LLViewerObject* root_object = obj;
1878		if (obj && obj->getParent())
1879		{
1880			LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
1881			if (!parent_obj->isAvatar())
1882			{
1883				root_object = parent_obj;
1884			}
1885		}
1886
1887		dropScript(root_object, item, active, mSource, mSourceID);
1888	}	
1889	return rv;
1890}
1891
1892EAcceptance LLToolDragAndDrop::dad3dApplyToObject(
1893	LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type)
1894{
1895	lldebugs << "LLToolDragAndDrop::dad3dApplyToObject()" << llendl;
1896
1897	// *HACK: In order to resolve SL-22177, we need to block drags
1898	// from notecards and objects onto other objects.
1899	if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
1900	{
1901		return ACCEPT_NO;
1902	}
1903	
1904	LLViewerInventoryItem* item;
1905	LLViewerInventoryCategory* cat;
1906	locateInventory(item, cat);
1907	if (!item || !item->isFinished()) return ACCEPT_NO;
1908	EAcceptance rv = willObjectAcceptInventory(obj, item);
1909	if((mask & MASK_CONTROL))
1910	{
1911		if((ACCEPT_YES_SINGLE <= rv) && drop)
1912		{
1913			dropInventory(obj, item, mSource, mSourceID);
1914		}
1915		return rv;
1916	}
1917	if(!obj->permModify())
1918	{
1919		return ACCEPT_NO_LOCKED;
1920	}
1921	//If texture !copyable don't texture or you'll never get it back.
1922	if(!item->getPermissions().allowCopyBy(gAgent.getID()))
1923	{
1924		return ACCEPT_NO;
1925	}
1926
1927	if(drop && (ACCEPT_YES_SINGLE <= rv))
1928	{
1929		if (cargo_type == DAD_TEXTURE)
1930		{
1931			if((mask & MASK_SHIFT))
1932			{
1933				dropTextureAllFaces(obj, item, mSource, mSourceID);
1934			}
1935			else
1936			{
1937				dropTextureOneFace(obj, face, item, mSource, mSourceID);
1938			}
1939		}
1940		else if (cargo_type == DAD_MESH)
1941		{
1942			dropMesh(obj, item, mSource, mSourceID);
1943		}
1944		else
1945		{
1946			llwarns << "unsupported asset type" << llendl;
1947		}
1948		
1949		// VEFFECT: SetTexture
1950		LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1951		effectp->setSourceObject(gAgentAvatarp);
1952		effectp->setTargetObject(obj);
1953		effectp->setDuration(LL_HUD_DUR_SHORT);
1954		effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1955	}
1956
1957	// enable multi-drop, although last texture will win
1958	return ACCEPT_YES_MULTI;
1959}
1960
1961
1962EAcceptance LLToolDragAndDrop::dad3dTextureObject(
1963	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1964{
1965	return dad3dApplyToObject(obj, face, mask, drop, DAD_TEXTURE);
1966}
1967
1968EAcceptance LLToolDragAndDrop::dad3dMeshObject(
1969	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1970{
1971	return dad3dApplyToObject(obj, face, mask, drop, DAD_MESH);
1972}
1973
1974
1975/*
1976EAcceptance LLToolDragAndDrop::dad3dTextureSelf(
1977	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1978{
1979	lldebugs << "LLToolDragAndDrop::dad3dTextureAvatar()" << llendl;
1980	if(drop)
1981	{
1982		if( !(mask & MASK_SHIFT) )
1983		{
1984			dropTextureOneFaceAvatar( (LLVOAvatar*)obj, face, (LLInventoryItem*)mCargoData);
1985		}
1986	}
1987	return (mask & MASK_SHIFT) ? ACCEPT_NO : ACCEPT_YES_SINGLE;
1988}
1989*/
1990
1991EAcceptance LLToolDragAndDrop::dad3dWearItem(
1992	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
1993{
1994	lldebugs << "LLToolDragAndDrop::dad3dWearItem()" << llendl;
1995	LLViewerInventoryItem* item;
1996	LLViewerInventoryCategory* cat;
1997	locateInventory(item, cat);
1998	if (!item || !item->isFinished()) return ACCEPT_NO;
1999
2000	if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
2001	{
2002		// it's in the agent inventory
2003		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
2004		if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
2005		{
2006			return ACCEPT_NO;
2007		}
2008
2009		if( drop )
2010		{
2011			// TODO: investigate wearables may not be loaded at this point EXT-8231
2012
2013			LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(),true, !(mask & MASK_CONTROL));
2014		}
2015		return ACCEPT_YES_MULTI;
2016	}
2017	else
2018	{
2019		// TODO: copy/move item to avatar's inventory and then wear it.
2020		return ACCEPT_NO;
2021	}
2022}
2023
2024EAcceptance LLToolDragAndDrop::dad3dActivateGesture(
2025	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2026{
2027	lldebugs << "LLToolDragAndDrop::dad3dActivateGesture()" << llendl;
2028	LLViewerInventoryItem* item;
2029	LLViewerInventoryCategory* cat;
2030	locateInventory(item, cat);
2031	if (!item || !item->isFinished()) return ACCEPT_NO;
2032
2033	if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
2034	{
2035		// it's in the agent inventory
2036		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
2037		if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
2038		{
2039			return ACCEPT_NO;
2040		}
2041
2042		if( drop )
2043		{
2044			LLUUID item_id;
2045			if(mSource == SOURCE_LIBRARY)
2046			{
2047				// create item based on that one, and put it on if that
2048				// was a success.
2049				LLPointer<LLInventoryCallback> cb = new ActivateGestureCallback();
2050				copy_inventory_item(
2051					gAgent.getID(),
2052					item->getPermissions().getOwner(),
2053					item->getUUID(),
2054					LLUUID::null,
2055					std::string(),
2056					cb);
2057			}
2058			else
2059			{
2060				LLGestureMgr::instance().activateGesture(item->getUUID());
2061				gInventory.updateItem(item);
2062				gInventory.notifyObservers();
2063			}
2064		}
2065		return ACCEPT_YES_MULTI;
2066	}
2067	else
2068	{
2069		return ACCEPT_NO;
2070	}
2071}
2072
2073EAcceptance LLToolDragAndDrop::dad3dWearCategory(
2074	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2075{
2076	lldebugs << "LLToolDragAndDrop::dad3dWearCategory()" << llendl;
2077	LLViewerInventoryItem* item;
2078	LLViewerInventoryCategory* category;
2079	locateInventory(item, category);
2080	if(!category) return ACCEPT_NO;
2081
2082	if (drop)
2083	{
2084		// TODO: investigate wearables may not be loaded at this point EXT-8231
2085	}
2086
2087	if(mSource == SOURCE_AGENT)
2088	{
2089		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
2090		if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) )
2091		{
2092			return ACCEPT_NO;
2093		}
2094
2095		const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
2096		if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id))
2097		{
2098			return ACCEPT_NO;
2099		}
2100
2101		if(drop)
2102		{
2103			BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
2104			LLAppearanceMgr::instance().wearInventoryCategory(category, false, append);
2105		}
2106		return ACCEPT_YES_MULTI;
2107	}
2108	else if(mSource == SOURCE_LIBRARY)
2109	{
2110		if(drop)
2111		{
2112			LLAppearanceMgr::instance().wearInventoryCategory(category, true, false);
2113		}
2114		return ACCEPT_YES_MULTI;
2115	}
2116	else
2117	{
2118		// TODO: copy/move category to avatar's inventory and then wear it.
2119		return ACCEPT_NO;
2120	}
2121}
2122
2123
2124EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
2125	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2126{
2127	lldebugs << "LLToolDragAndDrop::dadUpdateInventory()" << llendl;
2128
2129	// *HACK: In order to resolve SL-22177, we need to block drags
2130	// from notecards and objects onto other objects.
2131	if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
2132	{
2133		return ACCEPT_NO;
2134	}
2135
2136	LLViewerInventoryItem* item;
2137	LLViewerInventoryCategory* cat;
2138	locateInventory(item, cat);
2139	if (!item || !item->isFinished()) return ACCEPT_NO;
2140	LLViewerObject* root_object = obj;
2141	if (obj && obj->getParent())
2142	{
2143		LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
2144		if (!parent_obj->isAvatar())
2145		{
2146			root_object = parent_obj;
2147		}
2148	}
2149
2150	EAcceptance rv = willObjectAcceptInventory(root_object, item);
2151	if(root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv))
2152	{
2153		dropInventory(root_object, item, mSource, mSourceID);
2154	}
2155	return rv;
2156}
2157
2158BOOL LLToolDragAndDrop::dadUpdateInventory(LLViewerObject* obj, BOOL drop)
2159{
2160	EAcceptance rv = dad3dUpdateInventory(obj, -1, MASK_NONE, drop);
2161	return (rv >= ACCEPT_YES_COPY_SINGLE);
2162}
2163
2164EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
2165	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2166{
2167	lldebugs << "LLToolDragAndDrop::dad3dUpdateInventoryCategory()" << llendl;
2168	if (obj == NULL)
2169	{
2170		llwarns << "obj is NULL; aborting func with ACCEPT_NO" << llendl;
2171		return ACCEPT_NO;
2172	}
2173
2174	if ((mSource != SOURCE_AGENT) && (mSource != SOURCE_LIBRARY))
2175	{
2176		return ACCEPT_NO;
2177	}
2178	if (obj->isAttachment())
2179	{
2180		return ACCEPT_NO_LOCKED;
2181	}
2182
2183	LLViewerInventoryItem* item = NULL;
2184	LLViewerInventoryCategory* cat = NULL;
2185	locateInventory(item, cat);
2186	if (!cat) 
2187	{
2188		return ACCEPT_NO;
2189	}
2190
2191	// Find all the items in the category
2192	LLDroppableItem droppable(!obj->permYouOwner());
2193	LLInventoryModel::cat_array_t cats;
2194	LLInventoryModel::item_array_t items;
2195	gInventory.collectDescendentsIf(cat->getUUID(),
2196					cats,
2197					items,
2198					LLInventoryModel::EXCLUDE_TRASH,
2199					droppable);
2200	cats.put(cat);
2201 	if (droppable.countNoCopy() > 0)
2202 	{
2203 		llwarns << "*** Need to confirm this step" << llendl;
2204 	}
2205	LLViewerObject* root_object = obj;
2206	if (obj->getParent())
2207	{
2208		LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
2209		if (!parent_obj->isAvatar())
2210		{
2211			root_object = parent_obj;
2212		}
2213	}
2214
2215	EAcceptance rv = ACCEPT_NO;
2216
2217	// Check for accept
2218	for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin();
2219		 cat_iter != cats.end();
2220		 ++cat_iter)
2221	{
2222		const LLViewerInventoryCategory *cat = (*cat_iter);
2223		rv = gInventory.isCategoryComplete(cat->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO;
2224		if(rv < ACCEPT_YES_SINGLE)
2225		{
2226			lldebugs << "Category " << cat->getUUID() << "is not complete." << llendl;
2227			break;
2228		}
2229	}
2230	if (ACCEPT_YES_COPY_SINGLE <= rv)
2231	{
2232		for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin();
2233			 item_iter != items.end();
2234			 ++item_iter)
2235		{
2236			LLViewerInventoryItem *item = (*item_iter);
2237			/*
2238			// Pass the base objects, not the links.
2239			if (item && item->getIsLinkType())
2240			{
2241				item = item->getLinkedItem();
2242				(*item_iter) = item;
2243			}
2244			*/
2245			rv = willObjectAcceptInventory(root_object, item);
2246			if (rv < ACCEPT_YES_COPY_SINGLE)
2247			{
2248				lldebugs << "Object will not accept " << item->getUUID() << llendl;
2249				break;
2250			}
2251		}
2252	}
2253
2254	// If every item is accepted, send it on
2255	if (drop && (ACCEPT_YES_COPY_SINGLE <= rv))
2256	{
2257		uuid_vec_t ids;
2258		for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin();
2259			 item_iter != items.end();
2260			 ++item_iter)
2261		{
2262			const LLViewerInventoryItem *item = (*item_iter);
2263			ids.push_back(item->getUUID());
2264		}
2265		LLCategoryDropObserver* dropper = new LLCategoryDropObserver(ids, obj->getID(), mSource);
2266		dropper->startFetch();
2267		if (dropper->isFinished())
2268		{
2269			dropper->done();
2270		}
2271		else
2272		{
2273			gInventory.addObserver(dropper);
2274		}
2275	}
2276	return rv;
2277}
2278
2279BOOL LLToolDragAndDrop::dadUpdateInventoryCategory(LLViewerObject* obj,
2280												   BOOL drop)
2281{
2282	EAcceptance rv = dad3dUpdateInventoryCategory(obj, -1, MASK_NONE, drop);
2283	return (rv >= ACCEPT_YES_COPY_SINGLE);
2284}
2285
2286EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject(
2287	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2288{
2289	lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << llendl;
2290
2291	// item has to be in agent inventory.
2292	if(mSource != SOURCE_AGENT) return ACCEPT_NO;
2293
2294	// find the item now.
2295	LLViewerInventoryItem* item;
2296	LLViewerInventoryCategory* cat;
2297	locateInventory(item, cat);
2298	if (!item || !item->isFinished()) return ACCEPT_NO;
2299	if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
2300	{
2301		// cannot give away no-transfer objects
2302		return ACCEPT_NO;
2303	}
2304	LLVOAvatarSelf* avatar = gAgentAvatarp;
2305	if(avatar && avatar->isWearingAttachment( item->getUUID() ) )
2306	{
2307		// You can't give objects that are attached to you
2308		return ACCEPT_NO;
2309	}
2310	if( obj && avatar )
2311	{
2312		if(drop)
2313		{
2314			LLGiveInventory::doGiveInventoryItem(obj->getID(), item );
2315		}
2316		// *TODO: deal with all the issues surrounding multi-object
2317		// inventory transfers.
2318		return ACCEPT_YES_SINGLE;
2319	}
2320	return ACCEPT_NO;
2321}
2322
2323
2324EAcceptance LLToolDragAndDrop::dad3dGiveInventory(
2325	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2326{
2327	lldebugs << "LLToolDragAndDrop::dad3dGiveInventory()" << llendl;
2328	// item has to be in agent inventory.
2329	if(mSource != SOURCE_AGENT) return ACCEPT_NO;
2330	LLViewerInventoryItem* item;
2331	LLViewerInventoryCategory* cat;
2332	locateInventory(