aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lltooldraganddrop.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/lltooldraganddrop.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/lltooldraganddrop.cpp')
-rw-r--r--linden/indra/newview/lltooldraganddrop.cpp2991
1 files changed, 2991 insertions, 0 deletions
diff --git a/linden/indra/newview/lltooldraganddrop.cpp b/linden/indra/newview/lltooldraganddrop.cpp
new file mode 100644
index 0000000..398263f
--- /dev/null
+++ b/linden/indra/newview/lltooldraganddrop.cpp
@@ -0,0 +1,2991 @@
1/**
2 * @file lltooldraganddrop.cpp
3 * @brief LLToolDragAndDrop class implementation
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "message.h"
31#include "lltooldraganddrop.h"
32
33#include "llinstantmessage.h"
34#include "lldir.h"
35
36#include "llagent.h"
37#include "llviewercontrol.h"
38#include "llfirstuse.h"
39#include "llfloater.h"
40#include "llfloatertools.h"
41#include "llgesturemgr.h"
42#include "llhudeffecttrail.h"
43#include "llhudmanager.h"
44#include "llinventorymodel.h"
45#include "llinventoryview.h"
46#include "llnotify.h"
47#include "llpreviewnotecard.h"
48#include "llselectmgr.h"
49#include "lltoolmgr.h"
50#include "llui.h"
51#include "llviewerimagelist.h"
52#include "llviewerinventory.h"
53#include "llviewerobject.h"
54#include "llviewerobjectlist.h"
55#include "llviewerregion.h"
56#include "llviewerstats.h"
57#include "llviewerwindow.h"
58#include "llvoavatar.h"
59#include "llvolume.h"
60#include "llworld.h"
61#include "object_flags.h"
62#include "viewer.h"
63
64LLToolDragAndDrop *gToolDragAndDrop = NULL;
65
66// MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
67// or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
68// bit from there to give some pad.
69const S32 MAX_ITEMS = 42;
70const char* FOLDER_INCLUDES_ATTACHMENTS_BEING_WORN =
71 "Cannot give folders that contain objects that are attached to you.\n"
72 "Detach the object(s) and then try again.";
73
74
75// syntactic sugar
76#define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
77
78/*
79const LLUUID MULTI_CONTAINER_TEXTURE("b2181ea2-1937-2ee1-78b8-bf05c43536b7");
80LLUUID CONTAINER_TEXTURES[LLAssetType::AT_COUNT];
81
82const char* CONTAINER_TEXTURE_NAMES[LLAssetType::AT_COUNT] =
83{
84 "container_texture.tga",
85 "container_sound.tga",
86 "container_many_things.tga",
87 "container_landmark.tga",
88 "container_script.tga",
89 "container_clothing.tga",
90 "container_object.tga",
91 "container_many_things.tga",
92 "container_many_things.tga",
93 "container_many_things.tga",
94 "container_script.tga",
95 "container_script.tga",
96 "container_texture.tga",
97 "container_bodypart.tga",
98 "container_many_things.tga",
99 "container_many_things.tga",
100 "container_many_things.tga",
101 "container_sound.tga",
102 "container_texture.tga",
103 "container_texture.tga",
104 "container_animation.tga",
105 "container_gesture.tga"
106};
107*/
108
109class LLNoPreferredType : public LLInventoryCollectFunctor
110{
111public:
112 LLNoPreferredType() {}
113 virtual ~LLNoPreferredType() {}
114 virtual bool operator()(LLInventoryCategory* cat,
115 LLInventoryItem* item)
116 {
117 if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE))
118 {
119 return true;
120 }
121 return false;
122 }
123};
124
125class LLNoPreferredTypeOrItem : public LLInventoryCollectFunctor
126{
127public:
128 LLNoPreferredTypeOrItem() {}
129 virtual ~LLNoPreferredTypeOrItem() {}
130 virtual bool operator()(LLInventoryCategory* cat,
131 LLInventoryItem* item)
132 {
133 if(item) return true;
134 if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE))
135 {
136 return true;
137 }
138 return false;
139 }
140};
141
142class LLDroppableItem : public LLInventoryCollectFunctor
143{
144public:
145 LLDroppableItem(BOOL is_transfer) :
146 mCountLosing(0), mIsTransfer(is_transfer) {}
147 virtual ~LLDroppableItem() {}
148 virtual bool operator()(LLInventoryCategory* cat,
149 LLInventoryItem* item);
150 S32 countNoCopy() const { return mCountLosing; }
151
152protected:
153 S32 mCountLosing;
154 BOOL mIsTransfer;
155};
156
157bool LLDroppableItem::operator()(LLInventoryCategory* cat,
158 LLInventoryItem* item)
159{
160 bool allowed = false;
161 if(item)
162 {
163 LLVOAvatar* my_avatar = NULL;
164 switch(item->getType())
165 {
166 case LLAssetType::AT_CALLINGCARD:
167 // not allowed
168 break;
169
170 case LLAssetType::AT_OBJECT:
171 my_avatar = gAgent.getAvatarObject();
172 if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
173 {
174 allowed = true;
175 }
176 break;
177
178 case LLAssetType::AT_BODYPART:
179 case LLAssetType::AT_CLOTHING:
180 if(!gAgent.isWearingItem(item->getUUID()))
181 {
182 allowed = true;
183 }
184 break;
185
186 default:
187 allowed = true;
188 break;
189 }
190 if(mIsTransfer
191 && !item->getPermissions().allowOperationBy(PERM_TRANSFER,
192 gAgent.getID()))
193 {
194 allowed = false;
195 }
196 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
197 {
198 ++mCountLosing;
199 }
200 }
201 return allowed;
202}
203
204class LLUncopyableItems : public LLInventoryCollectFunctor
205{
206public:
207 LLUncopyableItems() {}
208 virtual ~LLUncopyableItems() {}
209 virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
210};
211
212bool LLUncopyableItems::operator()(LLInventoryCategory* cat,
213 LLInventoryItem* item)
214{
215 BOOL uncopyable = FALSE;
216 if(item)
217 {
218 BOOL allowed = FALSE;
219 LLVOAvatar* my_avatar = NULL;
220 switch(item->getType())
221 {
222 case LLAssetType::AT_CALLINGCARD:
223 // not allowed
224 break;
225
226 case LLAssetType::AT_OBJECT:
227 my_avatar = gAgent.getAvatarObject();
228 if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
229 {
230 allowed = TRUE;
231 }
232 break;
233
234 case LLAssetType::AT_BODYPART:
235 case LLAssetType::AT_CLOTHING:
236 if(!gAgent.isWearingItem(item->getUUID()))
237 {
238 allowed = TRUE;
239 }
240 break;
241
242 default:
243 allowed = TRUE;
244 break;
245 }
246 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
247 {
248 uncopyable = TRUE;
249 }
250 }
251 return (uncopyable ? true : false);
252}
253
254class LLDropCopyableItems : public LLInventoryCollectFunctor
255{
256public:
257 LLDropCopyableItems() {}
258 virtual ~LLDropCopyableItems() {}
259 virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
260};
261
262
263bool LLDropCopyableItems::operator()(
264 LLInventoryCategory* cat, LLInventoryItem* item)
265{
266 BOOL allowed = FALSE;
267 if(item)
268 {
269 LLVOAvatar* my_avatar = NULL;
270 switch(item->getType())
271 {
272 case LLAssetType::AT_CALLINGCARD:
273 // not allowed
274 break;
275
276 case LLAssetType::AT_OBJECT:
277 my_avatar = gAgent.getAvatarObject();
278 if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
279 {
280 allowed = TRUE;
281 }
282 break;
283
284 case LLAssetType::AT_BODYPART:
285 case LLAssetType::AT_CLOTHING:
286 if(!gAgent.isWearingItem(item->getUUID()))
287 {
288 allowed = TRUE;
289 }
290 break;
291
292 default:
293 allowed = TRUE;
294 break;
295 }
296 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
297 {
298 // whoops, can't copy it - don't allow it.
299 allowed = FALSE;
300 }
301 }
302 return (allowed ? true : false);
303}
304
305class LLGiveable : public LLInventoryCollectFunctor
306{
307public:
308 LLGiveable() : mCountLosing(0) {}
309 virtual ~LLGiveable() {}
310 virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
311
312 S32 countNoCopy() const { return mCountLosing; }
313protected:
314 S32 mCountLosing;
315};
316
317bool LLGiveable::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
318{
319 // All categories can be given.
320 if(cat) return TRUE;
321 BOOL allowed = FALSE;
322 if(item)
323 {
324 LLVOAvatar* my_avatar = NULL;
325 switch(item->getType())
326 {
327 case LLAssetType::AT_CALLINGCARD:
328 // not allowed
329 break;
330
331 case LLAssetType::AT_OBJECT:
332 my_avatar = gAgent.getAvatarObject();
333 if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
334 {
335 allowed = TRUE;
336 }
337 break;
338
339 case LLAssetType::AT_BODYPART:
340 case LLAssetType::AT_CLOTHING:
341 if(!gAgent.isWearingItem(item->getUUID()))
342 {
343 allowed = TRUE;
344 }
345 break;
346
347 default:
348 allowed = TRUE;
349 break;
350 }
351 if(!item->getPermissions().allowOperationBy(PERM_TRANSFER,
352 gAgent.getID()))
353 {
354 allowed = FALSE;
355 }
356 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
357 {
358 ++mCountLosing;
359 }
360 }
361 return (allowed ? true : false);
362}
363
364class LLCategoryFireAndForget : public LLInventoryFetchComboObserver
365{
366public:
367 LLCategoryFireAndForget() {}
368 ~LLCategoryFireAndForget() {}
369 virtual void done()
370 {
371 /* no-op: it's fire n forget right? */
372 lldebugs << "LLCategoryFireAndForget::done()" << llendl;
373 }
374};
375
376class LLCategoryDropObserver : public LLInventoryFetchObserver
377{
378public:
379 LLCategoryDropObserver(
380 const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
381 mObjectID(obj_id),
382 mSource(src)
383 {}
384 ~LLCategoryDropObserver() {}
385 virtual void done();
386
387protected:
388 LLUUID mObjectID;
389 LLToolDragAndDrop::ESource mSource;
390};
391
392void LLCategoryDropObserver::done()
393{
394 gInventory.removeObserver(this);
395 LLViewerObject* dst_obj = gObjectList.findObject(mObjectID);
396 if(dst_obj)
397 {
398 // *FIX: coalesce these...
399 LLInventoryItem* item = NULL;
400 item_ref_t::iterator it = mComplete.begin();
401 item_ref_t::iterator end = mComplete.end();
402 for(; it < end; ++it)
403 {
404 item = gInventory.getItem(*it);
405 if(item)
406 {
407 LLToolDragAndDrop::dropInventory(
408 dst_obj,
409 item,
410 mSource,
411 LLUUID::null);
412 }
413 }
414 }
415 delete this;
416}
417
418class LLCategoryDropDescendentsObserver : public LLInventoryFetchDescendentsObserver
419{
420public:
421 LLCategoryDropDescendentsObserver(
422 const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
423 mObjectID(obj_id),
424 mSource(src)
425 {}
426 ~LLCategoryDropDescendentsObserver() {}
427 virtual void done();
428
429protected:
430 LLUUID mObjectID;
431 LLToolDragAndDrop::ESource mSource;
432};
433
434void LLCategoryDropDescendentsObserver::done()
435{
436
437 gInventory.removeObserver(this);
438 folder_ref_t::iterator it = mCompleteFolders.begin();
439 folder_ref_t::iterator end = mCompleteFolders.end();
440 LLViewerInventoryCategory::cat_array_t cats;
441 LLViewerInventoryItem::item_array_t items;
442 for(; it != end; ++it)
443 {
444 gInventory.collectDescendents(
445 (*it),
446 cats,
447 items,
448 LLInventoryModel::EXCLUDE_TRASH);
449 }
450
451 S32 count = items.count();
452 if(count)
453 {
454 std::set<LLUUID> unique_ids;
455 for(S32 i = 0; i < count; ++i)
456 {
457 unique_ids.insert(items.get(i)->getUUID());
458 }
459 LLInventoryFetchObserver::item_ref_t ids;
460 std::back_insert_iterator<LLInventoryFetchObserver::item_ref_t> copier(ids);
461 std::copy(unique_ids.begin(), unique_ids.end(), copier);
462 LLCategoryDropObserver* dropper;
463 dropper = new LLCategoryDropObserver(mObjectID, mSource);
464 dropper->fetchItems(ids);
465 if(dropper->isEverythingComplete())
466 {
467 dropper->done();
468 }
469 else
470 {
471 gInventory.addObserver(dropper);
472 }
473 }
474 delete this;
475}
476
477// This array is used to more easily control what happens when a 3d
478// drag and drop event occurs. Since there's an array of drop target
479// and cargo type, it's implemented as an array of pointers to member
480// functions which correctly carry out the actual drop.
481LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT][LLToolDragAndDrop::DT_COUNT] =
482{
483 // Source: DAD_NONE
484 {
485 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
486 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
487 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
488 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
489 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
490 },
491 // Source: DAD_TEXTURE
492 {
493 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
494 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
495 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
496 &LLToolDragAndDrop::dad3dTextureObject, // Dest: DT_OBJECT
497 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
498 },
499 // Source: DAD_SOUND
500 {
501 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
502 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
503 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
504 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
505 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
506 },
507 // Source: DAD_CALLINGCARD
508 {
509 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
510 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
511 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
512 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
513 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
514 },
515 // Source: DAD_LANDMARK
516 {
517 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
518 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
519 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
520 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
521 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
522 },
523 // Source: DAD_SCRIPT
524 {
525 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
526 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
527 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
528 &LLToolDragAndDrop::dad3dRezScript, // Dest: DT_OBJECT
529 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
530 },
531 // Source: DAD_CLOTHING
532 {
533 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
534 &LLToolDragAndDrop::dad3dWearItem, // Dest: DT_SELF
535 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
536 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
537 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
538 },
539 // Source: DAD_OBJECT
540 {
541 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
542 &LLToolDragAndDrop::dad3dRezAttachmentFromInv, // Dest: DT_SELF
543 &LLToolDragAndDrop::dad3dGiveInventoryObject, // Dest: DT_AVATAR
544 &LLToolDragAndDrop::dad3dRezObjectOnObject, // Dest: DT_OBJECT
545 &LLToolDragAndDrop::dad3dRezObjectOnLand, // Dest: DT_LAND
546 },
547 // Source: DAD_NOTECARD
548 {
549 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
550 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
551 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
552 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
553 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
554 },
555 // Source: DAD_CATEGORY
556 {
557 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
558 &LLToolDragAndDrop::dad3dWearCategory, // Dest: DT_SELF
559 &LLToolDragAndDrop::dad3dGiveInventoryCategory, // Dest: DT_AVATAR
560 &LLToolDragAndDrop::dad3dUpdateInventoryCategory, // Dest: DT_OBJECT
561 &LLToolDragAndDrop::dad3dNULL,//dad3dCategoryOnLand, // Dest: DT_LAND
562 },
563 // Source: DAD_ROOT
564 {
565 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
566 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
567 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
568 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
569 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
570 },
571 // Source: DAD_BODYPART
572 {
573 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
574 &LLToolDragAndDrop::dad3dWearItem, // Dest: DT_SELF
575 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
576 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
577 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
578 },
579 // Source: DAD_ANIMATION
580 // TODO: animation on self could play it? edit it?
581 {
582 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
583 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
584 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
585 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
586 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
587 },
588 // Source: DAD_GESTURE
589 // TODO: gesture on self could play it? edit it?
590 {
591 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
592 &LLToolDragAndDrop::dad3dActivateGesture, // Dest: DT_SELF
593 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
594 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
595 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
596 },
597};
598
599LLToolDragAndDrop::LLToolDragAndDrop()
600 :
601 LLTool("draganddrop", NULL),
602 mDragStartX(0),
603 mDragStartY(0),
604 mCursor(UI_CURSOR_NO),
605 mLastAccept(ACCEPT_NO),
606 mDrop(FALSE),
607 mCurItemIndex(0)
608{
609 // setup container texture ids
610 //for (S32 i = 0; i < LLAssetType::AT_COUNT; i++)
611 //{
612 // CONTAINER_TEXTURES[i].set(gViewerArt.getString(CONTAINER_TEXTURE_NAMES[i]));
613 //}
614}
615
616void LLToolDragAndDrop::setDragStart(S32 x, S32 y)
617{
618 mDragStartX = x;
619 mDragStartY = y;
620}
621
622BOOL LLToolDragAndDrop::isOverThreshold(S32 x,S32 y)
623{
624 const S32 MIN_MANHATTAN_DIST = 3;
625 S32 manhattan_dist = llabs( x - mDragStartX ) + llabs( y - mDragStartY );
626 return manhattan_dist >= MIN_MANHATTAN_DIST;
627}
628
629void LLToolDragAndDrop::beginDrag(EDragAndDropType type,
630 const LLUUID& cargo_id,
631 ESource source,
632 const LLUUID& source_id,
633 const LLUUID& object_id)
634{
635 if(type == DAD_NONE)
636 {
637 llwarns << "Attempted to start drag without a cargo type" << llendl;
638 return;
639 }
640 mCargoTypes.clear();
641 mCargoTypes.push_back(type);
642 mCargoIDs.clear();
643 mCargoIDs.push_back(cargo_id);
644 mSource = source;
645 mSourceID = source_id;
646 mObjectID = object_id;
647
648 setMouseCapture( TRUE );
649 gToolMgr->setTransientTool( this );
650 mCursor = UI_CURSOR_NO;
651 if((mCargoTypes[0] == DAD_CATEGORY)
652 && ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)))
653 {
654 LLInventoryCategory* cat = gInventory.getCategory(cargo_id);
655 // go ahead and fire & forget the descendents if we are not
656 // dragging a protected folder.
657 if(cat)
658 {
659 LLViewerInventoryCategory::cat_array_t cats;
660 LLViewerInventoryItem::item_array_t items;
661 LLNoPreferredTypeOrItem is_not_preferred;
662 LLInventoryFetchComboObserver::folder_ref_t folder_ids;
663 LLInventoryFetchComboObserver::item_ref_t item_ids;
664 if(is_not_preferred(cat, NULL))
665 {
666 folder_ids.push_back(cargo_id);
667 }
668 gInventory.collectDescendentsIf(
669 cargo_id,
670 cats,
671 items,
672 LLInventoryModel::EXCLUDE_TRASH,
673 is_not_preferred);
674 S32 count = cats.count();
675 S32 i;
676 for(i = 0; i < count; ++i)
677 {
678 folder_ids.push_back(cats.get(i)->getUUID());
679 }
680 count = items.count();
681 for(i = 0; i < count; ++i)
682 {
683 item_ids.push_back(items.get(i)->getUUID());
684 }
685 if(!folder_ids.empty() || !item_ids.empty())
686 {
687 LLCategoryFireAndForget fetcher;
688 fetcher.fetch(folder_ids, item_ids);
689 }
690 }
691 }
692}
693
694void LLToolDragAndDrop::beginMultiDrag(
695 const std::vector<EDragAndDropType> types,
696 const std::vector<LLUUID>& cargo_ids,
697 ESource source,
698 const LLUUID& source_id)
699{
700 // assert on public api is evil
701 //llassert( type != DAD_NONE );
702
703 std::vector<EDragAndDropType>::const_iterator types_it;
704 for (types_it = types.begin(); types_it != types.end(); ++types_it)
705 {
706 if(DAD_NONE == *types_it)
707 {
708 llwarns << "Attempted to start drag without a cargo type" << llendl;
709 return;
710 }
711 }
712 mCargoTypes = types;
713 mCargoIDs = cargo_ids;
714 mSource = source;
715 mSourceID = source_id;
716
717 setMouseCapture( TRUE );
718 gToolMgr->setTransientTool( this );
719 mCursor = UI_CURSOR_NO;
720 if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
721 {
722 // find cats in the cargo.
723 LLInventoryCategory* cat = NULL;
724 S32 count = llmin(cargo_ids.size(), types.size());
725 std::set<LLUUID> cat_ids;
726 for(S32 i = 0; i < count; ++i)
727 {
728 cat = gInventory.getCategory(cargo_ids[i]);
729 if(cat)
730 {
731 LLViewerInventoryCategory::cat_array_t cats;
732 LLViewerInventoryItem::item_array_t items;
733 LLNoPreferredType is_not_preferred;
734 if(is_not_preferred(cat, NULL))
735 {
736 cat_ids.insert(cat->getUUID());
737 }
738 gInventory.collectDescendentsIf(
739 cat->getUUID(),
740 cats,
741 items,
742 LLInventoryModel::EXCLUDE_TRASH,
743 is_not_preferred);
744 S32 cat_count = cats.count();
745 for(S32 i = 0; i < cat_count; ++i)
746 {
747 cat_ids.insert(cat->getUUID());
748 }
749 }
750 }
751 if(!cat_ids.empty())
752 {
753 LLInventoryFetchComboObserver::folder_ref_t folder_ids;
754 LLInventoryFetchComboObserver::item_ref_t item_ids;
755 std::back_insert_iterator<LLInventoryFetchDescendentsObserver::folder_ref_t> copier(folder_ids);
756 std::copy(cat_ids.begin(), cat_ids.end(), copier);
757 LLCategoryFireAndForget fetcher;
758 fetcher.fetch(folder_ids, item_ids);
759 }
760 }
761}
762
763void LLToolDragAndDrop::endDrag()
764{
765 gSelectMgr->unhighlightAll();
766 setMouseCapture(FALSE);
767}
768
769void LLToolDragAndDrop::onMouseCaptureLost()
770{
771 // Called whenever the drag ends or if mouse captue is simply lost
772 gToolMgr->clearTransientTool();
773 mCargoTypes.clear();
774 mCargoIDs.clear();
775 mSource = SOURCE_AGENT;
776 mSourceID.setNull();
777 mObjectID.setNull();
778}
779
780BOOL LLToolDragAndDrop::handleMouseUp( S32 x, S32 y, MASK mask )
781{
782 if( hasMouseCapture() )
783 {
784 EAcceptance acceptance = ACCEPT_NO;
785 dragOrDrop( x, y, mask, TRUE, &acceptance );
786 endDrag();
787 }
788 return TRUE;
789}
790
791BOOL LLToolDragAndDrop::handleHover( S32 x, S32 y, MASK mask )
792{
793 EAcceptance acceptance = ACCEPT_NO;
794 dragOrDrop( x, y, mask, FALSE, &acceptance );
795
796 switch( acceptance )
797 {
798 case ACCEPT_YES_MULTI:
799 if (mCargoIDs.size() > 1)
800 {
801 mCursor = UI_CURSOR_ARROWDRAGMULTI;
802 }
803 else
804 {
805 mCursor = UI_CURSOR_ARROWDRAG;
806 }
807 break;
808 case ACCEPT_YES_SINGLE:
809 mCursor = UI_CURSOR_ARROWDRAG;
810 break;
811
812 case ACCEPT_NO_LOCKED:
813 mCursor = UI_CURSOR_NOLOCKED;
814 break;
815
816 case ACCEPT_NO:
817 mCursor = UI_CURSOR_NO;
818 break;
819
820 case ACCEPT_YES_COPY_MULTI:
821 if (mCargoIDs.size() > 1)
822 {
823 mCursor = UI_CURSOR_ARROWCOPYMULTI;
824 }
825 else
826 {
827 mCursor = UI_CURSOR_ARROWCOPY;
828 }
829 break;
830 case ACCEPT_YES_COPY_SINGLE:
831 mCursor = UI_CURSOR_ARROWCOPY;
832 break;
833 case ACCEPT_POSTPONED:
834 break;
835 default:
836 llassert( FALSE );
837 }
838
839 gViewerWindow->getWindow()->setCursor( mCursor );
840 lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolDragAndDrop" << llendl;
841 return TRUE;
842}
843
844BOOL LLToolDragAndDrop::handleKey(KEY key, MASK mask)
845{
846 if (key == KEY_ESCAPE)
847 {
848 // cancel drag and drop operation
849 endDrag();
850 return TRUE;
851 }
852
853 return FALSE;
854}
855
856BOOL LLToolDragAndDrop::handleToolTip(S32 x, S32 y, LLString& msg, LLRect *sticky_rect_screen)
857{
858 if (!mToolTipMsg.empty())
859 {
860 msg = mToolTipMsg;
861 //*stick_rect_screen = gViewerWindow->getWindowRect();
862 return TRUE;
863 }
864 return FALSE;
865}
866
867void LLToolDragAndDrop::handleDeselect()
868{
869 mToolTipMsg.clear();
870}
871
872// protected
873void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
874 EAcceptance* acceptance)
875{
876 *acceptance = ACCEPT_YES_MULTI;
877
878 BOOL handled = FALSE;
879
880 LLView* top_view = gViewerWindow->getTopView();
881 LLViewerInventoryItem* item;
882 LLViewerInventoryCategory* cat;
883
884 mToolTipMsg.assign("");
885
886 if(top_view)
887 {
888 handled = TRUE;
889
890 for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
891 {
892 LLInventoryObject* cargo = locateInventory(item, cat);
893
894 if (cargo)
895 {
896 S32 local_x, local_y;
897 top_view->screenPointToLocal( x, y, &local_x, &local_y );
898 EAcceptance item_acceptance = ACCEPT_NO;
899 handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE,
900 mCargoTypes[mCurItemIndex],
901 (void*)cargo,
902 &item_acceptance,
903 mToolTipMsg);
904 if (handled)
905 {
906 // use sort order to determine priority of acceptance
907 *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
908 }
909 }
910 else
911 {
912 return;
913 }
914 }
915
916 // all objects passed, go ahead and perform drop if necessary
917 if (handled && drop && (U32)*acceptance >= ACCEPT_YES_COPY_SINGLE)
918 {
919 // drop all items
920 if ((U32)*acceptance >= ACCEPT_YES_COPY_MULTI)
921 {
922 mCurItemIndex = 0;
923 }
924 // drop just last item
925 else
926 {
927 mCurItemIndex = mCargoIDs.size() - 1;
928 }
929 for (; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
930 {
931 LLInventoryObject* cargo = locateInventory(item, cat);
932
933 if (cargo)
934 {
935 S32 local_x, local_y;
936
937 EAcceptance item_acceptance;
938 top_view->screenPointToLocal( x, y, &local_x, &local_y );
939 handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, TRUE,
940 mCargoTypes[mCurItemIndex],
941 (void*)cargo,
942 &item_acceptance,
943 mToolTipMsg);
944 }
945 }
946 }
947 if (handled)
948 {
949 mLastAccept = (EAcceptance)*acceptance;
950 }
951 }
952
953 if(!handled)
954 {
955 handled = TRUE;
956
957 LLView* root_view = gViewerWindow->getRootView();
958
959 for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
960 {
961 LLInventoryObject* cargo = locateInventory(item, cat);
962
963 EAcceptance item_acceptance = ACCEPT_NO;
964 handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE,
965 mCargoTypes[mCurItemIndex],
966 (void*)cargo,
967 &item_acceptance,
968 mToolTipMsg);
969 if (handled)
970 {
971 // use sort order to determine priority of acceptance
972 *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
973 }
974 }
975 // all objects passed, go ahead and perform drop if necessary
976 if (handled && drop && (U32)*acceptance > ACCEPT_NO_LOCKED)
977 {
978 // drop all items
979 if ((U32)*acceptance >= ACCEPT_YES_COPY_MULTI)
980 {
981 mCurItemIndex = 0;
982 }
983 // drop just last item
984 else
985 {
986 mCurItemIndex = mCargoIDs.size() - 1;
987 }
988 for (; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
989 {
990 LLInventoryObject* cargo = locateInventory(item, cat);
991
992 if (cargo)
993 {
994 //S32 local_x, local_y;
995
996 EAcceptance item_acceptance;
997 handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE,
998 mCargoTypes[mCurItemIndex],
999 (void*)cargo,
1000 &item_acceptance,
1001 mToolTipMsg);
1002 }
1003 }
1004 }
1005
1006 if (handled)
1007 {
1008 mLastAccept = (EAcceptance)*acceptance;
1009 }
1010 }
1011
1012 if ( !handled )
1013 {
1014 dragOrDrop3D( x, y, mask, drop, acceptance );
1015 }
1016}
1017
1018void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* acceptance )
1019{
1020 mDrop = drop;
1021 if (mDrop)
1022 {
1023 gPickFaces = TRUE;
1024 // don't allow drag and drop onto transparent objects
1025 gViewerWindow->hitObjectOrLandGlobalImmediate(x, y, pickCallback, FALSE);
1026 }
1027 else
1028 {
1029 // Don't pick faces during hover. Nothing currently requires per-face
1030 // data.
1031 // don't allow drag and drop onto transparent objects
1032 gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, pickCallback, FALSE);
1033 }
1034
1035 *acceptance = mLastAccept;
1036}
1037
1038void LLToolDragAndDrop::pickCallback(S32 x, S32 y, MASK mask)
1039{
1040 EDropTarget target = DT_NONE;
1041 S32 hit_face = -1;
1042
1043 LLViewerObject* hit_obj = gViewerWindow->lastNonFloraObjectHit();
1044 gSelectMgr->unhighlightAll();
1045
1046 // Treat attachments as part of the avatar they are attached to.
1047 if (hit_obj)
1048 {
1049 if(hit_obj->isAttachment() && !hit_obj->isHUDAttachment())
1050 {
1051 LLVOAvatar* avatar = LLVOAvatar::findAvatarFromAttachment( hit_obj );
1052 if( !avatar )
1053 {
1054 gToolDragAndDrop->mLastAccept = ACCEPT_NO;
1055 gToolDragAndDrop->mCursor = UI_CURSOR_NO;
1056 gViewerWindow->getWindow()->setCursor( gToolDragAndDrop->mCursor );
1057 return;
1058 }
1059
1060 hit_obj = avatar;
1061 }
1062
1063 if(hit_obj->isAvatar())
1064 {
1065 if(((LLVOAvatar*) hit_obj)->mIsSelf)
1066 {
1067 target = DT_SELF;
1068 hit_face = -1;
1069 }
1070 else
1071 {
1072 target = DT_AVATAR;
1073 hit_face = -1;
1074 }
1075 }
1076 else
1077 {
1078 target = DT_OBJECT;
1079 hit_face = gLastHitNonFloraObjectFace;
1080 // if any item being dragged will be applied to the object under our cursor
1081 // highlight that object
1082 for (S32 i = 0; i < (S32)gToolDragAndDrop->mCargoIDs.size(); i++)
1083 {
1084 if (gToolDragAndDrop->mCargoTypes[i] != DAD_OBJECT || (mask & MASK_CONTROL))
1085 {
1086 gSelectMgr->highlightObjectAndFamily(hit_obj);
1087 break;
1088 }
1089 }
1090 }
1091 }
1092 else if(gLastHitLand)
1093 {
1094 target = DT_LAND;
1095 hit_face = -1;
1096 }
1097
1098 gToolDragAndDrop->mLastAccept = ACCEPT_YES_MULTI;
1099
1100 for (gToolDragAndDrop->mCurItemIndex = 0; gToolDragAndDrop->mCurItemIndex < (S32)gToolDragAndDrop->mCargoIDs.size();
1101 gToolDragAndDrop->mCurItemIndex++)
1102 {
1103 // Call the right implementation function
1104 gToolDragAndDrop->mLastAccept = (EAcceptance)llmin(
1105 (U32)gToolDragAndDrop->mLastAccept,
1106 (U32)callMemberFunction((*gToolDragAndDrop),
1107 gToolDragAndDrop->sDragAndDrop3d[gToolDragAndDrop->mCargoTypes[gToolDragAndDrop->mCurItemIndex]][target])
1108 (hit_obj, hit_face, mask, FALSE));
1109 }
1110
1111 if (gToolDragAndDrop->mDrop && (U32)gToolDragAndDrop->mLastAccept >= ACCEPT_YES_COPY_SINGLE)
1112 {
1113 // if target allows multi-drop, go ahead and start iteration at beginning of cargo list
1114 if (gToolDragAndDrop->mLastAccept >= ACCEPT_YES_COPY_MULTI)
1115 {
1116 gToolDragAndDrop->mCurItemIndex = 0;
1117 }
1118 // otherwise start at end, to follow selection rules (last selected item is most current)
1119 else
1120 {
1121 gToolDragAndDrop->mCurItemIndex = gToolDragAndDrop->mCargoIDs.size() - 1;
1122 }
1123
1124 for (; gToolDragAndDrop->mCurItemIndex < (S32)gToolDragAndDrop->mCargoIDs.size();
1125 gToolDragAndDrop->mCurItemIndex++)
1126 {
1127 // Call the right implementation function
1128 (U32)callMemberFunction((*gToolDragAndDrop),
1129 gToolDragAndDrop->sDragAndDrop3d[gToolDragAndDrop->mCargoTypes[gToolDragAndDrop->mCurItemIndex]][target])
1130 (hit_obj, hit_face, mask, TRUE);
1131 }
1132 }
1133
1134 switch( gToolDragAndDrop->mLastAccept )
1135 {
1136 case ACCEPT_YES_MULTI:
1137 if (gToolDragAndDrop->mCargoIDs.size() > 1)
1138 {
1139 gToolDragAndDrop->mCursor = UI_CURSOR_ARROWDRAGMULTI;
1140 }
1141 else
1142 {
1143 gToolDragAndDrop->mCursor = UI_CURSOR_ARROWDRAG;
1144 }
1145 break;
1146 case ACCEPT_YES_SINGLE:
1147 gToolDragAndDrop->mCursor = UI_CURSOR_ARROWDRAG;
1148 break;
1149
1150 case ACCEPT_NO_LOCKED:
1151 gToolDragAndDrop->mCursor = UI_CURSOR_NOLOCKED;
1152 break;
1153
1154 case ACCEPT_NO:
1155 gToolDragAndDrop->mCursor = UI_CURSOR_NO;
1156 break;
1157
1158 case ACCEPT_YES_COPY_MULTI:
1159 if (gToolDragAndDrop->mCargoIDs.size() > 1)
1160 {
1161 gToolDragAndDrop->mCursor = UI_CURSOR_ARROWCOPYMULTI;
1162 }
1163 else
1164 {
1165 gToolDragAndDrop->mCursor = UI_CURSOR_ARROWCOPY;
1166 }
1167 break;
1168 case ACCEPT_YES_COPY_SINGLE:
1169 gToolDragAndDrop->mCursor = UI_CURSOR_ARROWCOPY;
1170 break;
1171 case ACCEPT_POSTPONED:
1172 break;
1173 default:
1174 llassert( FALSE );
1175 }
1176
1177 gToolDragAndDrop->mLastHitPos = gLastHitPosGlobal + gLastHitObjectOffset;
1178 gToolDragAndDrop->mLastCameraPos = gAgent.getCameraPositionGlobal();
1179
1180 gViewerWindow->getWindow()->setCursor( gToolDragAndDrop->mCursor );
1181}
1182
1183// static
1184BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
1185 LLInventoryItem* item,
1186 LLToolDragAndDrop::ESource source,
1187 const LLUUID& src_id)
1188{
1189 // Always succeed if....
1190 // texture is from the library
1191 // or already in the contents of the object
1192 if(SOURCE_LIBRARY == source)
1193 {
1194 // dropping a texture from the library always just works.
1195 return TRUE;
1196 }
1197
1198 if (hit_obj->getInventoryItemByAsset(item->getAssetUUID()))
1199 {
1200 // if the asset is already in the object's inventory
1201 // then it can always be added to a side.
1202 // This saves some work if the task's inventory is already loaded
1203 return TRUE;
1204 }
1205
1206 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
1207 if(!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
1208 {
1209 // Check that we can add the texture as inventory to the object
1210 if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
1211 {
1212 return FALSE;
1213 }
1214 // make sure the object has the texture in it's inventory.
1215 if(SOURCE_AGENT == source)
1216 {
1217 // Remove the texture from local inventory. The server
1218 // will actually remove the item from agent inventory.
1219 gInventory.deleteObject(item->getUUID());
1220 gInventory.notifyObservers();
1221 }
1222 else if(SOURCE_WORLD == source)
1223 {
1224 // *FIX: if the objects are in different regions, and the
1225 // source region has crashed, you can bypass these
1226 // permissions.
1227 LLViewerObject* src_obj = gObjectList.findObject(src_id);
1228 if(src_obj)
1229 {
1230 src_obj->removeInventory(item->getUUID());
1231 }
1232 else
1233 {
1234 llwarns << "Unable to find source object." << llendl;
1235 return FALSE;
1236 }
1237 }
1238 hit_obj->updateInventory(new_item, TASK_INVENTORY_ASSET_KEY, true);
1239 }
1240 else if(!item->getPermissions().allowOperationBy(PERM_TRANSFER,
1241 gAgent.getID()))
1242 {
1243 // Check that we can add the testure as inventory to the object
1244 if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
1245 {
1246 return FALSE;
1247 }
1248 // *FIX: may want to make sure agent can paint hit_obj.
1249
1250 // make sure the object has the texture in it's inventory.
1251 hit_obj->updateInventory(new_item, TASK_INVENTORY_ASSET_KEY, true);
1252 }
1253 return TRUE;
1254}
1255
1256void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
1257 LLInventoryItem* item,
1258 LLToolDragAndDrop::ESource source,
1259 const LLUUID& src_id)
1260{
1261 LLUUID asset_id = item->getAssetUUID();
1262 BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
1263 if(!success)
1264 {
1265 return;
1266 }
1267 LLViewerImage* image = gImageList.getImage(asset_id);
1268 gViewerStats->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
1269 S32 num_faces = hit_obj->getNumTEs();
1270 for( S32 face = 0; face < num_faces; face++ )
1271 {
1272
1273 // update viewer side image in anticipation of update from simulator
1274 hit_obj->setTEImage(face, image);
1275 dialog_refresh_all();
1276
1277 // send the update to the simulator
1278 hit_obj->sendTEUpdate();
1279 }
1280
1281}
1282
1283/*
1284void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
1285{
1286 if (hit_face == -1) return;
1287 LLViewerImage* image = gImageList.getImage(item->getAssetUUID());
1288
1289 avatar->userSetOptionalTE( hit_face, image);
1290}
1291*/
1292
1293void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
1294 S32 hit_face,
1295 LLInventoryItem* item,
1296 LLToolDragAndDrop::ESource source,
1297 const LLUUID& src_id)
1298{
1299 if (hit_face == -1) return;
1300 if (!item)
1301 {
1302 llwarns << "LLToolDragAndDrop::dropTextureOneFace no texture item." << llendl;
1303 return;
1304 }
1305 LLUUID asset_id = item->getAssetUUID();
1306 BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
1307 if(!success)
1308 {
1309 return;
1310 }
1311 // update viewer side image in anticipation of update from simulator
1312 LLViewerImage* image = gImageList.getImage(asset_id);
1313 gViewerStats->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
1314 hit_obj->setTEImage(hit_face, image);
1315 dialog_refresh_all();
1316
1317 // send the update to the simulator
1318 hit_obj->sendTEUpdate();
1319}
1320
1321
1322void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj,
1323 LLInventoryItem* item,
1324 BOOL active,
1325 ESource source,
1326 const LLUUID& src_id)
1327{
1328 // *HACK: In order to resolve SL-22177, we need to block drags
1329 // from notecards and objects onto other objects.
1330 if((SOURCE_WORLD == gToolDragAndDrop->mSource)
1331 || (SOURCE_NOTECARD == gToolDragAndDrop->mSource))
1332 {
1333 llwarns << "Call to LLToolDragAndDrop::dropScript() from world"
1334 << " or notecard." << llendl;
1335 return;
1336 }
1337 if(hit_obj && item)
1338 {
1339 LLPointer<LLViewerInventoryItem> new_script = new LLViewerInventoryItem(item);
1340 if(!item->getPermissions().allowCopyBy(gAgent.getID()))
1341 {
1342 if(SOURCE_AGENT == source)
1343 {
1344 // Remove the script from local inventory. The server
1345 // will actually remove the item from agent inventory.
1346 gInventory.deleteObject(item->getUUID());
1347 gInventory.notifyObservers();
1348 }
1349 else if(SOURCE_WORLD == source)
1350 {
1351 // *FIX: if the objects are in different regions, and
1352 // the source region has crashed, you can bypass
1353 // these permissions.
1354 LLViewerObject* src_obj = gObjectList.findObject(src_id);
1355 if(src_obj)
1356 {
1357 src_obj->removeInventory(item->getUUID());
1358 }
1359 else
1360 {
1361 llwarns << "Unable to find source object." << llendl;
1362 return;
1363 }
1364 }
1365 }
1366 hit_obj->saveScript(new_script, active, true);
1367 gFloaterTools->dirty();
1368
1369 // VEFFECT: SetScript
1370 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1371 effectp->setSourceObject(gAgent.getAvatarObject());
1372 effectp->setTargetObject(hit_obj);
1373 effectp->setDuration(LL_HUD_DUR_SHORT);
1374 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1375 }
1376}
1377
1378void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
1379 BOOL bypass_sim_raycast,
1380 BOOL from_task_inventory,
1381 BOOL remove_from_inventory)
1382{
1383 LLViewerRegion* regionp = gWorldp->getRegionFromPosGlobal(mLastHitPos);
1384 if (!regionp)
1385 {
1386 llwarns << "Couldn't find region to rez object" << llendl;
1387 return;
1388 }
1389
1390 //llinfos << "Rezzing object" << llendl;
1391 make_ui_sound("UISndObjectRezIn");
1392 LLViewerInventoryItem* item;
1393 LLViewerInventoryCategory* cat;
1394 locateInventory(item, cat);
1395 if(!item || !item->isComplete()) return;
1396
1397 if (regionp
1398 && (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
1399 {
1400 LLFirstUse::useSandbox();
1401 }
1402
1403 LLMessageSystem* msg = gMessageSystem;
1404 if (mSource == SOURCE_NOTECARD)
1405 {
1406 msg->newMessageFast(_PREHASH_RezObjectFromNotecard);
1407 }
1408 else
1409 {
1410 msg->newMessageFast(_PREHASH_RezObject);
1411 }
1412 msg->nextBlockFast(_PREHASH_AgentData);
1413 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1414 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1415 msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
1416
1417 msg->nextBlock("RezData");
1418 // if it's being rezzed from task inventory, we need to enable
1419 // saving it back into the task inventory.
1420 // *FIX: We can probably compress this to a single byte, since I
1421 // think folderid == mSourceID. This will be a later
1422 // optimization.
1423 if(from_task_inventory)
1424 {
1425 msg->addUUIDFast(_PREHASH_FromTaskID, mSourceID);
1426 }
1427 else
1428 {
1429 msg->addUUIDFast(_PREHASH_FromTaskID, LLUUID::null);
1430 }
1431 msg->addU8Fast(_PREHASH_BypassRaycast, (U8) bypass_sim_raycast);
1432 msg->addVector3Fast(_PREHASH_RayStart, regionp->getPosRegionFromGlobal(mLastCameraPos));
1433 msg->addVector3Fast(_PREHASH_RayEnd, regionp->getPosRegionFromGlobal(mLastHitPos));
1434 // Limit raycast to a single object.
1435 // Speeds up server raycast + avoid problems with server ray
1436 // hitting objects that were clipped by the near plane or culled
1437 // on the viewer.
1438 LLUUID ray_target_id;
1439 if( raycast_target )
1440 {
1441 ray_target_id = raycast_target->getID();
1442 }
1443 else
1444 {
1445 ray_target_id.setNull();
1446 }
1447 msg->addUUIDFast(_PREHASH_RayTargetID, ray_target_id );
1448 msg->addBOOLFast(_PREHASH_RayEndIsIntersection, FALSE);
1449 // Select the object only if we're editing.
1450 BOOL rez_selected = gToolMgr->inEdit();
1451 msg->addBOOLFast(_PREHASH_RezSelected, rez_selected);
1452
1453 // check if it cannot be copied, and mark as remove if it is -
1454 // this will remove the object from inventory after rez. Only
1455 // bother with this check if we would not normally remove from
1456 // inventory.
1457 if(!remove_from_inventory
1458 && !item->getPermissions().allowCopyBy(gAgent.getID()))
1459 {
1460 remove_from_inventory = TRUE;
1461 }
1462
1463 // Check if it's in the trash.
1464 bool is_in_trash = false;
1465 LLUUID trash_id;
1466 trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
1467 if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
1468 {
1469 is_in_trash = true;
1470 remove_from_inventory = TRUE;
1471 }
1472 msg->addBOOLFast(_PREHASH_RemoveItem, remove_from_inventory);
1473
1474 // deal with permissions slam logic
1475 pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
1476
1477 LLUUID folder_id = item->getParentUUID();
1478 if((SOURCE_LIBRARY == mSource) || (is_in_trash))
1479 {
1480 // since it's coming from the library or trash, we want to not
1481 // 'take' it back to the same place.
1482 item->setParent(LLUUID::null);
1483 }
1484 if (mSource == SOURCE_NOTECARD)
1485 {
1486 msg->nextBlockFast(_PREHASH_NotecardData);
1487 msg->addUUIDFast(_PREHASH_NotecardItemID, mSourceID);
1488 msg->addUUIDFast(_PREHASH_ObjectID, mObjectID);
1489 msg->nextBlockFast(_PREHASH_InventoryData);
1490 msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
1491 }
1492 else
1493 {
1494 msg->nextBlockFast(_PREHASH_InventoryData);
1495 item->packMessage(msg);
1496 }
1497 msg->sendReliable(regionp->getHost());
1498 // back out the change. no actual internal changes take place.
1499 item->setParent(folder_id);
1500
1501 // If we're going to select it, get ready for the incoming
1502 // selected object.
1503 if (rez_selected)
1504 {
1505 gSelectMgr->deselectAll();
1506 gViewerWindow->getWindow()->incBusyCount();
1507 }
1508
1509 if(remove_from_inventory)
1510 {
1511 // Delete it from inventory immediately so that users cannot
1512 // easily bypass copy protection in laggy situations. If the
1513 // rez fails, we will put it back on the server.
1514 gInventory.deleteObject(item->getUUID());
1515 gInventory.notifyObservers();
1516 }
1517
1518 // VEFFECT: DropObject
1519 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1520 effectp->setSourceObject(gAgent.getAvatarObject());
1521 effectp->setPositionGlobal(mLastHitPos);
1522 effectp->setDuration(LL_HUD_DUR_SHORT);
1523 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1524
1525 gViewerStats->incStat(LLViewerStats::ST_REZ_COUNT);
1526}
1527
1528void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj,
1529 LLInventoryItem* item,
1530 LLToolDragAndDrop::ESource source,
1531 const LLUUID& src_id)
1532{
1533 // *HACK: In order to resolve SL-22177, we need to block drags
1534 // from notecards and objects onto other objects.
1535 if((SOURCE_WORLD == gToolDragAndDrop->mSource)
1536 || (SOURCE_NOTECARD == gToolDragAndDrop->mSource))
1537 {
1538 llwarns << "Call to LLToolDragAndDrop::dropInventory() from world"
1539 << " or notecard." << llendl;
1540 return;
1541 }
1542
1543 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
1544 S32 creation_date = time_corrected();
1545 new_item->setCreationDate(creation_date);
1546
1547 if(!item->getPermissions().allowCopyBy(gAgent.getID()))
1548 {
1549 if(SOURCE_AGENT == source)
1550 {
1551 // Remove the inventory item from local inventory. The
1552 // server will actually remove the item from agent
1553 // inventory.
1554 gInventory.deleteObject(item->getUUID());
1555 gInventory.notifyObservers();
1556 }
1557 else if(SOURCE_WORLD == source)
1558 {
1559 // *FIX: if the objects are in different regions, and the
1560 // source region has crashed, you can bypass these
1561 // permissions.
1562 LLViewerObject* src_obj = gObjectList.findObject(src_id);
1563 if(src_obj)
1564 {
1565 src_obj->removeInventory(item->getUUID());
1566 }
1567 else
1568 {
1569 llwarns << "Unable to find source object." << llendl;
1570 return;
1571 }
1572 }
1573 }
1574 hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
1575 if (gFloaterTools->getVisible())
1576 {
1577 // *FIX: only show this if panel not expanded?
1578 gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS);
1579 }
1580
1581 // VEFFECT: AddToInventory
1582 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1583 effectp->setSourceObject(gAgent.getAvatarObject());
1584 effectp->setTargetObject(hit_obj);
1585 effectp->setDuration(LL_HUD_DUR_SHORT);
1586 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1587 gFloaterTools->dirty();
1588}
1589
1590struct LLGiveInventoryInfo
1591{
1592 LLUUID mToAgentID;
1593 LLUUID mInventoryObjectID;
1594 LLGiveInventoryInfo(const LLUUID& to_agent, const LLUUID& obj_id) :
1595 mToAgentID(to_agent), mInventoryObjectID(obj_id) {}
1596};
1597
1598void LLToolDragAndDrop::giveInventory(const LLUUID& to_agent,
1599 LLInventoryItem* item)
1600{
1601 llinfos << "LLToolDragAndDrop::giveInventory()" << llendl;
1602 if(!isInventoryGiveAcceptable(item))
1603 {
1604 return;
1605 }
1606 if(item->getPermissions().allowCopyBy(gAgent.getID()))
1607 {
1608 // just give it away.
1609 LLToolDragAndDrop::commitGiveInventoryItem(to_agent, item);
1610 }
1611 else
1612 {
1613 // ask if the agent is sure.
1614 LLGiveInventoryInfo* info = new LLGiveInventoryInfo(to_agent,
1615 item->getUUID());
1616
1617 gViewerWindow->alertXml("CannotCopyWarning",
1618 &LLToolDragAndDrop::handleCopyProtectedItem,
1619 (void*)info);
1620 }
1621}
1622
1623// static
1624void LLToolDragAndDrop::handleCopyProtectedItem(S32 option, void* data)
1625{
1626 LLGiveInventoryInfo* info = (LLGiveInventoryInfo*)data;
1627 LLInventoryItem* item = NULL;
1628 switch(option)
1629 {
1630 case 0: // "Yes"
1631 item = gInventory.getItem(info->mInventoryObjectID);
1632 if(item)
1633 {
1634 LLToolDragAndDrop::commitGiveInventoryItem(info->mToAgentID,
1635 item);
1636 // delete it for now - it will be deleted on the server
1637 // quickly enough.
1638 gInventory.deleteObject(info->mInventoryObjectID);
1639 gInventory.notifyObservers();
1640 }
1641 else
1642 {
1643 gViewerWindow->alertXml("CannotGiveItem");
1644 }
1645 break;
1646
1647 default: // no, cancel, whatever, who cares, not yes.
1648 gViewerWindow->alertXml("TransactionCancelled");
1649 break;
1650 }
1651}
1652
1653// static
1654void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent,
1655 LLInventoryItem* item)
1656{
1657 if(!item) return;
1658 std::string name;
1659 gAgent.buildFullname(name);
1660 LLUUID transaction_id;
1661 transaction_id.generate();
1662 const S32 BUCKET_SIZE = sizeof(U8) + UUID_BYTES;
1663 U8 bucket[BUCKET_SIZE];
1664 bucket[0] = (U8)item->getType();
1665 memcpy(&bucket[1], &(item->getUUID().mData), UUID_BYTES);
1666 pack_instant_message(
1667 gMessageSystem,
1668 gAgent.getID(),
1669 FALSE,
1670 gAgent.getSessionID(),
1671 to_agent,
1672 name.c_str(),
1673 item->getName().c_str(),
1674 IM_ONLINE,
1675 IM_INVENTORY_OFFERED,
1676 transaction_id,
1677 0,
1678 LLUUID::null,
1679 gAgent.getPositionAgent(),
1680 NO_TIMESTAMP,
1681 bucket,
1682 BUCKET_SIZE);
1683 gAgent.sendReliableMessage();
1684
1685 // VEFFECT: giveInventory
1686 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1687 effectp->setSourceObject(gAgent.getAvatarObject());
1688 effectp->setTargetObject(gObjectList.findObject(to_agent));
1689 effectp->setDuration(LL_HUD_DUR_SHORT);
1690 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1691 gFloaterTools->dirty();
1692}
1693
1694void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent,
1695 LLInventoryCategory* cat)
1696{
1697 if(!cat) return;
1698 llinfos << "LLToolDragAndDrop::giveInventoryCategory() - "
1699 << cat->getUUID() << llendl;
1700
1701 LLVOAvatar* my_avatar = gAgent.getAvatarObject();
1702 if( !my_avatar )
1703 {
1704 return;
1705 }
1706
1707 // Test out how many items are being given.
1708 LLViewerInventoryCategory::cat_array_t cats;
1709 LLViewerInventoryItem::item_array_t items;
1710 LLGiveable giveable;
1711 gInventory.collectDescendentsIf(cat->getUUID(),
1712 cats,
1713 items,
1714 LLInventoryModel::EXCLUDE_TRASH,
1715 giveable);
1716 S32 count = cats.count();
1717 bool complete = true;
1718 for(S32 i = 0; i < count; ++i)
1719 {
1720 if(!gInventory.isCategoryComplete(cats.get(i)->getUUID()))
1721 {
1722 complete = false;
1723 break;
1724 }
1725 }
1726 if(!complete)
1727 {
1728 LLNotifyBox::showXml("IncompleteInventory");
1729 return;
1730 }
1731 count = items.count() + cats.count();
1732 if(count > MAX_ITEMS)
1733 {
1734 gViewerWindow->alertXml("TooManyItems");
1735 return;
1736 }
1737 else if(count == 0)
1738 {
1739 gViewerWindow->alertXml("NoItems");
1740 return;
1741 }
1742 else
1743 {
1744 if(0 == giveable.countNoCopy())
1745 {
1746 LLToolDragAndDrop::commitGiveInventoryCategory(to_agent, cat);
1747 }
1748 else
1749 {
1750 LLGiveInventoryInfo* info = NULL;
1751 info = new LLGiveInventoryInfo(to_agent, cat->getUUID());
1752 LLStringBase<char>::format_map_t args;
1753 args["[COUNT]"] = llformat("%d",giveable.countNoCopy());
1754 gViewerWindow->alertXml("CannotCopyCountItems", args,
1755 &LLToolDragAndDrop::handleCopyProtectedCategory,
1756 (void*)info);
1757
1758 }
1759 }
1760}
1761
1762
1763// static
1764void LLToolDragAndDrop::handleCopyProtectedCategory(S32 option, void* data)
1765{
1766 LLGiveInventoryInfo* info = (LLGiveInventoryInfo*)data;
1767 LLInventoryCategory* cat = NULL;
1768 switch(option)
1769 {
1770 case 0: // "Yes"
1771 cat = gInventory.getCategory(info->mInventoryObjectID);
1772 if(cat)
1773 {
1774 LLToolDragAndDrop::commitGiveInventoryCategory(info->mToAgentID,
1775 cat);
1776 LLViewerInventoryCategory::cat_array_t cats;
1777 LLViewerInventoryItem::item_array_t items;
1778 LLUncopyableItems remove;
1779 gInventory.collectDescendentsIf(cat->getUUID(),
1780 cats,
1781 items,
1782 LLInventoryModel::EXCLUDE_TRASH,
1783 remove);
1784 S32 count = items.count();
1785 for(S32 i = 0; i < count; ++i)
1786 {
1787 gInventory.deleteObject(items.get(i)->getUUID());
1788 }
1789 gInventory.notifyObservers();
1790 }
1791 else
1792 {
1793 gViewerWindow->alertXml("CannotGiveCategory");
1794 }
1795 break;
1796
1797 default: // no, cancel, whatever, who cares, not yes.
1798 gViewerWindow->alertXml("TransactionCancelled");
1799 break;
1800 }
1801}
1802
1803// static
1804void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent,
1805 LLInventoryCategory* cat)
1806{
1807 if(!cat) return;
1808 llinfos << "LLToolDragAndDrop::commitGiveInventoryCategory() - "
1809 << cat->getUUID() << llendl;
1810
1811 // Test out how many items are being given.
1812 LLViewerInventoryCategory::cat_array_t cats;
1813 LLViewerInventoryItem::item_array_t items;
1814 LLGiveable giveable;
1815 gInventory.collectDescendentsIf(cat->getUUID(),
1816 cats,
1817 items,
1818 LLInventoryModel::EXCLUDE_TRASH,
1819 giveable);
1820
1821 // MAX ITEMS is based on (sizeof(uuid)+2) * count must be <
1822 // MTUBYTES or 18 * count < 1200 => count < 1200/18 =>
1823 // 66. I've cut it down a bit from there to give some pad.
1824 S32 count = items.count() + cats.count();
1825 if(count > MAX_ITEMS)
1826 {
1827 gViewerWindow->alertXml("TooManyItems");
1828 return;
1829 }
1830 else if(count == 0)
1831 {
1832 gViewerWindow->alertXml("NoItems");
1833 return;
1834 }
1835 else
1836 {
1837 std::string name;
1838 gAgent.buildFullname(name);
1839 LLUUID transaction_id;
1840 transaction_id.generate();
1841 S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1);
1842 U8* bucket = new U8[bucket_size];
1843 U8* pos = bucket;
1844 U8 type = (U8)cat->getType();
1845 memcpy(pos, &type, sizeof(U8));
1846 pos += sizeof(U8);
1847 memcpy(pos, &(cat->getUUID()), UUID_BYTES);
1848 pos += UUID_BYTES;
1849 S32 i;
1850 count = cats.count();
1851 for(i = 0; i < count; ++i)
1852 {
1853 memcpy(pos, &type, sizeof(U8));
1854 pos += sizeof(U8);
1855 memcpy(pos, &(cats.get(i)->getUUID()), UUID_BYTES);
1856 pos += UUID_BYTES;
1857 }
1858 count = items.count();
1859 for(i = 0; i < count; ++i)
1860 {
1861 type = (U8)items.get(i)->getType();
1862 memcpy(pos, &type, sizeof(U8));
1863 pos += sizeof(U8);
1864 memcpy(pos, &(items.get(i)->getUUID()), UUID_BYTES);
1865 pos += UUID_BYTES;
1866 }
1867 pack_instant_message(
1868 gMessageSystem,
1869 gAgent.getID(),
1870 FALSE,
1871 gAgent.getSessionID(),
1872 to_agent,
1873 name.c_str(),
1874 cat->getName().c_str(),
1875 IM_ONLINE,
1876 IM_INVENTORY_OFFERED,
1877 transaction_id,
1878 0,
1879 LLUUID::null,
1880 gAgent.getPositionAgent(),
1881 NO_TIMESTAMP,
1882 bucket,
1883 bucket_size);
1884 gAgent.sendReliableMessage();
1885 delete[] bucket;
1886
1887 // VEFFECT: giveInventoryCategory
1888 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1889 effectp->setSourceObject(gAgent.getAvatarObject());
1890 effectp->setTargetObject(gObjectList.findObject(to_agent));
1891 effectp->setDuration(LL_HUD_DUR_SHORT);
1892 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1893 gFloaterTools->dirty();
1894 }
1895}
1896
1897// static
1898BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item)
1899{
1900 if(!item)
1901 {
1902 return FALSE;
1903 }
1904 if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
1905 {
1906 return FALSE;
1907 }
1908 BOOL copyable = FALSE;
1909 if(item->getPermissions().allowCopyBy(gAgent.getID())) copyable = TRUE;
1910 LLVOAvatar* my_avatar = gAgent.getAvatarObject();
1911 if(!my_avatar)
1912 {
1913 return FALSE;
1914 }
1915 BOOL acceptable = TRUE;
1916 switch(item->getType())
1917 {
1918 case LLAssetType::AT_CALLINGCARD:
1919 acceptable = FALSE;
1920 break;
1921 case LLAssetType::AT_OBJECT:
1922 if(my_avatar->isWearingAttachment(item->getUUID()))
1923 {
1924 acceptable = FALSE;
1925 }
1926 break;
1927 case LLAssetType::AT_BODYPART:
1928 case LLAssetType::AT_CLOTHING:
1929 if(!copyable && gAgent.isWearingItem(item->getUUID()))
1930 {
1931 acceptable = FALSE;
1932 }
1933 break;
1934 default:
1935 break;
1936 }
1937 return acceptable;
1938}
1939
1940// Static
1941BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item)
1942{
1943 if(!item)
1944 {
1945 return FALSE;
1946 }
1947
1948 // These permissions are double checked in the simulator in
1949 // LLGroupNoticeInventoryItemFetch::result().
1950 if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
1951 {
1952 return FALSE;
1953 }
1954 if(!item->getPermissions().allowCopyBy(gAgent.getID()))
1955 {
1956 return FALSE;
1957 }
1958
1959 LLVOAvatar* my_avatar = gAgent.getAvatarObject();
1960 if(!my_avatar)
1961 {
1962 return FALSE;
1963 }
1964
1965 BOOL acceptable = TRUE;
1966 switch(item->getType())
1967 {
1968 case LLAssetType::AT_CALLINGCARD:
1969 acceptable = FALSE;
1970 break;
1971 case LLAssetType::AT_OBJECT:
1972 if(my_avatar->isWearingAttachment(item->getUUID()))
1973 {
1974 acceptable = FALSE;
1975 }
1976 break;
1977 default:
1978 break;
1979 }
1980 return acceptable;
1981}
1982
1983// accessor that looks at permissions, copyability, and names of
1984// inventory items to determine if a drop would be ok.
1985EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item)
1986{
1987 // check the basics
1988 if(!item || !obj) return ACCEPT_NO;
1989 // HACK: downcast
1990 LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item;
1991 if(!vitem->isComplete()) return ACCEPT_NO;
1992
1993 // deny attempts to drop from an object onto itself. This is to
1994 // help make sure that drops that are from an object to an object
1995 // don't have to worry about order of evaluation. Think of this
1996 // like check for self in assignment.
1997 if(obj->getID() == item->getParentUUID())
1998 {
1999 return ACCEPT_NO;
2000 }
2001
2002 //BOOL copy = (perm.allowCopyBy(gAgent.getID(),
2003 // gAgent.getGroupID())
2004 // && (obj->mPermModify || obj->mFlagAllowInventoryAdd));
2005 BOOL worn = FALSE;
2006 LLVOAvatar* my_avatar = NULL;
2007 switch(item->getType())
2008 {
2009 case LLAssetType::AT_OBJECT:
2010 my_avatar = gAgent.getAvatarObject();
2011 if(my_avatar && my_avatar->isWearingAttachment(item->getUUID()))
2012 {
2013 worn = TRUE;
2014 }
2015 break;
2016 case LLAssetType::AT_BODYPART:
2017 case LLAssetType::AT_CLOTHING:
2018 if(gAgent.isWearingItem(item->getUUID()))
2019 {
2020 worn = TRUE;
2021 }
2022 break;
2023 default:
2024 break;
2025 }
2026 const LLPermissions& perm = item->getPermissions();
2027 BOOL modify = (obj->permModify() || obj->flagAllowInventoryAdd());
2028 BOOL transfer = FALSE;
2029 if((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
2030 || perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
2031 {
2032 transfer = TRUE;
2033 }
2034 BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
2035 BOOL attached = obj->isAttachment();
2036 BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
2037 if(attached && !unrestricted)
2038 {
2039 return ACCEPT_NO_LOCKED;
2040 }
2041 else if(modify && transfer && volume && !worn)
2042 {
2043 return ACCEPT_YES_MULTI;
2044 }
2045 else if(!modify)
2046 {
2047 return ACCEPT_NO_LOCKED;
2048 }
2049 return ACCEPT_NO;
2050}
2051
2052///
2053/// Methods called in the drag & drop array
2054///
2055
2056EAcceptance LLToolDragAndDrop::dad3dNULL(
2057 LLViewerObject*, S32, MASK, BOOL)
2058{
2059 lldebugs << "LLToolDragAndDrop::dad3dNULL()" << llendl;
2060 return ACCEPT_NO;
2061}
2062
2063EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
2064 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2065{
2066 lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl;
2067 // must be in the user's inventory
2068 if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
2069 {
2070 return ACCEPT_NO;
2071 }
2072
2073 LLViewerInventoryItem* item;
2074 LLViewerInventoryCategory* cat;
2075 locateInventory(item, cat);
2076 if(!item || !item->isComplete()) return ACCEPT_NO;
2077
2078 // must not be in the trash
2079 LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH));
2080 if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
2081 {
2082 return ACCEPT_NO;
2083 }
2084
2085 // must not be already wearing it
2086 LLVOAvatar* avatar = gAgent.getAvatarObject();
2087 if( !avatar || avatar->isWearingAttachment(item->getUUID()) )
2088 {
2089 return ACCEPT_NO;
2090 }
2091
2092 if( drop )
2093 {
2094 if(mSource == SOURCE_LIBRARY)
2095 {
2096 LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
2097 copy_inventory_item(
2098 gAgent.getID(),
2099 item->getPermissions().getOwner(),
2100 item->getUUID(),
2101 LLUUID::null,
2102 std::string(),
2103 cb);
2104 }
2105 else
2106 {
2107 rez_attachment(item, 0);
2108 }
2109 }
2110 return ACCEPT_YES_SINGLE;
2111}
2112
2113
2114EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
2115 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2116{
2117 if (mSource == SOURCE_WORLD)
2118 {
2119 return dad3dRezFromObjectOnLand(obj, face, mask, drop);
2120 }
2121
2122 lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnLand()" << llendl;
2123 LLViewerInventoryItem* item;
2124 LLViewerInventoryCategory* cat;
2125 locateInventory(item, cat);
2126 if(!item || !item->isComplete()) return ACCEPT_NO;
2127
2128 LLVOAvatar* my_avatar = gAgent.getAvatarObject();
2129 if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
2130 {
2131 return ACCEPT_NO;
2132 }
2133
2134 EAcceptance accept;
2135 BOOL remove_inventory;
2136
2137 // Get initial settings based on shift key
2138 if (mask & MASK_SHIFT)
2139 {
2140 // For now, always make copy
2141 //accept = ACCEPT_YES_SINGLE;
2142 //remove_inventory = TRUE;
2143 accept = ACCEPT_YES_COPY_SINGLE;
2144 remove_inventory = FALSE;
2145 }
2146 else
2147 {
2148 accept = ACCEPT_YES_COPY_SINGLE;
2149 remove_inventory = FALSE;
2150 }
2151
2152 // check if the item can be copied. If not, send that to the sim
2153 // which will remove the inventory item.
2154 if(!item->getPermissions().allowCopyBy(gAgent.getID()))
2155 {
2156 accept = ACCEPT_YES_SINGLE;
2157 remove_inventory = TRUE;
2158 }
2159
2160 // Check if it's in the trash.
2161 LLUUID trash_id;
2162 trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
2163 if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
2164 {
2165 accept = ACCEPT_YES_SINGLE;
2166 remove_inventory = TRUE;
2167 }
2168
2169 if(drop)
2170 {
2171 dropObject(obj, TRUE, FALSE, remove_inventory);
2172 }
2173
2174 return accept;
2175}
2176
2177EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
2178 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2179{
2180 // handle objects coming from object inventory
2181 if (mSource == SOURCE_WORLD)
2182 {
2183 return dad3dRezFromObjectOnObject(obj, face, mask, drop);
2184 }
2185
2186 lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnObject()" << llendl;
2187 LLViewerInventoryItem* item;
2188 LLViewerInventoryCategory* cat;
2189 locateInventory(item, cat);
2190 if(!item || !item->isComplete()) return ACCEPT_NO;
2191 LLVOAvatar* my_avatar = gAgent.getAvatarObject();
2192 if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
2193 {
2194 return ACCEPT_NO;
2195 }
2196
2197 if((mask & MASK_CONTROL))
2198 {
2199 // *HACK: In order to resolve SL-22177, we need to block drags
2200 // from notecards and objects onto other objects.
2201 if(mSource == SOURCE_NOTECARD)
2202 {
2203 return ACCEPT_NO;
2204 }
2205
2206 EAcceptance rv = willObjectAcceptInventory(obj, item);
2207 if(drop && (ACCEPT_YES_SINGLE <= rv))
2208 {
2209 dropInventory(obj, item, mSource, mSourceID);
2210 }
2211 return rv;
2212 }
2213
2214 EAcceptance accept;
2215 BOOL remove_inventory;
2216
2217 if (mask & MASK_SHIFT)
2218 {
2219 // For now, always make copy
2220 //accept = ACCEPT_YES_SINGLE;
2221 //remove_inventory = TRUE;
2222 accept = ACCEPT_YES_COPY_SINGLE;
2223 remove_inventory = FALSE;
2224 }
2225 else
2226 {
2227 accept = ACCEPT_YES_COPY_SINGLE;
2228 remove_inventory = FALSE;
2229 }
2230
2231 // check if the item can be copied. If not, send that to the sim
2232 // which will remove the inventory item.
2233 if(!item->getPermissions().allowCopyBy(gAgent.getID()))
2234 {
2235 accept = ACCEPT_YES_SINGLE;
2236 remove_inventory = TRUE;
2237 }
2238
2239 // Check if it's in the trash.
2240 LLUUID trash_id;
2241 trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
2242 if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
2243 {
2244 accept = ACCEPT_YES_SINGLE;
2245 remove_inventory = TRUE;
2246 }
2247
2248 if(drop)
2249 {
2250 dropObject(obj, FALSE, FALSE, remove_inventory);
2251 }
2252
2253 return accept;
2254}
2255
2256EAcceptance LLToolDragAndDrop::dad3dRezScript(
2257 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2258{
2259 lldebugs << "LLToolDragAndDrop::dad3dRezScript()" << llendl;
2260
2261 // *HACK: In order to resolve SL-22177, we need to block drags
2262 // from notecards and objects onto other objects.
2263 if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
2264 {
2265 return ACCEPT_NO;
2266 }
2267
2268 LLViewerInventoryItem* item;
2269 LLViewerInventoryCategory* cat;
2270 locateInventory(item, cat);
2271 if(!item || !item->isComplete()) return ACCEPT_NO;
2272 EAcceptance rv = willObjectAcceptInventory(obj, item);
2273 if(drop && (ACCEPT_YES_SINGLE <= rv))
2274 {
2275 // rez in the script active by default, rez in inactive if the
2276 // control key is being held down.
2277 BOOL active = ((mask & MASK_CONTROL) == 0);
2278
2279 LLViewerObject* root_object = obj;
2280 if (obj && obj->getParent())
2281 {
2282 LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
2283 if (!parent_obj->isAvatar())
2284 {
2285 root_object = parent_obj;
2286 }
2287 }
2288
2289 dropScript(root_object, item, active, mSource, mSourceID);
2290 }
2291 return rv;
2292}
2293
2294EAcceptance LLToolDragAndDrop::dad3dTextureObject(
2295 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2296{
2297 lldebugs << "LLToolDragAndDrop::dad3dTextureObject()" << llendl;
2298
2299 // *HACK: In order to resolve SL-22177, we need to block drags
2300 // from notecards and objects onto other objects.
2301 if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
2302 {
2303 return ACCEPT_NO;
2304 }
2305
2306 LLViewerInventoryItem* item;
2307 LLViewerInventoryCategory* cat;
2308 locateInventory(item, cat);
2309 if(!item || !item->isComplete()) return ACCEPT_NO;
2310 EAcceptance rv = willObjectAcceptInventory(obj, item);
2311 if((mask & MASK_CONTROL))
2312 {
2313 if((ACCEPT_YES_SINGLE <= rv) && drop)
2314 {
2315 dropInventory(obj, item, mSource, mSourceID);
2316 }
2317 return rv;
2318 }
2319 if(!obj->permModify())
2320 {
2321 return ACCEPT_NO_LOCKED;
2322 }
2323 if(drop && (ACCEPT_YES_SINGLE <= rv))
2324 {
2325 if((mask & MASK_SHIFT))
2326 {
2327 dropTextureAllFaces(obj, item, mSource, mSourceID);
2328 }
2329 else
2330 {
2331 dropTextureOneFace(obj, face, item, mSource, mSourceID);
2332 }
2333
2334 // VEFFECT: SetTexture
2335 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
2336 effectp->setSourceObject(gAgent.getAvatarObject());
2337 effectp->setTargetObject(obj);
2338 effectp->setDuration(LL_HUD_DUR_SHORT);
2339 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
2340 }
2341
2342 // enable multi-drop, although last texture will win
2343 return ACCEPT_YES_MULTI;
2344}
2345/*
2346EAcceptance LLToolDragAndDrop::dad3dTextureSelf(
2347 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2348{
2349 lldebugs << "LLToolDragAndDrop::dad3dTextureAvatar()" << llendl;
2350 if(drop)
2351 {
2352 if( !(mask & MASK_SHIFT) )
2353 {
2354 dropTextureOneFaceAvatar( (LLVOAvatar*)obj, face, (LLInventoryItem*)mCargoData);
2355 }
2356 }
2357 return (mask & MASK_SHIFT) ? ACCEPT_NO : ACCEPT_YES_SINGLE;
2358}
2359*/
2360
2361EAcceptance LLToolDragAndDrop::dad3dWearItem(
2362 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2363{
2364 lldebugs << "LLToolDragAndDrop::dad3dWearItem()" << llendl;
2365 LLViewerInventoryItem* item;
2366 LLViewerInventoryCategory* cat;
2367 locateInventory(item, cat);
2368 if(!item || !item->isComplete()) return ACCEPT_NO;
2369
2370 if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
2371 {
2372 // it's in the agent inventory
2373 LLUUID trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
2374 if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
2375 {
2376 return ACCEPT_NO;
2377 }
2378
2379 if( drop )
2380 {
2381 // Don't wear anything until initial wearables are loaded, can
2382 // destroy clothing items.
2383 if (!gAgent.areWearablesLoaded())
2384 {
2385 gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded");
2386 return ACCEPT_NO;
2387 }
2388
2389 if(mSource == SOURCE_LIBRARY)
2390 {
2391 // create item based on that one, and put it on if that
2392 // was a success.
2393 LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
2394 copy_inventory_item(
2395 gAgent.getID(),
2396 item->getPermissions().getOwner(),
2397 item->getUUID(),
2398 LLUUID::null,
2399 std::string(),
2400 cb);
2401 }
2402 else
2403 {
2404 wear_inventory_item_on_avatar( item );
2405 }
2406 }
2407 return ACCEPT_YES_MULTI;
2408 }
2409 else
2410 {
2411 // TODO: copy/move item to avatar's inventory and then wear it.
2412 return ACCEPT_NO;
2413 }
2414}
2415
2416EAcceptance LLToolDragAndDrop::dad3dActivateGesture(
2417 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2418{
2419 lldebugs << "LLToolDragAndDrop::dad3dActivateGesture()" << llendl;
2420 LLViewerInventoryItem* item;
2421 LLViewerInventoryCategory* cat;
2422 locateInventory(item, cat);
2423 if(!item || !item->isComplete()) return ACCEPT_NO;
2424
2425 if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
2426 {
2427 // it's in the agent inventory
2428 LLUUID trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
2429 if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
2430 {
2431 return ACCEPT_NO;
2432 }
2433
2434 if( drop )
2435 {
2436 LLUUID item_id;
2437 if(mSource == SOURCE_LIBRARY)
2438 {
2439 // create item based on that one, and put it on if that
2440 // was a success.
2441 LLPointer<LLInventoryCallback> cb = new ActivateGestureCallback();
2442 copy_inventory_item(
2443 gAgent.getID(),
2444 item->getPermissions().getOwner(),
2445 item->getUUID(),
2446 LLUUID::null,
2447 std::string(),
2448 cb);
2449 }
2450 else
2451 {
2452 gGestureManager.activateGesture(item->getUUID());
2453 gInventory.updateItem(item);
2454 gInventory.notifyObservers();
2455 }
2456 }
2457 return ACCEPT_YES_MULTI;
2458 }
2459 else
2460 {
2461 return ACCEPT_NO;
2462 }
2463}
2464
2465EAcceptance LLToolDragAndDrop::dad3dWearCategory(
2466 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2467{
2468 lldebugs << "LLToolDragAndDrop::dad3dWearCategory()" << llendl;
2469 LLViewerInventoryItem* item;
2470 LLViewerInventoryCategory* category;
2471 locateInventory(item, category);
2472 if(!category) return ACCEPT_NO;
2473
2474 if (drop)
2475 {
2476 // Don't wear anything until initial wearables are loaded, can
2477 // destroy clothing items.
2478 if (!gAgent.areWearablesLoaded())
2479 {
2480 gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded");
2481 return ACCEPT_NO;
2482 }
2483 }
2484
2485 if(mSource == SOURCE_AGENT)
2486 {
2487 LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH));
2488 if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) )
2489 {
2490 return ACCEPT_NO;
2491 }
2492
2493 if(drop)
2494 {
2495 BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
2496 wear_inventory_category(category, false, append);
2497 }
2498 return ACCEPT_YES_MULTI;
2499 }
2500 else if(mSource == SOURCE_LIBRARY)
2501 {
2502 if(drop)
2503 {
2504 wear_inventory_category(category, true, false);
2505 }
2506 return ACCEPT_YES_MULTI;
2507 }
2508 else
2509 {
2510 // TODO: copy/move category to avatar's inventory and then wear it.
2511 return ACCEPT_NO;
2512 }
2513}
2514
2515
2516EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
2517 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2518{
2519 lldebugs << "LLToolDragAndDrop::dadUpdateInventory()" << llendl;
2520
2521 // *HACK: In order to resolve SL-22177, we need to block drags
2522 // from notecards and objects onto other objects.
2523 if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
2524 {
2525 return ACCEPT_NO;
2526 }
2527
2528 LLViewerInventoryItem* item;
2529 LLViewerInventoryCategory* cat;
2530 locateInventory(item, cat);
2531 if(!item || !item->isComplete()) return ACCEPT_NO;
2532 LLViewerObject* root_object = obj;
2533 if (obj && obj->getParent())
2534 {
2535 LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
2536 if (!parent_obj->isAvatar())
2537 {
2538 root_object = parent_obj;
2539 }
2540 }
2541
2542 EAcceptance rv = willObjectAcceptInventory(root_object, item);
2543 if(root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv))
2544 {
2545 dropInventory(root_object, item, mSource, mSourceID);
2546 }
2547 return rv;
2548}
2549
2550BOOL LLToolDragAndDrop::dadUpdateInventory(LLViewerObject* obj, BOOL drop)
2551{
2552 EAcceptance rv = dad3dUpdateInventory(obj, -1, MASK_NONE, drop);
2553 return (rv >= ACCEPT_YES_COPY_SINGLE);
2554}
2555
2556EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
2557 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2558{
2559 lldebugs << "LLToolDragAndDrop::dad3dUpdateInventoryCategory()" << llendl;
2560 if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
2561 {
2562 return ACCEPT_NO;
2563 }
2564 if(obj->isAttachment()) return ACCEPT_NO_LOCKED;
2565 LLViewerInventoryItem* item;
2566 LLViewerInventoryCategory* cat;
2567 locateInventory(item, cat);
2568 if(!cat) return ACCEPT_NO;
2569 EAcceptance rv = ACCEPT_NO;
2570
2571 // find all the items in the category
2572 LLDroppableItem droppable(!obj->permYouOwner());
2573 LLInventoryModel::cat_array_t cats;
2574 LLInventoryModel::item_array_t items;
2575 gInventory.collectDescendentsIf(cat->getUUID(),
2576 cats,
2577 items,
2578 LLInventoryModel::EXCLUDE_TRASH,
2579 droppable);
2580 cats.put(cat);
2581 if(droppable.countNoCopy() > 0)
2582 {
2583 llwarns << "*** Need to confirm this step" << llendl;
2584 }
2585 LLViewerObject* root_object = obj;
2586 if (obj && obj->getParent())
2587 {
2588 LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
2589 if (!parent_obj->isAvatar())
2590 {
2591 root_object = parent_obj;
2592 }
2593 }
2594
2595 // Check for accept
2596 S32 i;
2597 S32 count = cats.count();
2598 for(i = 0; i < count; ++i)
2599 {
2600 rv = gInventory.isCategoryComplete(cats.get(i)->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO;
2601 if(rv < ACCEPT_YES_SINGLE)
2602 {
2603 lldebugs << "Category " << cats.get(i)->getUUID()
2604 << "is not complete." << llendl;
2605 break;
2606 }
2607 }
2608 if(ACCEPT_YES_COPY_SINGLE <= rv)
2609 {
2610 count = items.count();
2611 for(i = 0; i < count; ++i)
2612 {
2613 rv = willObjectAcceptInventory(root_object, items.get(i));
2614 if(rv < ACCEPT_YES_COPY_SINGLE)
2615 {
2616 lldebugs << "Object will not accept "
2617 << items.get(i)->getUUID() << llendl;
2618 break;
2619 }
2620 }
2621 }
2622
2623 // if every item is accepted, go ahead and send it on.
2624 if(drop && (ACCEPT_YES_COPY_SINGLE <= rv))
2625 {
2626 S32 count = items.count();
2627 LLInventoryFetchObserver::item_ref_t ids;
2628 for(i = 0; i < count; ++i)
2629 {
2630 //dropInventory(root_object, items.get(i), mSource, mSourceID);
2631 ids.push_back(items.get(i)->getUUID());
2632 }
2633 LLCategoryDropObserver* dropper;
2634 dropper = new LLCategoryDropObserver(obj->getID(), mSource);
2635 dropper->fetchItems(ids);
2636 if(dropper->isEverythingComplete())
2637 {
2638 dropper->done();
2639 }
2640 else
2641 {
2642 gInventory.addObserver(dropper);
2643 }
2644 }
2645 return rv;
2646}
2647
2648BOOL LLToolDragAndDrop::dadUpdateInventoryCategory(LLViewerObject* obj,
2649 BOOL drop)
2650{
2651 EAcceptance rv = dad3dUpdateInventoryCategory(obj, -1, MASK_NONE, drop);
2652 return (rv >= ACCEPT_YES_COPY_SINGLE);
2653}
2654
2655EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject(
2656 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2657{
2658 lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << llendl;
2659
2660 // item has to be in agent inventory.
2661 if(mSource != SOURCE_AGENT) return ACCEPT_NO;
2662
2663 // find the item now.
2664 LLViewerInventoryItem* item;
2665 LLViewerInventoryCategory* cat;
2666 locateInventory(item, cat);
2667 if(!item || !item->isComplete()) return ACCEPT_NO;
2668 if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
2669 {
2670 // cannot give away no-transfer objects
2671 return ACCEPT_NO;
2672 }
2673 LLVOAvatar* avatar = gAgent.getAvatarObject();
2674 if(avatar && avatar->isWearingAttachment( item->getUUID() ) )
2675 {
2676 // You can't give objects that are attached to you
2677 return ACCEPT_NO;
2678 }
2679 if( obj && avatar )
2680 {
2681 if(drop)
2682 {
2683 giveInventory(obj->getID(), item );
2684 }
2685 // *TODO: deal with all the issues surrounding multi-object
2686 // inventory transfers.
2687 return ACCEPT_YES_SINGLE;
2688 }
2689 return ACCEPT_NO;
2690}
2691
2692
2693EAcceptance LLToolDragAndDrop::dad3dGiveInventory(
2694 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2695{
2696 lldebugs << "LLToolDragAndDrop::dad3dGiveInventory()" << llendl;
2697 // item has to be in agent inventory.
2698 if(mSource != SOURCE_AGENT) return ACCEPT_NO;
2699 LLViewerInventoryItem* item;
2700 LLViewerInventoryCategory* cat;
2701 locateInventory(item, cat);
2702 if(!item || !item->isComplete()) return ACCEPT_NO;
2703 if(!isInventoryGiveAcceptable(item))
2704 {
2705 return ACCEPT_NO;
2706 }
2707 if(drop && obj)
2708 {
2709 giveInventory(obj->getID(), item);
2710 }
2711 // *TODO: deal with all the issues surrounding multi-object
2712 // inventory transfers.
2713 return ACCEPT_YES_SINGLE;
2714}
2715
2716EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory(
2717 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2718{
2719 lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryCategory()" << llendl;
2720 if(drop && obj)
2721 {
2722 LLViewerInventoryItem* item;
2723 LLViewerInventoryCategory* cat;
2724 locateInventory(item, cat);
2725 if(!cat) return ACCEPT_NO;
2726 giveInventoryCategory(obj->getID(), cat);
2727 }
2728 // *TODO: deal with all the issues surrounding multi-object
2729 // inventory transfers.
2730 return ACCEPT_YES_SINGLE;
2731}
2732
2733
2734EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand(
2735 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2736{
2737 lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnLand()" << llendl;
2738 LLViewerInventoryItem* item = NULL;
2739 LLViewerInventoryCategory* cat = NULL;
2740 locateInventory(item, cat);
2741 if(!item || !item->isComplete()) return ACCEPT_NO;
2742 if(!item->getPermissions().allowCopyBy(gAgent.getID(),
2743 gAgent.getGroupID())
2744 || !item->getPermissions().allowTransferTo(LLUUID::null))
2745 {
2746 return ACCEPT_NO_LOCKED;
2747 }
2748 if(drop)
2749 {
2750 dropObject(obj, TRUE, TRUE, FALSE);
2751 }
2752 return ACCEPT_YES_SINGLE;
2753}
2754
2755EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject(
2756 LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
2757{
2758 lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnObject()" << llendl;
2759 LLViewerInventoryItem* item;
2760 LLViewerInventoryCategory* cat;
2761 locateInventory(item, cat);
2762 if(!item || !item->isComplete()) return ACCEPT_NO;
2763 if((mask & MASK_CONTROL))
2764 {
2765 // *HACK: In order to resolve SL-22177, we need to block drags
2766 // from notecards and objects onto other objects.
2767 return ACCEPT_NO;
2768
2769 // *HACK: uncomment this when appropriate
2770 //EAcceptance rv = willObjectAcceptInventory(obj, item);
2771 //if(drop && (ACCEPT_YES_SINGLE <= rv))
2772 //{
2773 // dropInventory(obj, item, mSource, mSourceID);
2774 //}
2775 //return rv;
2776 }
2777 if(!item->getPermissions().allowCopyBy(gAgent.getID(),
2778 gAgent.getGroupID())
2779 || !item->getPermissions().allowTransferTo(LLUUID::null))
2780 {
2781 return ACCEPT_NO_LOCKED;
2782 }
2783 if(drop)
2784 {
2785 dropObject(obj, FALSE, TRUE, FALSE);
2786 }
2787 return ACCEPT_YES_SINGLE;
2788}
2789
2790EAcceptance LLToolDragAndDrop::dad3dCategoryOnLand(
2791 LLViewerObject *obj, S32 face, MASK mask, BOOL drop)
2792{
2793 return ACCEPT_NO;
2794 /*
2795 lldebugs << "LLToolDragAndDrop::dad3dCategoryOnLand()" << llendl;
2796 LLInventoryItem* item;
2797 LLInventoryCategory* cat;
2798 locateInventory(item, cat);
2799 if(!cat) return ACCEPT_NO;
2800 EAcceptance rv = ACCEPT_NO;
2801
2802 // find all the items in the category
2803 LLViewerInventoryCategory::cat_array_t cats;
2804 LLViewerInventoryItem::item_array_t items;
2805 LLDropCopyableItems droppable;
2806 gInventory.collectDescendentsIf(cat->getUUID(),
2807 cats,
2808 items,
2809 LLInventoryModel::EXCLUDE_TRASH,
2810 droppable);
2811 if(items.count() > 0)
2812 {
2813 rv = ACCEPT_YES_SINGLE;
2814 }
2815 if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
2816 {
2817 createContainer(items, cat->getName());
2818 return ACCEPT_NO;
2819 }
2820 return rv;
2821 */
2822}
2823
2824
2825// This is based on ALOT of copied, special-cased code
2826// This shortcuts alot of steps to make a basic object
2827// w/ an inventory and a special permissions set
2828EAcceptance LLToolDragAndDrop::dad3dAssetOnLand(
2829 LLViewerObject *obj, S32 face, MASK mask, BOOL drop)
2830{
2831 return ACCEPT_NO;
2832 /*
2833 lldebugs << "LLToolDragAndDrop::dad3dAssetOnLand()" << llendl;
2834 LLViewerInventoryCategory::cat_array_t cats;
2835 LLViewerInventoryItem::item_array_t items;
2836 LLViewerInventoryItem::item_array_t copyable_items;
2837 locateMultipleInventory(items, cats);
2838 if(!items.count()) return ACCEPT_NO;
2839 EAcceptance rv = ACCEPT_NO;
2840 for (S32 i = 0; i < items.count(); i++)
2841 {
2842 LLInventoryItem* item = items[i];
2843 if(item->getPermissions().allowCopyBy(gAgent.getID()))
2844 {
2845 copyable_items.put(item);
2846 rv = ACCEPT_YES_SINGLE;
2847 }
2848 }
2849
2850 if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
2851 {
2852 createContainer(copyable_items, NULL);
2853 }
2854
2855 return rv;
2856 */
2857}
2858
2859LLInventoryObject* LLToolDragAndDrop::locateInventory(
2860 LLViewerInventoryItem*& item,
2861 LLViewerInventoryCategory*& cat)
2862{
2863 item = NULL;
2864 cat = NULL;
2865 if(mCargoIDs.empty()) return NULL;
2866 if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
2867 {
2868 // The object should be in user inventory.
2869 item = (LLViewerInventoryItem*)gInventory.getItem(mCargoIDs[mCurItemIndex]);
2870 cat = (LLViewerInventoryCategory*)gInventory.getCategory(mCargoIDs[mCurItemIndex]);
2871 }
2872 else if(mSource == SOURCE_WORLD)
2873 {
2874 // This object is in some task inventory somewhere.
2875 LLViewerObject* obj = gObjectList.findObject(mSourceID);
2876 if(obj)
2877 {
2878 if((mCargoTypes[mCurItemIndex] == DAD_CATEGORY)
2879 || (mCargoTypes[mCurItemIndex] == DAD_ROOT_CATEGORY))
2880 {
2881 cat = (LLViewerInventoryCategory*)obj->getInventoryObject(mCargoIDs[mCurItemIndex]);
2882 }
2883 else
2884 {
2885 item = (LLViewerInventoryItem*)obj->getInventoryObject(mCargoIDs[mCurItemIndex]);
2886 }
2887 }
2888 }
2889 else if(mSource == SOURCE_NOTECARD)
2890 {
2891 LLPreviewNotecard* card;
2892 card = (LLPreviewNotecard*)LLPreview::find(mSourceID);
2893 if(card)
2894 {
2895 item = (LLViewerInventoryItem*)card->getDragItem();
2896 }
2897 }
2898 if(item) return item;
2899 if(cat) return cat;
2900 return NULL;
2901}
2902
2903/*
2904LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats,
2905 LLViewerInventoryItem::item_array_t& items)
2906{
2907 if(mCargoIDs.count() == 0) return NULL;
2908 if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
2909 {
2910 // The object should be in user inventory.
2911 for (S32 i = 0; i < mCargoIDs.count(); i++)
2912 {
2913 LLInventoryItem* item = gInventory.getItem(mCargoIDs[i]);
2914 if (item)
2915 {
2916 items.put(item);
2917 }
2918 LLInventoryCategory* category = gInventory.getCategory(mCargoIDs[i]);
2919 if (category)
2920 {
2921 cats.put(category);
2922 }
2923 }
2924 }
2925 else if(mSource == SOURCE_WORLD)
2926 {
2927 // This object is in some task inventory somewhere.
2928 LLViewerObject* obj = gObjectList.findObject(mSourceID);
2929 if(obj)
2930 {
2931 if((mCargoType == DAD_CATEGORY)
2932 || (mCargoType == DAD_ROOT_CATEGORY))
2933 {
2934 // The object should be in user inventory.
2935 for (S32 i = 0; i < mCargoIDs.count(); i++)
2936 {
2937 LLInventoryCategory* category = (LLInventoryCategory*)obj->getInventoryObject(mCargoIDs[i]);
2938 if (category)
2939 {
2940 cats.put(category);
2941 }
2942 }
2943 }
2944 else
2945 {
2946 for (S32 i = 0; i < mCargoIDs.count(); i++)
2947 {
2948 LLInventoryItem* item = (LLInventoryItem*)obj->getInventoryObject(mCargoIDs[i]);
2949 if (item)
2950 {
2951 items.put(item);
2952 }
2953 }
2954 }
2955 }
2956 }
2957 else if(mSource == SOURCE_NOTECARD)
2958 {
2959 LLPreviewNotecard* card;
2960 card = (LLPreviewNotecard*)LLPreview::find(mSourceID);
2961 if(card)
2962 {
2963 items.put((LLInventoryItem*)card->getDragItem());
2964 }
2965 }
2966 if(items.count()) return items[0];
2967 if(cats.count()) return cats[0];
2968 return NULL;
2969}
2970*/
2971
2972void LLToolDragAndDrop::createContainer(LLViewerInventoryItem::item_array_t &items, const char* preferred_name )
2973{
2974 llwarns << "LLToolDragAndDrop::createContainer()" << llendl;
2975 return;
2976}
2977
2978
2979// utility functions
2980
2981void pack_permissions_slam(LLMessageSystem* msg, U32 flags, const LLPermissions& perms)
2982{
2983 U32 group_mask = perms.getMaskGroup();
2984 U32 everyone_mask = perms.getMaskEveryone();
2985 U32 next_owner_mask = perms.getMaskNextOwner();
2986
2987 msg->addU32Fast(_PREHASH_ItemFlags, flags);
2988 msg->addU32Fast(_PREHASH_GroupMask, group_mask);
2989 msg->addU32Fast(_PREHASH_EveryoneMask, everyone_mask);
2990 msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_mask);
2991}