lltooldraganddrop.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "message.h"
00035 #include "lltooldraganddrop.h"
00036 
00037 #include "llinstantmessage.h"
00038 #include "lldir.h"
00039 
00040 #include "llagent.h"
00041 #include "llviewercontrol.h"
00042 #include "llfirstuse.h"
00043 #include "llfloater.h"
00044 #include "llfloatertools.h"
00045 #include "llgesturemgr.h"
00046 #include "llhudeffecttrail.h"
00047 #include "llhudmanager.h"
00048 #include "llinventorymodel.h"
00049 #include "llinventoryview.h"
00050 #include "llmutelist.h"
00051 #include "llnotify.h"
00052 #include "llpreviewnotecard.h"
00053 #include "llselectmgr.h"
00054 #include "lltoolmgr.h"
00055 #include "llui.h"
00056 #include "llviewerimagelist.h"
00057 #include "llviewerinventory.h"
00058 #include "llviewerobject.h"
00059 #include "llviewerobjectlist.h"
00060 #include "llviewerregion.h"
00061 #include "llviewerstats.h"
00062 #include "llviewerwindow.h"
00063 #include "llvoavatar.h"
00064 #include "llvolume.h"
00065 #include "llworld.h"
00066 #include "object_flags.h"
00067 
00068 
00069 // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
00070 // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
00071 // bit from there to give some pad.
00072 const S32 MAX_ITEMS = 42;
00073 const char* FOLDER_INCLUDES_ATTACHMENTS_BEING_WORN = 
00074                                 "Cannot give folders that contain objects that are attached to you.\n"
00075                                 "Detach the object(s) and then try again.";
00076 
00077 
00078 // syntactic sugar
00079 #define callMemberFunction(object,ptrToMember)  ((object).*(ptrToMember))
00080 
00081 class LLNoPreferredType : public LLInventoryCollectFunctor
00082 {
00083 public:
00084         LLNoPreferredType() {}
00085         virtual ~LLNoPreferredType() {}
00086         virtual bool operator()(LLInventoryCategory* cat,
00087                                                         LLInventoryItem* item)
00088         {
00089                 if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE))
00090                 {
00091                         return true;
00092                 }
00093                 return false;
00094         }
00095 };
00096 
00097 class LLNoPreferredTypeOrItem : public LLInventoryCollectFunctor
00098 {
00099 public:
00100         LLNoPreferredTypeOrItem() {}
00101         virtual ~LLNoPreferredTypeOrItem() {}
00102         virtual bool operator()(LLInventoryCategory* cat,
00103                                                         LLInventoryItem* item)
00104         {
00105                 if(item) return true;
00106                 if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE))
00107                 {
00108                         return true;
00109                 }
00110                 return false;
00111         }
00112 };
00113 
00114 class LLDroppableItem : public LLInventoryCollectFunctor
00115 {
00116 public:
00117         LLDroppableItem(BOOL is_transfer) :
00118                 mCountLosing(0), mIsTransfer(is_transfer) {}
00119         virtual ~LLDroppableItem() {}
00120         virtual bool operator()(LLInventoryCategory* cat,
00121                                                         LLInventoryItem* item);
00122         S32 countNoCopy() const { return mCountLosing; }
00123 
00124 protected:
00125         S32 mCountLosing;
00126         BOOL mIsTransfer;
00127 };
00128 
00129 bool LLDroppableItem::operator()(LLInventoryCategory* cat,
00130                                                                  LLInventoryItem* item)
00131 {
00132         bool allowed = false;
00133         if(item)
00134         {
00135                 LLVOAvatar* my_avatar = NULL;
00136                 switch(item->getType())
00137                 {
00138                 case LLAssetType::AT_CALLINGCARD:
00139                         // not allowed
00140                         break;
00141 
00142                 case LLAssetType::AT_OBJECT:
00143                         my_avatar = gAgent.getAvatarObject();
00144                         if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
00145                         {
00146                                 allowed = true;
00147                         }
00148                         break;
00149 
00150                 case LLAssetType::AT_BODYPART:
00151                 case LLAssetType::AT_CLOTHING:
00152                         if(!gAgent.isWearingItem(item->getUUID()))
00153                         {
00154                                 allowed = true;
00155                         }
00156                         break;
00157 
00158                 default:
00159                         allowed = true;
00160                         break;
00161                 }
00162                 if(mIsTransfer
00163                    && !item->getPermissions().allowOperationBy(PERM_TRANSFER,
00164                                                                                                            gAgent.getID()))
00165                 {
00166                         allowed = false;
00167                 }
00168                 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
00169                 {
00170                         ++mCountLosing;
00171                 }
00172         }
00173         return allowed;
00174 }
00175 
00176 class LLUncopyableItems : public LLInventoryCollectFunctor
00177 {
00178 public:
00179         LLUncopyableItems() {}
00180         virtual ~LLUncopyableItems() {}
00181         virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
00182 };
00183 
00184 bool LLUncopyableItems::operator()(LLInventoryCategory* cat,
00185                                                                    LLInventoryItem* item)
00186 {
00187         BOOL uncopyable = FALSE;
00188         if(item)
00189         {
00190                 BOOL allowed = FALSE;
00191                 LLVOAvatar* my_avatar = NULL;
00192                 switch(item->getType())
00193                 {
00194                 case LLAssetType::AT_CALLINGCARD:
00195                         // not allowed
00196                         break;
00197 
00198                 case LLAssetType::AT_OBJECT:
00199                         my_avatar = gAgent.getAvatarObject();
00200                         if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
00201                         {
00202                                 allowed = TRUE;
00203                         }
00204                         break;
00205 
00206                 case LLAssetType::AT_BODYPART:
00207                 case LLAssetType::AT_CLOTHING:
00208                         if(!gAgent.isWearingItem(item->getUUID()))
00209                         {
00210                                 allowed = TRUE;
00211                         }
00212                         break;
00213 
00214                 default:
00215                         allowed = TRUE;
00216                         break;
00217                 }
00218                 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
00219                 {
00220                         uncopyable = TRUE;
00221                 }
00222         }
00223         return (uncopyable ? true : false);
00224 }
00225 
00226 class LLDropCopyableItems : public LLInventoryCollectFunctor
00227 {
00228 public:
00229         LLDropCopyableItems() {}
00230         virtual ~LLDropCopyableItems() {}
00231         virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
00232 };
00233 
00234 
00235 bool LLDropCopyableItems::operator()(
00236         LLInventoryCategory* cat, LLInventoryItem* item)
00237 {
00238         BOOL allowed = FALSE;
00239         if(item)
00240         {
00241                 LLVOAvatar* my_avatar = NULL;
00242                 switch(item->getType())
00243                 {
00244                 case LLAssetType::AT_CALLINGCARD:
00245                         // not allowed
00246                         break;
00247 
00248                 case LLAssetType::AT_OBJECT:
00249                         my_avatar = gAgent.getAvatarObject();
00250                         if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
00251                         {
00252                                 allowed = TRUE;
00253                         }
00254                         break;
00255 
00256                 case LLAssetType::AT_BODYPART:
00257                 case LLAssetType::AT_CLOTHING:
00258                         if(!gAgent.isWearingItem(item->getUUID()))
00259                         {
00260                                 allowed = TRUE;
00261                         }
00262                         break;
00263 
00264                 default:
00265                         allowed = TRUE;
00266                         break;
00267                 }
00268                 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
00269                 {
00270                         // whoops, can't copy it - don't allow it.
00271                         allowed = FALSE;
00272                 }
00273         }
00274         return (allowed ? true : false);
00275 }
00276 
00277 class LLGiveable : public LLInventoryCollectFunctor
00278 {
00279 public:
00280         LLGiveable() : mCountLosing(0) {}
00281         virtual ~LLGiveable() {}
00282         virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
00283 
00284         S32 countNoCopy() const { return mCountLosing; }
00285 protected:
00286         S32 mCountLosing;
00287 };
00288 
00289 bool LLGiveable::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
00290 {
00291         // All categories can be given.
00292         if(cat) return TRUE;
00293         BOOL allowed = FALSE;
00294         if(item)
00295         {
00296                 LLVOAvatar* my_avatar = NULL;
00297                 switch(item->getType())
00298                 {
00299                 case LLAssetType::AT_CALLINGCARD:
00300                         // not allowed
00301                         break;
00302 
00303                 case LLAssetType::AT_OBJECT:
00304                         my_avatar = gAgent.getAvatarObject();
00305                         if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
00306                         {
00307                                 allowed = TRUE;
00308                         }
00309                         break;
00310 
00311                 case LLAssetType::AT_BODYPART:
00312                 case LLAssetType::AT_CLOTHING:
00313                         if(!gAgent.isWearingItem(item->getUUID()))
00314                         {
00315                                 allowed = TRUE;
00316                         }
00317                         break;
00318 
00319                 default:
00320                         allowed = TRUE;
00321                         break;
00322                 }
00323                 if(!item->getPermissions().allowOperationBy(PERM_TRANSFER,
00324                                                                                                         gAgent.getID()))
00325                 {
00326                         allowed = FALSE;
00327                 }
00328                 if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
00329                 {
00330                         ++mCountLosing;
00331                 }
00332         }
00333         return (allowed ? true : false);
00334 }
00335 
00336 class LLCategoryFireAndForget : public LLInventoryFetchComboObserver
00337 {
00338 public:
00339         LLCategoryFireAndForget() {}
00340         ~LLCategoryFireAndForget() {}
00341         virtual void done()
00342         {
00343                 /* no-op: it's fire n forget right? */
00344                 lldebugs << "LLCategoryFireAndForget::done()" << llendl;
00345         }
00346 };
00347 
00348 class LLCategoryDropObserver : public LLInventoryFetchObserver
00349 {
00350 public:
00351         LLCategoryDropObserver(
00352                 const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
00353                 mObjectID(obj_id),
00354                 mSource(src)
00355         {}
00356         ~LLCategoryDropObserver() {}
00357         virtual void done();
00358 
00359 protected:
00360         LLUUID mObjectID;
00361         LLToolDragAndDrop::ESource mSource;
00362 };
00363 
00364 void LLCategoryDropObserver::done()
00365 {
00366         gInventory.removeObserver(this);
00367         LLViewerObject* dst_obj = gObjectList.findObject(mObjectID);
00368         if(dst_obj)
00369         {
00370                 // *FIX: coalesce these...
00371                 LLInventoryItem* item = NULL;
00372                 item_ref_t::iterator it = mComplete.begin();
00373                 item_ref_t::iterator end = mComplete.end();
00374                 for(; it < end; ++it)
00375                 {
00376                         item = gInventory.getItem(*it);
00377                         if(item)
00378                         {
00379                                 LLToolDragAndDrop::dropInventory(
00380                                         dst_obj,
00381                                         item,
00382                                         mSource,
00383                                         LLUUID::null);
00384                         }
00385                 }
00386         }
00387         delete this;
00388 }
00389 
00390 class LLCategoryDropDescendentsObserver : public LLInventoryFetchDescendentsObserver
00391 {
00392 public:
00393         LLCategoryDropDescendentsObserver(
00394                 const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
00395                 mObjectID(obj_id),
00396                 mSource(src)
00397         {}
00398         ~LLCategoryDropDescendentsObserver() {}
00399         virtual void done();
00400 
00401 protected:
00402         LLUUID mObjectID;
00403         LLToolDragAndDrop::ESource mSource;
00404 };
00405 
00406 void LLCategoryDropDescendentsObserver::done()
00407 {
00408 
00409         gInventory.removeObserver(this);
00410         folder_ref_t::iterator it = mCompleteFolders.begin();
00411         folder_ref_t::iterator end = mCompleteFolders.end();
00412         LLViewerInventoryCategory::cat_array_t cats;
00413         LLViewerInventoryItem::item_array_t items;
00414         for(; it != end; ++it)
00415         {
00416                 gInventory.collectDescendents(
00417                         (*it),
00418                         cats,
00419                         items,
00420                         LLInventoryModel::EXCLUDE_TRASH);
00421         }
00422 
00423         S32 count = items.count();
00424         if(count)
00425         {
00426                 std::set<LLUUID> unique_ids;
00427                 for(S32 i = 0; i < count; ++i)
00428                 {
00429                         unique_ids.insert(items.get(i)->getUUID());
00430                 }
00431                 LLInventoryFetchObserver::item_ref_t ids;
00432                 std::back_insert_iterator<LLInventoryFetchObserver::item_ref_t> copier(ids);
00433                 std::copy(unique_ids.begin(), unique_ids.end(), copier);
00434                 LLCategoryDropObserver* dropper;
00435                 dropper = new LLCategoryDropObserver(mObjectID, mSource);
00436                 dropper->fetchItems(ids);
00437                 if(dropper->isEverythingComplete())
00438                 {
00439                         dropper->done();
00440                 }
00441                 else
00442                 {
00443                         gInventory.addObserver(dropper);
00444                 }
00445         }
00446         delete this;
00447 }
00448 
00449 // This array is used to more easily control what happens when a 3d
00450 // drag and drop event occurs. Since there's an array of drop target
00451 // and cargo type, it's implemented as an array of pointers to member
00452 // functions which correctly carry out the actual drop.
00453 LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT][LLToolDragAndDrop::DT_COUNT] =
00454 {
00455         //      Source: DAD_NONE
00456         {
00457                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00458                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00459                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
00460                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
00461                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
00462         },
00463         //      Source: DAD_TEXTURE
00464         {
00465                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00466                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00467                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00468                 &LLToolDragAndDrop::dad3dTextureObject, // Dest: DT_OBJECT
00469                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00470         },
00471         //      Source: DAD_SOUND
00472         {
00473                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00474                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00475                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00476                 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
00477                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00478         },
00479         //      Source: DAD_CALLINGCARD
00480         {
00481                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00482                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00483                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
00484                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
00485                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
00486         },
00487         //      Source: DAD_LANDMARK
00488         {
00489                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00490                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00491                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00492                 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
00493                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00494         },
00495         //      Source: DAD_SCRIPT
00496         {
00497                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00498                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00499                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00500                 &LLToolDragAndDrop::dad3dRezScript, // Dest: DT_OBJECT
00501                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00502         },
00503         //      Source: DAD_CLOTHING
00504         {
00505                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00506                 &LLToolDragAndDrop::dad3dWearItem, // Dest: DT_SELF
00507                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00508                 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
00509                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00510         },
00511         //      Source: DAD_OBJECT
00512         {
00513                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00514                 &LLToolDragAndDrop::dad3dRezAttachmentFromInv, // Dest: DT_SELF
00515                 &LLToolDragAndDrop::dad3dGiveInventoryObject, // Dest: DT_AVATAR
00516                 &LLToolDragAndDrop::dad3dRezObjectOnObject, // Dest: DT_OBJECT
00517                 &LLToolDragAndDrop::dad3dRezObjectOnLand, // Dest: DT_LAND
00518         },
00519         //      Source: DAD_NOTECARD
00520         {
00521                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00522                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00523                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00524                 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
00525                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00526         },
00527         //      Source: DAD_CATEGORY
00528         {
00529                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00530                 &LLToolDragAndDrop::dad3dWearCategory, // Dest: DT_SELF
00531                 &LLToolDragAndDrop::dad3dGiveInventoryCategory, // Dest: DT_AVATAR
00532                 &LLToolDragAndDrop::dad3dUpdateInventoryCategory, // Dest: DT_OBJECT
00533                 &LLToolDragAndDrop::dad3dNULL,//dad3dCategoryOnLand, // Dest: DT_LAND
00534         },
00535         //      Source: DAD_ROOT
00536         {
00537                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00538                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00539                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR
00540                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
00541                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND
00542         },
00543         //      Source: DAD_BODYPART
00544         {
00545                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00546                 &LLToolDragAndDrop::dad3dWearItem, // Dest: DT_SELF
00547                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00548                 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
00549                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00550         },
00551         //      Source: DAD_ANIMATION
00552         // TODO: animation on self could play it?  edit it?
00553         {
00554                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00555                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
00556                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00557                 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
00558                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00559         },
00560         //      Source: DAD_GESTURE
00561         // TODO: gesture on self could play it?  edit it?
00562         {
00563                 &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
00564                 &LLToolDragAndDrop::dad3dActivateGesture, // Dest: DT_SELF
00565                 &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
00566                 &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
00567                 &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
00568         },
00569 };
00570 
00571 LLToolDragAndDrop::LLToolDragAndDrop()
00572          :
00573          LLTool("draganddrop", NULL),
00574          mDragStartX(0),
00575          mDragStartY(0),
00576          mSource(SOURCE_AGENT),
00577          mCursor(UI_CURSOR_NO),
00578          mLastAccept(ACCEPT_NO),
00579          mDrop(FALSE),
00580          mCurItemIndex(0)
00581 {
00582 
00583 }
00584 
00585 void LLToolDragAndDrop::setDragStart(S32 x, S32 y)
00586 {
00587         mDragStartX = x;
00588         mDragStartY = y;
00589 }
00590 
00591 BOOL LLToolDragAndDrop::isOverThreshold(S32 x,S32 y)
00592 {
00593         const S32 MIN_MANHATTAN_DIST = 3;
00594         S32 manhattan_dist = llabs( x - mDragStartX ) + llabs( y - mDragStartY );
00595         return manhattan_dist >= MIN_MANHATTAN_DIST;
00596 }
00597 
00598 void LLToolDragAndDrop::beginDrag(EDragAndDropType type,
00599                                                                   const LLUUID& cargo_id,
00600                                                                   ESource source,
00601                                                                   const LLUUID& source_id,
00602                                                                   const LLUUID& object_id)
00603 {
00604         if(type == DAD_NONE)
00605         {
00606                 llwarns << "Attempted to start drag without a cargo type" << llendl;
00607                 return;
00608         }
00609         mCargoTypes.clear();
00610         mCargoTypes.push_back(type);
00611         mCargoIDs.clear();
00612         mCargoIDs.push_back(cargo_id);
00613         mSource = source;
00614         mSourceID = source_id;
00615         mObjectID = object_id;
00616 
00617         setMouseCapture( TRUE );
00618         LLToolMgr::getInstance()->setTransientTool( this );
00619         mCursor = UI_CURSOR_NO;
00620         if((mCargoTypes[0] == DAD_CATEGORY)
00621            && ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)))
00622         {
00623                 LLInventoryCategory* cat = gInventory.getCategory(cargo_id);
00624                 // go ahead and fire & forget the descendents if we are not
00625                 // dragging a protected folder.
00626                 if(cat)
00627                 {
00628                         LLViewerInventoryCategory::cat_array_t cats;
00629                         LLViewerInventoryItem::item_array_t items;
00630                         LLNoPreferredTypeOrItem is_not_preferred;
00631                         LLInventoryFetchComboObserver::folder_ref_t folder_ids;
00632                         LLInventoryFetchComboObserver::item_ref_t item_ids;
00633                         if(is_not_preferred(cat, NULL))
00634                         {
00635                                 folder_ids.push_back(cargo_id);
00636                         }
00637                         gInventory.collectDescendentsIf(
00638                                 cargo_id,
00639                                 cats,
00640                                 items,
00641                                 LLInventoryModel::EXCLUDE_TRASH,
00642                                 is_not_preferred);
00643                         S32 count = cats.count();
00644                         S32 i;
00645                         for(i = 0; i < count; ++i)
00646                         {
00647                                 folder_ids.push_back(cats.get(i)->getUUID());
00648                         }
00649                         count = items.count();
00650                         for(i = 0; i < count; ++i)
00651                         {
00652                                 item_ids.push_back(items.get(i)->getUUID());
00653                         }
00654                         if(!folder_ids.empty() || !item_ids.empty())
00655                         {
00656                                 LLCategoryFireAndForget fetcher;
00657                                 fetcher.fetch(folder_ids, item_ids);
00658                         }
00659                 }
00660         }
00661 }
00662 
00663 void LLToolDragAndDrop::beginMultiDrag(
00664         const std::vector<EDragAndDropType> types,
00665         const std::vector<LLUUID>& cargo_ids,
00666         ESource source,
00667         const LLUUID& source_id)
00668 {
00669         // assert on public api is evil
00670         //llassert( type != DAD_NONE );
00671 
00672         std::vector<EDragAndDropType>::const_iterator types_it;
00673         for (types_it = types.begin(); types_it != types.end(); ++types_it)
00674         {
00675                 if(DAD_NONE == *types_it)
00676                 {
00677                         llwarns << "Attempted to start drag without a cargo type" << llendl;
00678                         return;
00679                 }
00680         }
00681         mCargoTypes = types;
00682         mCargoIDs = cargo_ids;
00683         mSource = source;
00684         mSourceID = source_id;
00685 
00686         setMouseCapture( TRUE );
00687         LLToolMgr::getInstance()->setTransientTool( this );
00688         mCursor = UI_CURSOR_NO;
00689         if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
00690         {
00691                 // find cats in the cargo.
00692                 LLInventoryCategory* cat = NULL;
00693                 S32 count = llmin(cargo_ids.size(), types.size());
00694                 std::set<LLUUID> cat_ids;
00695                 for(S32 i = 0; i < count; ++i)
00696                 {
00697                         cat = gInventory.getCategory(cargo_ids[i]);
00698                         if(cat)
00699                         {
00700                                 LLViewerInventoryCategory::cat_array_t cats;
00701                                 LLViewerInventoryItem::item_array_t items;
00702                                 LLNoPreferredType is_not_preferred;
00703                                 if(is_not_preferred(cat, NULL))
00704                                 {
00705                                         cat_ids.insert(cat->getUUID());
00706                                 }
00707                                 gInventory.collectDescendentsIf(
00708                                         cat->getUUID(),
00709                                         cats,
00710                                         items,
00711                                         LLInventoryModel::EXCLUDE_TRASH,
00712                                         is_not_preferred);
00713                                 S32 cat_count = cats.count();
00714                                 for(S32 i = 0; i < cat_count; ++i)
00715                                 {
00716                                         cat_ids.insert(cat->getUUID());
00717                                 }
00718                         }
00719                 }
00720                 if(!cat_ids.empty())
00721                 {
00722                         LLInventoryFetchComboObserver::folder_ref_t folder_ids;
00723                         LLInventoryFetchComboObserver::item_ref_t item_ids;
00724                         std::back_insert_iterator<LLInventoryFetchDescendentsObserver::folder_ref_t> copier(folder_ids);
00725                         std::copy(cat_ids.begin(), cat_ids.end(), copier);
00726                         LLCategoryFireAndForget fetcher;
00727                         fetcher.fetch(folder_ids, item_ids);
00728                 }
00729         }
00730 }
00731 
00732 void LLToolDragAndDrop::endDrag()
00733 {
00734         LLSelectMgr::getInstance()->unhighlightAll();
00735         setMouseCapture(FALSE);
00736 }
00737 
00738 void LLToolDragAndDrop::onMouseCaptureLost()
00739 {
00740         // Called whenever the drag ends or if mouse captue is simply lost
00741         LLToolMgr::getInstance()->clearTransientTool();
00742         mCargoTypes.clear();
00743         mCargoIDs.clear();
00744         mSource = SOURCE_AGENT;
00745         mSourceID.setNull();
00746         mObjectID.setNull();
00747 }
00748 
00749 BOOL LLToolDragAndDrop::handleMouseUp( S32 x, S32 y, MASK mask )
00750 {
00751         if( hasMouseCapture() )
00752         {
00753                 EAcceptance acceptance = ACCEPT_NO;
00754                 dragOrDrop( x, y, mask, TRUE, &acceptance );
00755                 endDrag();
00756         }
00757         return TRUE;
00758 }
00759 
00760 BOOL LLToolDragAndDrop::handleHover( S32 x, S32 y, MASK mask )
00761 {
00762         EAcceptance acceptance = ACCEPT_NO;
00763         dragOrDrop( x, y, mask, FALSE, &acceptance );
00764 
00765         switch( acceptance )
00766         {
00767         case ACCEPT_YES_MULTI:
00768                 if (mCargoIDs.size() > 1)
00769                 {
00770                         mCursor = UI_CURSOR_ARROWDRAGMULTI;
00771                 }
00772                 else
00773                 {
00774                         mCursor = UI_CURSOR_ARROWDRAG;
00775                 }
00776                 break;
00777         case ACCEPT_YES_SINGLE: 
00778                 mCursor = UI_CURSOR_ARROWDRAG;
00779                 break;
00780 
00781         case ACCEPT_NO_LOCKED:
00782                 mCursor = UI_CURSOR_NOLOCKED;
00783                 break;
00784 
00785         case ACCEPT_NO:
00786                 mCursor = UI_CURSOR_NO;
00787                 break;
00788 
00789         case ACCEPT_YES_COPY_MULTI:
00790                 if (mCargoIDs.size() > 1)
00791                 {
00792                         mCursor = UI_CURSOR_ARROWCOPYMULTI;
00793                 }
00794                 else
00795                 {
00796                         mCursor = UI_CURSOR_ARROWCOPY;
00797                 }
00798                 break;
00799         case ACCEPT_YES_COPY_SINGLE:
00800                 mCursor = UI_CURSOR_ARROWCOPY;
00801                 break;
00802         case ACCEPT_POSTPONED:
00803                 break;
00804         default:
00805                 llassert( FALSE );
00806         }
00807 
00808         gViewerWindow->getWindow()->setCursor( mCursor );
00809         lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolDragAndDrop" << llendl;
00810         return TRUE;
00811 }
00812 
00813 BOOL LLToolDragAndDrop::handleKey(KEY key, MASK mask)
00814 {
00815         if (key == KEY_ESCAPE)
00816         {
00817                 // cancel drag and drop operation
00818                 endDrag();
00819                 return TRUE;
00820         }
00821 
00822         return FALSE;
00823 }
00824 
00825 BOOL LLToolDragAndDrop::handleToolTip(S32 x, S32 y, LLString& msg, LLRect *sticky_rect_screen)
00826 {
00827         if (!mToolTipMsg.empty())
00828         {
00829                 msg = mToolTipMsg;
00830                 //*stick_rect_screen = gViewerWindow->getWindowRect();
00831                 return TRUE;
00832         }
00833         return FALSE;
00834 }
00835 
00836 void LLToolDragAndDrop::handleDeselect()
00837 {
00838         mToolTipMsg.clear();
00839 }
00840 
00841 // protected
00842 void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, 
00843                                                                    EAcceptance* acceptance)
00844 {
00845         *acceptance = ACCEPT_YES_MULTI;
00846 
00847         BOOL handled = FALSE;
00848 
00849         LLView* top_view = gViewerWindow->getTopCtrl();
00850         LLViewerInventoryItem* item;
00851         LLViewerInventoryCategory* cat;
00852 
00853         mToolTipMsg.assign("");
00854 
00855         if(top_view)
00856         {
00857                 handled = TRUE;
00858 
00859                 for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
00860                 {
00861                         LLInventoryObject* cargo = locateInventory(item, cat);
00862 
00863                         if (cargo)
00864                         {
00865                                 S32 local_x, local_y;
00866                                 top_view->screenPointToLocal( x, y, &local_x, &local_y );
00867                                 EAcceptance item_acceptance = ACCEPT_NO;
00868                                 handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE,
00869                                                                                                         mCargoTypes[mCurItemIndex],
00870                                                                                                         (void*)cargo,
00871                                                                                                         &item_acceptance,
00872                                                                                                         mToolTipMsg);
00873                                 if (handled)
00874                                 {
00875                                         // use sort order to determine priority of acceptance
00876                                         *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
00877                                 }
00878                         }
00879                         else
00880                         {
00881                                 return;         
00882                         }
00883                 }
00884 
00885                 // all objects passed, go ahead and perform drop if necessary
00886                 if (handled && drop && (U32)*acceptance >= ACCEPT_YES_COPY_SINGLE)
00887                 {
00888                         // drop all items
00889                         if ((U32)*acceptance >= ACCEPT_YES_COPY_MULTI)
00890                         {
00891                                 mCurItemIndex = 0;
00892                         }
00893                         // drop just last item
00894                         else
00895                         {
00896                                 mCurItemIndex = mCargoIDs.size() - 1;
00897                         }
00898                         for (; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
00899                         {
00900                                 LLInventoryObject* cargo = locateInventory(item, cat);
00901 
00902                                 if (cargo)
00903                                 {
00904                                         S32 local_x, local_y;
00905 
00906                                         EAcceptance item_acceptance;
00907                                         top_view->screenPointToLocal( x, y, &local_x, &local_y );
00908                                         handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, TRUE,
00909                                                                                                                 mCargoTypes[mCurItemIndex],
00910                                                                                                                 (void*)cargo,
00911                                                                                                                 &item_acceptance,
00912                                                                                                                 mToolTipMsg);
00913                                 }
00914                         }
00915                 }
00916                 if (handled)
00917                 {
00918                         mLastAccept = (EAcceptance)*acceptance;
00919                 }
00920         }
00921 
00922         if(!handled)
00923         {
00924                 handled = TRUE;
00925 
00926                 LLView* root_view = gViewerWindow->getRootView();
00927 
00928                 for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
00929                 {
00930                         LLInventoryObject* cargo = locateInventory(item, cat);
00931 
00932                         EAcceptance item_acceptance = ACCEPT_NO;
00933                         handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE,
00934                                                                                                 mCargoTypes[mCurItemIndex],
00935                                                                                                 (void*)cargo,
00936                                                                                                 &item_acceptance,
00937                                                                                                 mToolTipMsg);
00938                         if (handled)
00939                         {
00940                                 // use sort order to determine priority of acceptance
00941                                 *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
00942                         }
00943                 }
00944                 // all objects passed, go ahead and perform drop if necessary
00945                 if (handled && drop && (U32)*acceptance > ACCEPT_NO_LOCKED)
00946                 {       
00947                         // drop all items
00948                         if ((U32)*acceptance >= ACCEPT_YES_COPY_MULTI)
00949                         {
00950                                 mCurItemIndex = 0;
00951                         }
00952                         // drop just last item
00953                         else
00954                         {
00955                                 mCurItemIndex = mCargoIDs.size() - 1;
00956                         }
00957                         for (; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
00958                         {
00959                                 LLInventoryObject* cargo = locateInventory(item, cat);
00960 
00961                                 if (cargo)
00962                                 {
00963                                         //S32 local_x, local_y;
00964 
00965                                         EAcceptance item_acceptance;
00966                                         handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE,
00967                                                                                                                 mCargoTypes[mCurItemIndex],
00968                                                                                                                 (void*)cargo,
00969                                                                                                                 &item_acceptance,
00970                                                                                                                 mToolTipMsg);
00971                                 }
00972                         }
00973                 }
00974 
00975                 if (handled)
00976                 {
00977                         mLastAccept = (EAcceptance)*acceptance;
00978                 }
00979         }
00980 
00981         if ( !handled )
00982         {
00983                 dragOrDrop3D( x, y, mask, drop, acceptance );
00984         }
00985 }
00986 
00987 void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* acceptance )
00988 {
00989         mDrop = drop;
00990         if (mDrop)
00991         {
00992                 gPickFaces = TRUE;
00993                 // don't allow drag and drop onto transparent objects
00994                 gViewerWindow->hitObjectOrLandGlobalImmediate(x, y, pickCallback, FALSE);
00995         }
00996         else
00997         {
00998                 // Don't pick faces during hover.  Nothing currently requires per-face
00999                 // data.
01000                 // don't allow drag and drop onto transparent objects
01001                 gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, pickCallback, FALSE);
01002         }
01003 
01004         *acceptance = mLastAccept;
01005 }
01006 
01007 void LLToolDragAndDrop::pickCallback(S32 x, S32 y, MASK mask)
01008 {
01009         EDropTarget target = DT_NONE;
01010         S32     hit_face = -1;
01011 
01012         LLViewerObject* hit_obj = gViewerWindow->lastNonFloraObjectHit();
01013         LLSelectMgr::getInstance()->unhighlightAll();
01014 
01015         // Treat attachments as part of the avatar they are attached to.
01016         if (hit_obj)
01017         {
01018                 if(hit_obj->isAttachment() && !hit_obj->isHUDAttachment())
01019                 {
01020                         LLVOAvatar* avatar = LLVOAvatar::findAvatarFromAttachment( hit_obj );
01021                         if( !avatar )
01022                         {
01023                                 LLToolDragAndDrop::getInstance()->mLastAccept = ACCEPT_NO;
01024                                 LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_NO;
01025                                 gViewerWindow->getWindow()->setCursor( LLToolDragAndDrop::getInstance()->mCursor );
01026                                 return;
01027                         }
01028                         
01029                         hit_obj = avatar;
01030                 }
01031 
01032                 if(hit_obj->isAvatar())
01033                 {
01034                         if(((LLVOAvatar*) hit_obj)->mIsSelf)
01035                         {
01036                                 target = DT_SELF;
01037                                 hit_face = -1;
01038                         }
01039                         else
01040                         {
01041                                 target = DT_AVATAR;
01042                                 hit_face = -1;
01043                         }
01044                 }
01045                 else
01046                 {
01047                         target = DT_OBJECT;
01048                         hit_face = gLastHitNonFloraObjectFace;
01049                         // if any item being dragged will be applied to the object under our cursor
01050                         // highlight that object
01051                         for (S32 i = 0; i < (S32)LLToolDragAndDrop::getInstance()->mCargoIDs.size(); i++)
01052                         {
01053                                 if (LLToolDragAndDrop::getInstance()->mCargoTypes[i] != DAD_OBJECT || (mask & MASK_CONTROL))
01054                                 {
01055                                         LLSelectMgr::getInstance()->highlightObjectAndFamily(hit_obj);
01056                                         break;
01057                                 }
01058                         }
01059                 }
01060         }
01061         else if(gLastHitLand)
01062         {
01063                 target = DT_LAND;
01064                 hit_face = -1;
01065         }
01066 
01067         LLToolDragAndDrop::getInstance()->mLastAccept = ACCEPT_YES_MULTI;
01068 
01069         for (LLToolDragAndDrop::getInstance()->mCurItemIndex = 0; LLToolDragAndDrop::getInstance()->mCurItemIndex < (S32)LLToolDragAndDrop::getInstance()->mCargoIDs.size(); 
01070                 LLToolDragAndDrop::getInstance()->mCurItemIndex++)
01071         {
01072                 // Call the right implementation function
01073                 LLToolDragAndDrop::getInstance()->mLastAccept = (EAcceptance)llmin(
01074                         (U32)LLToolDragAndDrop::getInstance()->mLastAccept,
01075                         (U32)callMemberFunction((*LLToolDragAndDrop::getInstance()), 
01076                                 LLToolDragAndDrop::getInstance()->sDragAndDrop3d[LLToolDragAndDrop::getInstance()->mCargoTypes[LLToolDragAndDrop::getInstance()->mCurItemIndex]][target])
01077                                 (hit_obj, hit_face, mask, FALSE));
01078         }
01079 
01080         if (LLToolDragAndDrop::getInstance()->mDrop && (U32)LLToolDragAndDrop::getInstance()->mLastAccept >= ACCEPT_YES_COPY_SINGLE)
01081         {
01082                 // if target allows multi-drop, go ahead and start iteration at beginning of cargo list
01083                 if (LLToolDragAndDrop::getInstance()->mLastAccept >= ACCEPT_YES_COPY_MULTI)
01084                 {
01085                         LLToolDragAndDrop::getInstance()->mCurItemIndex = 0;
01086                 }
01087                 // otherwise start at end, to follow selection rules (last selected item is most current)
01088                 else
01089                 {
01090                         LLToolDragAndDrop::getInstance()->mCurItemIndex = LLToolDragAndDrop::getInstance()->mCargoIDs.size() - 1;
01091                 }
01092 
01093                 for (; LLToolDragAndDrop::getInstance()->mCurItemIndex < (S32)LLToolDragAndDrop::getInstance()->mCargoIDs.size(); 
01094                         LLToolDragAndDrop::getInstance()->mCurItemIndex++)
01095                 {
01096                         // Call the right implementation function
01097                         (U32)callMemberFunction((*LLToolDragAndDrop::getInstance()), 
01098                                 LLToolDragAndDrop::getInstance()->sDragAndDrop3d[LLToolDragAndDrop::getInstance()->mCargoTypes[LLToolDragAndDrop::getInstance()->mCurItemIndex]][target])
01099                                 (hit_obj, hit_face, mask, TRUE);
01100                 }
01101         }
01102 
01103         switch( LLToolDragAndDrop::getInstance()->mLastAccept )
01104         {
01105         case ACCEPT_YES_MULTI: 
01106                 if (LLToolDragAndDrop::getInstance()->mCargoIDs.size() > 1)
01107                 {
01108                         LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_ARROWDRAGMULTI;
01109                 }
01110                 else
01111                 {
01112                         LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_ARROWDRAG;
01113                 }
01114                 break;
01115         case ACCEPT_YES_SINGLE: 
01116                 LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_ARROWDRAG;
01117                 break;
01118 
01119         case ACCEPT_NO_LOCKED:
01120                 LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_NOLOCKED;
01121                 break;
01122 
01123         case ACCEPT_NO:
01124                 LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_NO;
01125                 break;
01126 
01127         case ACCEPT_YES_COPY_MULTI:
01128         if (LLToolDragAndDrop::getInstance()->mCargoIDs.size() > 1)
01129                 {
01130                         LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_ARROWCOPYMULTI;
01131                 }
01132                 else
01133                 {
01134                         LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_ARROWCOPY;
01135                 }
01136                 break;
01137         case ACCEPT_YES_COPY_SINGLE:
01138                 LLToolDragAndDrop::getInstance()->mCursor = UI_CURSOR_ARROWCOPY;
01139                 break;
01140         case ACCEPT_POSTPONED:
01141                 break;
01142         default:
01143                 llassert( FALSE );
01144         }
01145 
01146         LLToolDragAndDrop::getInstance()->mLastHitPos = gLastHitPosGlobal + gLastHitObjectOffset;
01147         LLToolDragAndDrop::getInstance()->mLastCameraPos = gAgent.getCameraPositionGlobal();
01148 
01149         gViewerWindow->getWindow()->setCursor( LLToolDragAndDrop::getInstance()->mCursor );
01150 }
01151 
01152 // static
01153 BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
01154                                                                                                          LLInventoryItem* item,
01155                                                                                                          LLToolDragAndDrop::ESource source,
01156                                                                                                          const LLUUID& src_id)
01157 {
01158         // Always succeed if....
01159         // texture is from the library 
01160         // or already in the contents of the object
01161         if(SOURCE_LIBRARY == source)
01162         {
01163                 // dropping a texture from the library always just works.
01164                 return TRUE;
01165         }
01166 
01167         // In case the inventory has not been updated (e.g. due to some recent operation
01168         // causing a dirty inventory), stall the user while fetching the inventory.
01169         if (hit_obj->isInventoryDirty())
01170         {
01171                 hit_obj->fetchInventoryFromServer();
01172                 LLString::format_map_t args;
01173                 args["[ERROR_MESSAGE]"] = "Unable to add texture.\nPlease wait a few seconds and try again.";
01174                 gViewerWindow->alertXml("ErrorMessage", args);
01175                 return FALSE;
01176         }
01177         if (hit_obj->getInventoryItemByAsset(item->getAssetUUID()))
01178         {
01179                 // if the asset is already in the object's inventory 
01180                 // then it can always be added to a side.
01181                 // This saves some work if the task's inventory is already loaded
01182                 // and ensures that the texture item is only added once.
01183                 return TRUE;
01184         }
01185 
01186         if (!item) return FALSE;
01187         
01188         LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
01189         if(!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
01190         {
01191                 // Check that we can add the texture as inventory to the object
01192                 if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
01193                 {
01194                         return FALSE;
01195                 }
01196                 // make sure the object has the texture in it's inventory.
01197                 if(SOURCE_AGENT == source)
01198                 {
01199                         // Remove the texture from local inventory. The server
01200                         // will actually remove the item from agent inventory.
01201                         gInventory.deleteObject(item->getUUID());
01202                         gInventory.notifyObservers();
01203                 }
01204                 else if(SOURCE_WORLD == source)
01205                 {
01206                         // *FIX: if the objects are in different regions, and the
01207                         // source region has crashed, you can bypass these
01208                         // permissions.
01209                         LLViewerObject* src_obj = gObjectList.findObject(src_id);
01210                         if(src_obj)
01211                         {
01212                                 src_obj->removeInventory(item->getUUID());
01213                         }
01214                         else
01215                         {
01216                                 llwarns << "Unable to find source object." << llendl;
01217                                 return FALSE;
01218                         }
01219                 }
01220                 // Add the texture item to the target object's inventory.
01221                 hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
01222                 // TODO: Check to see if adding the item was successful; if not, then
01223                 // we should return false here.
01224         }
01225         else if(!item->getPermissions().allowOperationBy(PERM_TRANSFER,
01226                                                                                                          gAgent.getID()))
01227         {
01228                 // Check that we can add the testure as inventory to the object
01229                 if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
01230                 {
01231                         return FALSE;
01232                 }
01233                 // *FIX: may want to make sure agent can paint hit_obj.
01234 
01235                 // Add the texture item to the target object's inventory.
01236                 hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
01237                 // Force the object to update its refetch its inventory so it has this texture.
01238                 hit_obj->fetchInventoryFromServer();
01239                 // TODO: Check to see if adding the item was successful; if not, then
01240                 // we should return false here.
01241         }
01242         return TRUE;
01243 }
01244 
01245 void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
01246                                                                                         LLInventoryItem* item,
01247                                                                                         LLToolDragAndDrop::ESource source,
01248                                                                                         const LLUUID& src_id)
01249 {
01250         if (!item)
01251         {
01252                 llwarns << "LLToolDragAndDrop::dropTextureAllFaces no texture item." << llendl;
01253                 return;
01254         }
01255         LLUUID asset_id = item->getAssetUUID();
01256         BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
01257         if(!success)
01258         {
01259                 return;
01260         }
01261         LLViewerImage* image = gImageList.getImage(asset_id);
01262         LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
01263         S32 num_faces = hit_obj->getNumTEs();
01264         for( S32 face = 0; face < num_faces; face++ )
01265         {
01266 
01267                 // update viewer side image in anticipation of update from simulator
01268                 hit_obj->setTEImage(face, image);
01269                 dialog_refresh_all();
01270         }
01271         // send the update to the simulator
01272         hit_obj->sendTEUpdate();
01273 }
01274 
01275 /*
01276 void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
01277 {
01278         if (hit_face == -1) return;
01279         LLViewerImage* image = gImageList.getImage(item->getAssetUUID());
01280         
01281         avatar->userSetOptionalTE( hit_face, image);
01282 }
01283 */
01284 
01285 void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
01286                                                                                    S32 hit_face,
01287                                                                                    LLInventoryItem* item,
01288                                                                                    LLToolDragAndDrop::ESource source,
01289                                                                                    const LLUUID& src_id)
01290 {
01291         if (hit_face == -1) return;
01292         if (!item)
01293         {
01294                 llwarns << "LLToolDragAndDrop::dropTextureOneFace no texture item." << llendl;
01295                 return;
01296         }
01297         LLUUID asset_id = item->getAssetUUID();
01298         BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
01299         if(!success)
01300         {
01301                 return;
01302         }
01303         // update viewer side image in anticipation of update from simulator
01304         LLViewerImage* image = gImageList.getImage(asset_id);
01305         LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
01306         hit_obj->setTEImage(hit_face, image);
01307         dialog_refresh_all();
01308 
01309         // send the update to the simulator
01310         hit_obj->sendTEUpdate();
01311 }
01312 
01313 
01314 void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj,
01315                                                                    LLInventoryItem* item,
01316                                                                    BOOL active,
01317                                                                    ESource source,
01318                                                                    const LLUUID& src_id)
01319 {
01320         // *HACK: In order to resolve SL-22177, we need to block drags
01321         // from notecards and objects onto other objects.
01322         if((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource)
01323            || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource))
01324         {
01325                 llwarns << "Call to LLToolDragAndDrop::dropScript() from world"
01326                         << " or notecard." << llendl;
01327                 return;
01328         }
01329         if(hit_obj && item)
01330         {
01331                 LLPointer<LLViewerInventoryItem> new_script = new LLViewerInventoryItem(item);
01332                 if(!item->getPermissions().allowCopyBy(gAgent.getID()))
01333                 {
01334                         if(SOURCE_AGENT == source)
01335                         {
01336                                 // Remove the script from local inventory. The server
01337                                 // will actually remove the item from agent inventory.
01338                                 gInventory.deleteObject(item->getUUID());
01339                                 gInventory.notifyObservers();
01340                         }
01341                         else if(SOURCE_WORLD == source)
01342                         {
01343                                 // *FIX: if the objects are in different regions, and
01344                                 // the source region has crashed, you can bypass
01345                                 // these permissions.
01346                                 LLViewerObject* src_obj = gObjectList.findObject(src_id);
01347                                 if(src_obj)
01348                                 {
01349                                         src_obj->removeInventory(item->getUUID());
01350                                 }
01351                                 else
01352                                 {
01353                                         llwarns << "Unable to find source object." << llendl;
01354                                         return;
01355                                 }
01356                         }
01357                 }
01358                 hit_obj->saveScript(new_script, active, true);
01359                 gFloaterTools->dirty();
01360 
01361                 // VEFFECT: SetScript
01362                 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
01363                 effectp->setSourceObject(gAgent.getAvatarObject());
01364                 effectp->setTargetObject(hit_obj);
01365                 effectp->setDuration(LL_HUD_DUR_SHORT);
01366                 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
01367         }
01368 }
01369 
01370 void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
01371                                                                    BOOL bypass_sim_raycast,
01372                                                                    BOOL from_task_inventory,
01373                                                                    BOOL remove_from_inventory)
01374 {
01375         LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mLastHitPos);
01376         if (!regionp)
01377         {
01378                 llwarns << "Couldn't find region to rez object" << llendl;
01379                 return;
01380         }
01381 
01382         //llinfos << "Rezzing object" << llendl;
01383         make_ui_sound("UISndObjectRezIn");
01384         LLViewerInventoryItem* item;
01385         LLViewerInventoryCategory* cat;
01386         locateInventory(item, cat);
01387         if(!item || !item->isComplete()) return;
01388         
01389         if (regionp
01390                 && (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
01391         {
01392                 LLFirstUse::useSandbox();
01393         }
01394         // check if it cannot be copied, and mark as remove if it is -
01395         // this will remove the object from inventory after rez. Only
01396         // bother with this check if we would not normally remove from
01397         // inventory.
01398         if(!remove_from_inventory
01399                 && !item->getPermissions().allowCopyBy(gAgent.getID()))
01400         {
01401                 remove_from_inventory = TRUE;
01402         }
01403 
01404         // Limit raycast to a single object.  
01405         // Speeds up server raycast + avoid problems with server ray
01406         // hitting objects that were clipped by the near plane or culled
01407         // on the viewer.
01408         LLUUID ray_target_id;
01409         if( raycast_target )
01410         {
01411                 ray_target_id = raycast_target->getID();
01412         }
01413         else
01414         {
01415                 ray_target_id.setNull();
01416         }
01417 
01418         // Check if it's in the trash.
01419         bool is_in_trash = false;
01420         LLUUID trash_id;
01421         trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
01422         if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
01423         {
01424                 is_in_trash = true;
01425                 remove_from_inventory = TRUE;
01426         }
01427 
01428         LLUUID source_id = from_task_inventory ? mSourceID : LLUUID::null;
01429 
01430         // Select the object only if we're editing.
01431         BOOL rez_selected = LLToolMgr::getInstance()->inEdit();
01432 
01433 
01434         LLVector3 ray_start = regionp->getPosRegionFromGlobal(mLastCameraPos);
01435         LLVector3 ray_end   = regionp->getPosRegionFromGlobal(mLastHitPos);
01436         // currently the ray's end point is an approximation,
01437         // and is sometimes too short (causing failure.)  so we
01438         // double the ray's length:
01439         if (bypass_sim_raycast == FALSE)
01440         {
01441                 LLVector3 ray_direction = ray_start - ray_end;
01442                 ray_end = ray_end - ray_direction;
01443         }
01444         
01445         
01446         // Message packing code should be it's own uninterrupted block
01447         LLMessageSystem* msg = gMessageSystem;
01448         if (mSource == SOURCE_NOTECARD)
01449         {
01450                 msg->newMessageFast(_PREHASH_RezObjectFromNotecard);
01451         }
01452         else
01453         {
01454                 msg->newMessageFast(_PREHASH_RezObject);
01455         }
01456         msg->nextBlockFast(_PREHASH_AgentData);
01457         msg->addUUIDFast(_PREHASH_AgentID,  gAgent.getID());
01458         msg->addUUIDFast(_PREHASH_SessionID,  gAgent.getSessionID());
01459         msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
01460 
01461         msg->nextBlock("RezData");
01462         // if it's being rezzed from task inventory, we need to enable
01463         // saving it back into the task inventory.
01464         // *FIX: We can probably compress this to a single byte, since I
01465         // think folderid == mSourceID. This will be a later
01466         // optimization.
01467         msg->addUUIDFast(_PREHASH_FromTaskID, source_id);
01468         msg->addU8Fast(_PREHASH_BypassRaycast, (U8) bypass_sim_raycast);
01469         msg->addVector3Fast(_PREHASH_RayStart, ray_start);
01470         msg->addVector3Fast(_PREHASH_RayEnd, ray_end);
01471         msg->addUUIDFast(_PREHASH_RayTargetID, ray_target_id );
01472         msg->addBOOLFast(_PREHASH_RayEndIsIntersection, FALSE);
01473         msg->addBOOLFast(_PREHASH_RezSelected, rez_selected);
01474         msg->addBOOLFast(_PREHASH_RemoveItem, remove_from_inventory);
01475 
01476         // deal with permissions slam logic
01477         pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
01478 
01479         LLUUID folder_id = item->getParentUUID();
01480         if((SOURCE_LIBRARY == mSource) || (is_in_trash))
01481         {
01482                 // since it's coming from the library or trash, we want to not
01483                 // 'take' it back to the same place.
01484                 item->setParent(LLUUID::null);
01485                 // *TODO this code isn't working - the parent (FolderID) is still
01486                 // set when the object is "taken".  so code on the "take" side is
01487                 // checking for trash and library as well (llviewermenu.cpp)
01488         }
01489         if (mSource == SOURCE_NOTECARD)
01490         {
01491                 msg->nextBlockFast(_PREHASH_NotecardData);
01492                 msg->addUUIDFast(_PREHASH_NotecardItemID, mSourceID);
01493                 msg->addUUIDFast(_PREHASH_ObjectID, mObjectID);
01494                 msg->nextBlockFast(_PREHASH_InventoryData);
01495                 msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
01496         }
01497         else
01498         {
01499                 msg->nextBlockFast(_PREHASH_InventoryData);
01500                 item->packMessage(msg);
01501         }
01502         msg->sendReliable(regionp->getHost());
01503         // back out the change. no actual internal changes take place.
01504         item->setParent(folder_id); 
01505 
01506         // If we're going to select it, get ready for the incoming
01507         // selected object.
01508         if (rez_selected)
01509         {
01510                 LLSelectMgr::getInstance()->deselectAll();
01511                 gViewerWindow->getWindow()->incBusyCount();
01512         }
01513 
01514         if(remove_from_inventory)
01515         {
01516                 // Delete it from inventory immediately so that users cannot
01517                 // easily bypass copy protection in laggy situations. If the
01518                 // rez fails, we will put it back on the server.
01519                 gInventory.deleteObject(item->getUUID());
01520                 gInventory.notifyObservers();
01521         }
01522 
01523         // VEFFECT: DropObject
01524         LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
01525         effectp->setSourceObject(gAgent.getAvatarObject());
01526         effectp->setPositionGlobal(mLastHitPos);
01527         effectp->setDuration(LL_HUD_DUR_SHORT);
01528         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
01529 
01530         LLViewerStats::getInstance()->incStat(LLViewerStats::ST_REZ_COUNT);
01531 }
01532 
01533 void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj,
01534                                                                           LLInventoryItem* item,
01535                                                                           LLToolDragAndDrop::ESource source,
01536                                                                           const LLUUID& src_id)
01537 {
01538         // *HACK: In order to resolve SL-22177, we need to block drags
01539         // from notecards and objects onto other objects.
01540         if((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource)
01541            || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource))
01542         {
01543                 llwarns << "Call to LLToolDragAndDrop::dropInventory() from world"
01544                         << " or notecard." << llendl;
01545                 return;
01546         }
01547 
01548         LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
01549         S32 creation_date = time_corrected();
01550         new_item->setCreationDate(creation_date);
01551 
01552         if(!item->getPermissions().allowCopyBy(gAgent.getID()))
01553         {
01554                 if(SOURCE_AGENT == source)
01555                 {
01556                         // Remove the inventory item from local inventory. The
01557                         // server will actually remove the item from agent
01558                         // inventory.
01559                         gInventory.deleteObject(item->getUUID());
01560                         gInventory.notifyObservers();
01561                 }
01562                 else if(SOURCE_WORLD == source)
01563                 {
01564                         // *FIX: if the objects are in different regions, and the
01565                         // source region has crashed, you can bypass these
01566                         // permissions.
01567                         LLViewerObject* src_obj = gObjectList.findObject(src_id);
01568                         if(src_obj)
01569                         {
01570                                 src_obj->removeInventory(item->getUUID());
01571                         }
01572                         else
01573                         {
01574                                 llwarns << "Unable to find source object." << llendl;
01575                                 return;
01576                         }
01577                 }
01578         }
01579         hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
01580         if (gFloaterTools->getVisible())
01581         {
01582                 // *FIX: only show this if panel not expanded?
01583                 gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS);
01584         }
01585 
01586         // VEFFECT: AddToInventory
01587         LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
01588         effectp->setSourceObject(gAgent.getAvatarObject());
01589         effectp->setTargetObject(hit_obj);
01590         effectp->setDuration(LL_HUD_DUR_SHORT);
01591         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
01592         gFloaterTools->dirty();
01593 }
01594 
01595 struct LLGiveInventoryInfo
01596 {
01597         LLUUID mToAgentID;
01598         LLUUID mInventoryObjectID;
01599         LLGiveInventoryInfo(const LLUUID& to_agent, const LLUUID& obj_id) :
01600                 mToAgentID(to_agent), mInventoryObjectID(obj_id) {}
01601 };
01602 
01603 void LLToolDragAndDrop::giveInventory(const LLUUID& to_agent,
01604                                                                           LLInventoryItem* item)
01605 {
01606         llinfos << "LLToolDragAndDrop::giveInventory()" << llendl;
01607         if(!isInventoryGiveAcceptable(item))
01608         {
01609                 return;
01610         }
01611         if(item->getPermissions().allowCopyBy(gAgent.getID()))
01612         {
01613                 // just give it away.
01614                 LLToolDragAndDrop::commitGiveInventoryItem(to_agent, item);
01615         }
01616         else
01617         {
01618                 // ask if the agent is sure.
01619                 LLGiveInventoryInfo* info = new LLGiveInventoryInfo(to_agent,
01620                                                                                                                         item->getUUID());
01621 
01622                 gViewerWindow->alertXml("CannotCopyWarning",
01623                                                                   &LLToolDragAndDrop::handleCopyProtectedItem,
01624                                                                   (void*)info);
01625         }
01626 }
01627 
01628 // static
01629 void LLToolDragAndDrop::handleCopyProtectedItem(S32 option, void* data)
01630 {
01631         LLGiveInventoryInfo* info = (LLGiveInventoryInfo*)data;
01632         LLInventoryItem* item = NULL;
01633         switch(option)
01634         {
01635         case 0:  // "Yes"
01636                 item = gInventory.getItem(info->mInventoryObjectID);
01637                 if(item)
01638                 {
01639                         LLToolDragAndDrop::commitGiveInventoryItem(info->mToAgentID,
01640                                                                                                            item);
01641                         // delete it for now - it will be deleted on the server
01642                         // quickly enough.
01643                         gInventory.deleteObject(info->mInventoryObjectID);
01644                         gInventory.notifyObservers();
01645                 }
01646                 else
01647                 {
01648                         gViewerWindow->alertXml("CannotGiveItem");              
01649                 }
01650                 break;
01651 
01652         default: // no, cancel, whatever, who cares, not yes.
01653                 gViewerWindow->alertXml("TransactionCancelled");
01654                 break;
01655         }
01656 }
01657 
01658 // static
01659 void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent,
01660                                                                                                 LLInventoryItem* item)
01661 {
01662         if(!item) return;
01663         std::string name;
01664         gAgent.buildFullname(name);
01665         LLUUID transaction_id;
01666         transaction_id.generate();
01667         const S32 BUCKET_SIZE = sizeof(U8) + UUID_BYTES;
01668         U8 bucket[BUCKET_SIZE];
01669         bucket[0] = (U8)item->getType();
01670         memcpy(&bucket[1], &(item->getUUID().mData), UUID_BYTES);               /* Flawfinder: ignore */
01671         pack_instant_message(
01672                 gMessageSystem,
01673                 gAgent.getID(),
01674                 FALSE,
01675                 gAgent.getSessionID(),
01676                 to_agent,
01677                 name.c_str(),
01678                 item->getName().c_str(),
01679                 IM_ONLINE,
01680                 IM_INVENTORY_OFFERED,
01681                 transaction_id,
01682                 0,
01683                 LLUUID::null,
01684                 gAgent.getPositionAgent(),
01685                 NO_TIMESTAMP,
01686                 bucket,
01687                 BUCKET_SIZE);
01688         gAgent.sendReliableMessage(); 
01689 
01690         // VEFFECT: giveInventory
01691         LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
01692         effectp->setSourceObject(gAgent.getAvatarObject());
01693         effectp->setTargetObject(gObjectList.findObject(to_agent));
01694         effectp->setDuration(LL_HUD_DUR_SHORT);
01695         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
01696         gFloaterTools->dirty();
01697 
01698         LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
01699 }
01700 
01701 void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent,
01702                                                                                           LLInventoryCategory* cat)
01703 {
01704         if(!cat) return;
01705         llinfos << "LLToolDragAndDrop::giveInventoryCategory() - "
01706                         << cat->getUUID() << llendl;
01707 
01708         LLVOAvatar* my_avatar = gAgent.getAvatarObject();
01709         if( !my_avatar )
01710         {
01711                 return;
01712         }
01713 
01714         // Test out how many items are being given.
01715         LLViewerInventoryCategory::cat_array_t cats;
01716         LLViewerInventoryItem::item_array_t items;
01717         LLGiveable giveable;
01718         gInventory.collectDescendentsIf(cat->getUUID(),
01719                                                                         cats,
01720                                                                         items,
01721                                                                         LLInventoryModel::EXCLUDE_TRASH,
01722                                                                         giveable);
01723         S32 count = cats.count();
01724         bool complete = true;
01725         for(S32 i = 0; i < count; ++i)
01726         {
01727                 if(!gInventory.isCategoryComplete(cats.get(i)->getUUID()))
01728                 {
01729                         complete = false;
01730                         break;
01731                 }
01732         }
01733         if(!complete)
01734         {
01735                 LLNotifyBox::showXml("IncompleteInventory");
01736                 return;
01737         }
01738         count = items.count() + cats.count();
01739         if(count > MAX_ITEMS)
01740         {
01741                 gViewerWindow->alertXml("TooManyItems");
01742                 return;
01743         }
01744         else if(count == 0)
01745         {
01746                 gViewerWindow->alertXml("NoItems");
01747                 return;
01748         }
01749         else
01750         {
01751                 if(0 == giveable.countNoCopy())
01752                 {
01753                         LLToolDragAndDrop::commitGiveInventoryCategory(to_agent, cat);
01754                 }
01755                 else 
01756                 {
01757                         LLGiveInventoryInfo* info = NULL;
01758                         info = new LLGiveInventoryInfo(to_agent, cat->getUUID());
01759                         LLStringBase<char>::format_map_t args;
01760                         args["[COUNT]"] = llformat("%d",giveable.countNoCopy());
01761                         gViewerWindow->alertXml("CannotCopyCountItems", args,
01762                                 &LLToolDragAndDrop::handleCopyProtectedCategory,
01763                                 (void*)info);
01764                                 
01765                 }
01766         }
01767 }
01768 
01769 
01770 // static
01771 void LLToolDragAndDrop::handleCopyProtectedCategory(S32 option, void* data)
01772 {
01773         LLGiveInventoryInfo* info = (LLGiveInventoryInfo*)data;
01774         LLInventoryCategory* cat = NULL;
01775         switch(option)
01776         {
01777         case 0:  // "Yes"
01778                 cat = gInventory.getCategory(info->mInventoryObjectID);
01779                 if(cat)
01780                 {
01781                         LLToolDragAndDrop::commitGiveInventoryCategory(info->mToAgentID,
01782                                                                                                                    cat);
01783                         LLViewerInventoryCategory::cat_array_t cats;
01784                         LLViewerInventoryItem::item_array_t items;
01785                         LLUncopyableItems remove;
01786                         gInventory.collectDescendentsIf(cat->getUUID(),
01787                                                                                         cats,
01788                                                                                         items,
01789                                                                                         LLInventoryModel::EXCLUDE_TRASH,
01790                                                                                         remove);
01791                         S32 count = items.count();
01792                         for(S32 i = 0; i < count; ++i)
01793                         {
01794                                 gInventory.deleteObject(items.get(i)->getUUID());
01795                         }
01796                         gInventory.notifyObservers();
01797                 }
01798                 else
01799                 {
01800                         gViewerWindow->alertXml("CannotGiveCategory");
01801                 }
01802                 break;
01803 
01804         default: // no, cancel, whatever, who cares, not yes.
01805                 gViewerWindow->alertXml("TransactionCancelled");
01806                 break;
01807         }
01808 }
01809 
01810 // static
01811 void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent,
01812                                                                                                         LLInventoryCategory* cat)
01813 {
01814         if(!cat) return;
01815         llinfos << "LLToolDragAndDrop::commitGiveInventoryCategory() - "
01816                         << cat->getUUID() << llendl;
01817 
01818         // Test out how many items are being given.
01819         LLViewerInventoryCategory::cat_array_t cats;
01820         LLViewerInventoryItem::item_array_t items;
01821         LLGiveable giveable;
01822         gInventory.collectDescendentsIf(cat->getUUID(),
01823                                                                         cats,
01824                                                                         items,
01825                                                                         LLInventoryModel::EXCLUDE_TRASH,
01826                                                                         giveable);
01827 
01828         // MAX ITEMS is based on (sizeof(uuid)+2) * count must be <
01829         // MTUBYTES or 18 * count < 1200 => count < 1200/18 =>
01830         // 66. I've cut it down a bit from there to give some pad.
01831         S32 count = items.count() + cats.count();
01832         if(count > MAX_ITEMS)
01833         {
01834                 gViewerWindow->alertXml("TooManyItems");
01835                 return;
01836         }
01837         else if(count == 0)
01838         {
01839                 gViewerWindow->alertXml("NoItems");
01840                 return;
01841         }
01842         else
01843         {
01844                 std::string name;
01845                 gAgent.buildFullname(name);
01846                 LLUUID transaction_id;
01847                 transaction_id.generate();
01848                 S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1);
01849                 U8* bucket = new U8[bucket_size];
01850                 U8* pos = bucket;
01851                 U8 type = (U8)cat->getType();
01852                 memcpy(pos, &type, sizeof(U8));         /* Flawfinder: ignore */
01853                 pos += sizeof(U8);
01854                 memcpy(pos, &(cat->getUUID()), UUID_BYTES);             /* Flawfinder: ignore */
01855                 pos += UUID_BYTES;
01856                 S32 i;
01857                 count = cats.count();
01858                 for(i = 0; i < count; ++i)
01859                 {
01860                         memcpy(pos, &type, sizeof(U8));         /* Flawfinder: ignore */
01861                         pos += sizeof(U8);
01862                         memcpy(pos, &(cats.get(i)->getUUID()), UUID_BYTES);             /* Flawfinder: ignore */
01863                         pos += UUID_BYTES;
01864                 }
01865                 count = items.count();
01866                 for(i = 0; i < count; ++i)
01867                 {
01868                         type = (U8)items.get(i)->getType();
01869                         memcpy(pos, &type, sizeof(U8));         /* Flawfinder: ignore */
01870                         pos += sizeof(U8);
01871                         memcpy(pos, &(items.get(i)->getUUID()), UUID_BYTES);            /* Flawfinder: ignore */
01872                         pos += UUID_BYTES;
01873                 }
01874                 pack_instant_message(
01875                         gMessageSystem,
01876                         gAgent.getID(),
01877                         FALSE,
01878                         gAgent.getSessionID(),
01879                         to_agent,
01880                         name.c_str(),
01881                         cat->getName().c_str(),
01882                         IM_ONLINE,
01883                         IM_INVENTORY_OFFERED,
01884                         transaction_id,
01885                         0,
01886                         LLUUID::null,
01887                         gAgent.getPositionAgent(),
01888                         NO_TIMESTAMP,
01889                         bucket,
01890                         bucket_size);
01891                 gAgent.sendReliableMessage();
01892                 delete[] bucket;
01893 
01894                 // VEFFECT: giveInventoryCategory
01895                 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
01896                 effectp->setSourceObject(gAgent.getAvatarObject());
01897                 effectp->setTargetObject(gObjectList.findObject(to_agent));
01898                 effectp->setDuration(LL_HUD_DUR_SHORT);
01899                 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
01900                 gFloaterTools->dirty();
01901 
01902                 LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY);
01903         }
01904 }
01905 
01906 // static
01907 BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item)
01908 {
01909         if(!item)
01910         {
01911                 return FALSE;
01912         }
01913         if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
01914         {
01915                 return FALSE;
01916         }
01917         BOOL copyable = FALSE;
01918         if(item->getPermissions().allowCopyBy(gAgent.getID())) copyable = TRUE;
01919         LLVOAvatar* my_avatar = gAgent.getAvatarObject();
01920         if(!my_avatar)
01921         {
01922                 return FALSE;
01923         }
01924         BOOL acceptable = TRUE;
01925         switch(item->getType())
01926         {
01927         case LLAssetType::AT_CALLINGCARD:
01928                 acceptable = FALSE;
01929                 break;
01930         case LLAssetType::AT_OBJECT:
01931                 if(my_avatar->isWearingAttachment(item->getUUID()))
01932                 {
01933                         acceptable = FALSE;
01934                 }
01935                 break;
01936         case LLAssetType::AT_BODYPART:
01937         case LLAssetType::AT_CLOTHING:
01938                 if(!copyable && gAgent.isWearingItem(item->getUUID()))
01939                 {
01940                         acceptable = FALSE;
01941                 }
01942                 break;
01943         default:
01944                 break;
01945         }
01946         return acceptable;
01947 }
01948 
01949 // Static
01950 BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item)
01951 {
01952         if(!item)
01953         {
01954                 return FALSE;
01955         }
01956 
01957         // These permissions are double checked in the simulator in
01958         // LLGroupNoticeInventoryItemFetch::result().
01959         if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
01960         {
01961                 return FALSE;
01962         }
01963         if(!item->getPermissions().allowCopyBy(gAgent.getID()))
01964         {
01965                 return FALSE;
01966         }
01967 
01968         LLVOAvatar* my_avatar = gAgent.getAvatarObject();
01969         if(!my_avatar)
01970         {
01971                 return FALSE;
01972         }
01973 
01974         BOOL acceptable = TRUE;
01975         switch(item->getType())
01976         {
01977         case LLAssetType::AT_CALLINGCARD:
01978                 acceptable = FALSE;
01979                 break;
01980         case LLAssetType::AT_OBJECT:
01981                 if(my_avatar->isWearingAttachment(item->getUUID()))
01982                 {
01983                         acceptable = FALSE;
01984                 }
01985                 break;
01986         default:
01987                 break;
01988         }
01989         return acceptable;
01990 }
01991 
01992 // accessor that looks at permissions, copyability, and names of
01993 // inventory items to determine if a drop would be ok.
01994 EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item)
01995 {
01996         // check the basics
01997         if(!item || !obj) return ACCEPT_NO;
01998         // HACK: downcast
01999         LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item;
02000         if(!vitem->isComplete()) return ACCEPT_NO;
02001 
02002         // deny attempts to drop from an object onto itself. This is to
02003         // help make sure that drops that are from an object to an object
02004         // don't have to worry about order of evaluation. Think of this
02005         // like check for self in assignment.
02006         if(obj->getID() == item->getParentUUID())
02007         {
02008                 return ACCEPT_NO;
02009         }
02010 
02011         //BOOL copy = (perm.allowCopyBy(gAgent.getID(),
02012         //                                                        gAgent.getGroupID())
02013         //                       && (obj->mPermModify || obj->mFlagAllowInventoryAdd));
02014         BOOL worn = FALSE;
02015         LLVOAvatar* my_avatar = NULL;
02016         switch(item->getType())
02017         {
02018         case LLAssetType::AT_OBJECT:
02019                 my_avatar = gAgent.getAvatarObject();
02020                 if(my_avatar && my_avatar->isWearingAttachment(item->getUUID()))
02021                 {
02022                                 worn = TRUE;
02023                 }
02024                 break;
02025         case LLAssetType::AT_BODYPART:
02026         case LLAssetType::AT_CLOTHING:
02027                 if(gAgent.isWearingItem(item->getUUID()))
02028                 {
02029                         worn = TRUE;
02030                 }
02031                 break;
02032         default:
02033                         break;
02034         }
02035         const LLPermissions& perm = item->getPermissions();
02036         BOOL modify = (obj->permModify() || obj->flagAllowInventoryAdd());
02037         BOOL transfer = FALSE;
02038         if((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
02039            || perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
02040         {
02041                 transfer = TRUE;
02042         }
02043         BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
02044         BOOL attached = obj->isAttachment();
02045         BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
02046         if(attached && !unrestricted)
02047         {
02048                 return ACCEPT_NO_LOCKED;
02049         }
02050         else if(modify && transfer && volume && !worn)
02051         {
02052                 return ACCEPT_YES_MULTI;
02053         }
02054         else if(!modify)
02055         {
02056                 return ACCEPT_NO_LOCKED;
02057         }
02058         return ACCEPT_NO;
02059 }
02060 
02064 
02065 EAcceptance LLToolDragAndDrop::dad3dNULL(
02066         LLViewerObject*, S32, MASK, BOOL)
02067 {
02068         lldebugs << "LLToolDragAndDrop::dad3dNULL()" << llendl;
02069         return ACCEPT_NO;
02070 }
02071 
02072 EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
02073         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02074 {
02075         lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl;
02076         // must be in the user's inventory
02077         if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
02078         {
02079                 return ACCEPT_NO;
02080         }
02081 
02082         LLViewerInventoryItem* item;
02083         LLViewerInventoryCategory* cat;
02084         locateInventory(item, cat);
02085         if(!item || !item->isComplete()) return ACCEPT_NO;
02086 
02087         // must not be in the trash
02088         LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH));
02089         if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
02090         {
02091                 return ACCEPT_NO;
02092         }
02093 
02094         // must not be already wearing it
02095         LLVOAvatar* avatar = gAgent.getAvatarObject();
02096         if( !avatar || avatar->isWearingAttachment(item->getUUID()) )
02097         {
02098                 return ACCEPT_NO;
02099         }
02100 
02101         if( drop )
02102         {
02103                 if(mSource == SOURCE_LIBRARY)
02104                 {
02105                         LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
02106                         copy_inventory_item(
02107                                 gAgent.getID(),
02108                                 item->getPermissions().getOwner(),
02109                                 item->getUUID(),
02110                                 LLUUID::null,
02111                                 std::string(),
02112                                 cb);
02113                 }
02114                 else
02115                 {
02116                         rez_attachment(item, 0);
02117                 }
02118         }
02119         return ACCEPT_YES_SINGLE;
02120 }
02121 
02122 
02123 EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
02124         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02125 {
02126         if (mSource == SOURCE_WORLD)
02127         {
02128                 return dad3dRezFromObjectOnLand(obj, face, mask, drop);
02129         }
02130 
02131         lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnLand()" << llendl;
02132         LLViewerInventoryItem* item;
02133         LLViewerInventoryCategory* cat;
02134         locateInventory(item, cat);
02135         if(!item || !item->isComplete()) return ACCEPT_NO;
02136 
02137         LLVOAvatar* my_avatar = gAgent.getAvatarObject();
02138         if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
02139         {
02140                 return ACCEPT_NO;
02141         }
02142 
02143         EAcceptance accept;
02144         BOOL remove_inventory;
02145 
02146         // Get initial settings based on shift key
02147         if (mask & MASK_SHIFT)
02148         {
02149                 // For now, always make copy
02150                 //accept = ACCEPT_YES_SINGLE;
02151                 //remove_inventory = TRUE;
02152                 accept = ACCEPT_YES_COPY_SINGLE;
02153                 remove_inventory = FALSE;
02154         }
02155         else
02156         {
02157                 accept = ACCEPT_YES_COPY_SINGLE;
02158                 remove_inventory = FALSE;
02159         }
02160 
02161         // check if the item can be copied. If not, send that to the sim
02162         // which will remove the inventory item.
02163         if(!item->getPermissions().allowCopyBy(gAgent.getID()))
02164         {
02165                 accept = ACCEPT_YES_SINGLE;
02166                 remove_inventory = TRUE;
02167         }
02168 
02169         // Check if it's in the trash.
02170         LLUUID trash_id;
02171         trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
02172         if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
02173         {
02174                 accept = ACCEPT_YES_SINGLE;
02175                 remove_inventory = TRUE;
02176         }
02177 
02178         if(drop)
02179         {
02180                 dropObject(obj, TRUE, FALSE, remove_inventory);
02181         }
02182 
02183         return accept;
02184 }
02185 
02186 EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
02187         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02188 {
02189         // handle objects coming from object inventory
02190         if (mSource == SOURCE_WORLD)
02191         {
02192                 return dad3dRezFromObjectOnObject(obj, face, mask, drop);
02193         }
02194 
02195         lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnObject()" << llendl;
02196         LLViewerInventoryItem* item;
02197         LLViewerInventoryCategory* cat;
02198         locateInventory(item, cat);
02199         if(!item || !item->isComplete()) return ACCEPT_NO;
02200         LLVOAvatar* my_avatar = gAgent.getAvatarObject();
02201         if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
02202         {
02203                 return ACCEPT_NO;
02204         }
02205 
02206         if((mask & MASK_CONTROL))
02207         {
02208                 // *HACK: In order to resolve SL-22177, we need to block drags
02209                 // from notecards and objects onto other objects.
02210                 if(mSource == SOURCE_NOTECARD)
02211                 {
02212                         return ACCEPT_NO;
02213                 }
02214 
02215                 EAcceptance rv = willObjectAcceptInventory(obj, item);
02216                 if(drop && (ACCEPT_YES_SINGLE <= rv))
02217                 {
02218                         dropInventory(obj, item, mSource, mSourceID);
02219                 }
02220                 return rv;
02221         }
02222         
02223         EAcceptance accept;
02224         BOOL remove_inventory;
02225 
02226         if (mask & MASK_SHIFT)
02227         {
02228                 // For now, always make copy
02229                 //accept = ACCEPT_YES_SINGLE;
02230                 //remove_inventory = TRUE;
02231                 accept = ACCEPT_YES_COPY_SINGLE;
02232                 remove_inventory = FALSE;
02233         }
02234         else
02235         {
02236                 accept = ACCEPT_YES_COPY_SINGLE;
02237                 remove_inventory = FALSE;
02238         }
02239         
02240         // check if the item can be copied. If not, send that to the sim
02241         // which will remove the inventory item.
02242         if(!item->getPermissions().allowCopyBy(gAgent.getID()))
02243         {
02244                 accept = ACCEPT_YES_SINGLE;
02245                 remove_inventory = TRUE;
02246         }
02247 
02248         // Check if it's in the trash.
02249         LLUUID trash_id;
02250         trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
02251         if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
02252         {
02253                 accept = ACCEPT_YES_SINGLE;
02254                 remove_inventory = TRUE;
02255         }
02256 
02257         if(drop)
02258         {
02259                 dropObject(obj, FALSE, FALSE, remove_inventory);
02260         }
02261 
02262         return accept;
02263 }
02264 
02265 EAcceptance LLToolDragAndDrop::dad3dRezScript(
02266         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02267 {
02268         lldebugs << "LLToolDragAndDrop::dad3dRezScript()" << llendl;
02269 
02270         // *HACK: In order to resolve SL-22177, we need to block drags
02271         // from notecards and objects onto other objects.
02272         if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
02273         {
02274                 return ACCEPT_NO;
02275         }
02276 
02277         LLViewerInventoryItem* item;
02278         LLViewerInventoryCategory* cat;
02279         locateInventory(item, cat);
02280         if(!item || !item->isComplete()) return ACCEPT_NO;
02281         EAcceptance rv = willObjectAcceptInventory(obj, item);
02282         if(drop && (ACCEPT_YES_SINGLE <= rv))
02283         {
02284                 // rez in the script active by default, rez in inactive if the
02285                 // control key is being held down.
02286                 BOOL active = ((mask & MASK_CONTROL) == 0);
02287         
02288                 LLViewerObject* root_object = obj;
02289                 if (obj && obj->getParent())
02290                 {
02291                         LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
02292                         if (!parent_obj->isAvatar())
02293                         {
02294                                 root_object = parent_obj;
02295                         }
02296                 }
02297 
02298                 dropScript(root_object, item, active, mSource, mSourceID);
02299         }       
02300         return rv;
02301 }
02302 
02303 EAcceptance LLToolDragAndDrop::dad3dTextureObject(
02304         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02305 {
02306         lldebugs << "LLToolDragAndDrop::dad3dTextureObject()" << llendl;
02307 
02308         // *HACK: In order to resolve SL-22177, we need to block drags
02309         // from notecards and objects onto other objects.
02310         if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
02311         {
02312                 return ACCEPT_NO;
02313         }
02314         
02315         LLViewerInventoryItem* item;
02316         LLViewerInventoryCategory* cat;
02317         locateInventory(item, cat);
02318         if(!item || !item->isComplete()) return ACCEPT_NO;
02319         EAcceptance rv = willObjectAcceptInventory(obj, item);
02320         if((mask & MASK_CONTROL))
02321         {
02322                 if((ACCEPT_YES_SINGLE <= rv) && drop)
02323                 {
02324                         dropInventory(obj, item, mSource, mSourceID);
02325                 }
02326                 return rv;
02327         }
02328         if(!obj->permModify())
02329         {
02330                 return ACCEPT_NO_LOCKED;
02331         }
02332         //If texture !copyable don't texture or you'll never get it back.
02333         if(!item->getPermissions().allowCopyBy(gAgent.getID()))
02334         {
02335                 return ACCEPT_NO;
02336         }
02337 
02338         if(drop && (ACCEPT_YES_SINGLE <= rv))
02339         {
02340                 if((mask & MASK_SHIFT))
02341                 {
02342                         dropTextureAllFaces(obj, item, mSource, mSourceID);
02343                 }
02344                 else
02345                 {
02346                         dropTextureOneFace(obj, face, item, mSource, mSourceID);
02347                 }
02348                 
02349                 // VEFFECT: SetTexture
02350                 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
02351                 effectp->setSourceObject(gAgent.getAvatarObject());
02352                 effectp->setTargetObject(obj);
02353                 effectp->setDuration(LL_HUD_DUR_SHORT);
02354                 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
02355         }
02356 
02357         // enable multi-drop, although last texture will win
02358         return ACCEPT_YES_MULTI;
02359 }
02360 /*
02361 EAcceptance LLToolDragAndDrop::dad3dTextureSelf(
02362         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02363 {
02364         lldebugs << "LLToolDragAndDrop::dad3dTextureAvatar()" << llendl;
02365         if(drop)
02366         {
02367                 if( !(mask & MASK_SHIFT) )
02368                 {
02369                         dropTextureOneFaceAvatar( (LLVOAvatar*)obj, face, (LLInventoryItem*)mCargoData);
02370                 }
02371         }
02372         return (mask & MASK_SHIFT) ? ACCEPT_NO : ACCEPT_YES_SINGLE;
02373 }
02374 */
02375 
02376 EAcceptance LLToolDragAndDrop::dad3dWearItem(
02377         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02378 {
02379         lldebugs << "LLToolDragAndDrop::dad3dWearItem()" << llendl;
02380         LLViewerInventoryItem* item;
02381         LLViewerInventoryCategory* cat;
02382         locateInventory(item, cat);
02383         if(!item || !item->isComplete()) return ACCEPT_NO;
02384 
02385         if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
02386         {
02387                 // it's in the agent inventory
02388                 LLUUID trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
02389                 if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
02390                 {
02391                         return ACCEPT_NO;
02392                 }
02393 
02394                 if( drop )
02395                 {
02396                         // Don't wear anything until initial wearables are loaded, can
02397                         // destroy clothing items.
02398                         if (!gAgent.areWearablesLoaded()) 
02399                         {
02400                                 gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded");
02401                                 return ACCEPT_NO;
02402                         }
02403 
02404                         if(mSource == SOURCE_LIBRARY)
02405                         {
02406                                 // create item based on that one, and put it on if that
02407                                 // was a success.
02408                                 LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
02409                                 copy_inventory_item(
02410                                         gAgent.getID(),
02411                                         item->getPermissions().getOwner(),
02412                                         item->getUUID(),
02413                                         LLUUID::null,
02414                                         std::string(),
02415                                         cb);
02416                         }
02417                         else
02418                         {
02419                                 wear_inventory_item_on_avatar( item );
02420                         }
02421                 }
02422                 return ACCEPT_YES_MULTI;
02423         }
02424         else
02425         {
02426                 // TODO: copy/move item to avatar's inventory and then wear it.
02427                 return ACCEPT_NO;
02428         }
02429 }
02430 
02431 EAcceptance LLToolDragAndDrop::dad3dActivateGesture(
02432         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02433 {
02434         lldebugs << "LLToolDragAndDrop::dad3dActivateGesture()" << llendl;
02435         LLViewerInventoryItem* item;
02436         LLViewerInventoryCategory* cat;
02437         locateInventory(item, cat);
02438         if(!item || !item->isComplete()) return ACCEPT_NO;
02439 
02440         if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
02441         {
02442                 // it's in the agent inventory
02443                 LLUUID trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
02444                 if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
02445                 {
02446                         return ACCEPT_NO;
02447                 }
02448 
02449                 if( drop )
02450                 {
02451                         LLUUID item_id;
02452                         if(mSource == SOURCE_LIBRARY)
02453                         {
02454                                 // create item based on that one, and put it on if that
02455                                 // was a success.
02456                                 LLPointer<LLInventoryCallback> cb = new ActivateGestureCallback();
02457                                 copy_inventory_item(
02458                                         gAgent.getID(),
02459                                         item->getPermissions().getOwner(),
02460                                         item->getUUID(),
02461                                         LLUUID::null,
02462                                         std::string(),
02463                                         cb);
02464                         }
02465                         else
02466                         {
02467                                 gGestureManager.activateGesture(item->getUUID());
02468                                 gInventory.updateItem(item);
02469                                 gInventory.notifyObservers();
02470                         }
02471                 }
02472                 return ACCEPT_YES_MULTI;
02473         }
02474         else
02475         {
02476                 return ACCEPT_NO;
02477         }
02478 }
02479 
02480 EAcceptance LLToolDragAndDrop::dad3dWearCategory(
02481         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02482 {
02483         lldebugs << "LLToolDragAndDrop::dad3dWearCategory()" << llendl;
02484         LLViewerInventoryItem* item;
02485         LLViewerInventoryCategory* category;
02486         locateInventory(item, category);
02487         if(!category) return ACCEPT_NO;
02488 
02489         if (drop)
02490         {
02491                 // Don't wear anything until initial wearables are loaded, can
02492                 // destroy clothing items.
02493                 if (!gAgent.areWearablesLoaded()) 
02494                 {
02495                         gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded");
02496                         return ACCEPT_NO;
02497                 }
02498         }
02499 
02500         if(mSource == SOURCE_AGENT)
02501         {
02502                 LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH));
02503                 if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) )
02504                 {
02505                         return ACCEPT_NO;
02506                 }
02507 
02508                 if(drop)
02509                 {
02510                     BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
02511                         wear_inventory_category(category, false, append);
02512                 }
02513                 return ACCEPT_YES_MULTI;
02514         }
02515         else if(mSource == SOURCE_LIBRARY)
02516         {
02517                 if(drop)
02518                 {
02519                         wear_inventory_category(category, true, false);
02520                 }
02521                 return ACCEPT_YES_MULTI;
02522         }
02523         else
02524         {
02525                 // TODO: copy/move category to avatar's inventory and then wear it.
02526                 return ACCEPT_NO;
02527         }
02528 }
02529 
02530 
02531 EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
02532         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02533 {
02534         lldebugs << "LLToolDragAndDrop::dadUpdateInventory()" << llendl;
02535 
02536         // *HACK: In order to resolve SL-22177, we need to block drags
02537         // from notecards and objects onto other objects.
02538         if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
02539         {
02540                 return ACCEPT_NO;
02541         }
02542 
02543         LLViewerInventoryItem* item;
02544         LLViewerInventoryCategory* cat;
02545         locateInventory(item, cat);
02546         if(!item || !item->isComplete()) return ACCEPT_NO;
02547         LLViewerObject* root_object = obj;
02548         if (obj && obj->getParent())
02549         {
02550                 LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
02551                 if (!parent_obj->isAvatar())
02552                 {
02553                         root_object = parent_obj;
02554                 }
02555         }
02556 
02557         EAcceptance rv = willObjectAcceptInventory(root_object, item);
02558         if(root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv))
02559         {
02560                 dropInventory(root_object, item, mSource, mSourceID);
02561         }
02562         return rv;
02563 }
02564 
02565 BOOL LLToolDragAndDrop::dadUpdateInventory(LLViewerObject* obj, BOOL drop)
02566 {
02567         EAcceptance rv = dad3dUpdateInventory(obj, -1, MASK_NONE, drop);
02568         return (rv >= ACCEPT_YES_COPY_SINGLE);
02569 }
02570 
02571 EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
02572         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02573 {
02574         lldebugs << "LLToolDragAndDrop::dad3dUpdateInventoryCategory()" << llendl;
02575         if (NULL==obj)
02576         {
02577                 llwarns << "obj is NULL; aborting func with ACCEPT_NO" << llendl;
02578                 return ACCEPT_NO;
02579         }
02580 
02581         if (mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
02582         {
02583                 return ACCEPT_NO;
02584         }
02585         if(obj->isAttachment()) return ACCEPT_NO_LOCKED;
02586         LLViewerInventoryItem* item;
02587         LLViewerInventoryCategory* cat;
02588         locateInventory(item, cat);
02589         if(!cat) return ACCEPT_NO;
02590         EAcceptance rv = ACCEPT_NO;
02591 
02592         // find all the items in the category
02593         LLDroppableItem droppable(!obj->permYouOwner());
02594         LLInventoryModel::cat_array_t cats;
02595         LLInventoryModel::item_array_t items;
02596         gInventory.collectDescendentsIf(cat->getUUID(),
02597                                         cats,
02598                                         items,
02599                                         LLInventoryModel::EXCLUDE_TRASH,
02600                                         droppable);
02601         cats.put(cat);
02602         if(droppable.countNoCopy() > 0)
02603         {
02604                 llwarns << "*** Need to confirm this step" << llendl;
02605         }
02606         LLViewerObject* root_object = obj;
02607         if (obj->getParent())
02608         {
02609                 LLViewerObject* parent_obj = (LLViewerObject*)obj->getParent();
02610                 if (!parent_obj->isAvatar())
02611                 {
02612                         root_object = parent_obj;
02613                 }
02614         }
02615 
02616         // Check for accept
02617         S32 i;
02618         S32 count = cats.count();
02619         for(i = 0; i < count; ++i)
02620         {
02621                 rv = gInventory.isCategoryComplete(cats.get(i)->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO;
02622                 if(rv < ACCEPT_YES_SINGLE)
02623                 {
02624                         lldebugs << "Category " << cats.get(i)->getUUID()
02625                                          << "is not complete." << llendl;
02626                         break;
02627                 }
02628         }
02629         if(ACCEPT_YES_COPY_SINGLE <= rv)
02630         {
02631                 count = items.count();
02632                 for(i = 0; i < count; ++i)
02633                 {
02634                         rv = willObjectAcceptInventory(root_object, items.get(i));
02635                         if(rv < ACCEPT_YES_COPY_SINGLE)
02636                         {
02637                                 lldebugs << "Object will not accept "
02638                                                  << items.get(i)->getUUID() << llendl;
02639                                 break;
02640                         }
02641                 }
02642         }
02643 
02644         // if every item is accepted, go ahead and send it on.
02645         if(drop && (ACCEPT_YES_COPY_SINGLE <= rv))
02646         {
02647                 S32 count = items.count();
02648                 LLInventoryFetchObserver::item_ref_t ids;
02649                 for(i = 0; i < count; ++i)
02650                 {
02651                         //dropInventory(root_object, items.get(i), mSource, mSourceID);
02652                         ids.push_back(items.get(i)->getUUID());
02653                 }
02654                 LLCategoryDropObserver* dropper;
02655                 dropper = new LLCategoryDropObserver(obj->getID(), mSource);
02656                 dropper->fetchItems(ids);
02657                 if(dropper->isEverythingComplete())
02658                 {
02659                         dropper->done();
02660                 }
02661                 else
02662                 {
02663                         gInventory.addObserver(dropper);
02664                 }
02665         }
02666         return rv;
02667 }
02668 
02669 BOOL LLToolDragAndDrop::dadUpdateInventoryCategory(LLViewerObject* obj,
02670                                                                                                    BOOL drop)
02671 {
02672         EAcceptance rv = dad3dUpdateInventoryCategory(obj, -1, MASK_NONE, drop);
02673         return (rv >= ACCEPT_YES_COPY_SINGLE);
02674 }
02675 
02676 EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject(
02677         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02678 {
02679         lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << llendl;
02680 
02681         // item has to be in agent inventory.
02682         if(mSource != SOURCE_AGENT) return ACCEPT_NO;
02683 
02684         // find the item now.
02685         LLViewerInventoryItem* item;
02686         LLViewerInventoryCategory* cat;
02687         locateInventory(item, cat);
02688         if(!item || !item->isComplete()) return ACCEPT_NO;
02689         if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
02690         {
02691                 // cannot give away no-transfer objects
02692                 return ACCEPT_NO;
02693         }
02694         LLVOAvatar* avatar = gAgent.getAvatarObject();
02695         if(avatar && avatar->isWearingAttachment( item->getUUID() ) )
02696         {
02697                 // You can't give objects that are attached to you
02698                 return ACCEPT_NO;
02699         }
02700         if( obj && avatar )
02701         {
02702                 if(drop)
02703                 {
02704                         giveInventory(obj->getID(), item );
02705                 }
02706                 // *TODO: deal with all the issues surrounding multi-object
02707                 // inventory transfers.
02708                 return ACCEPT_YES_SINGLE;
02709         }
02710         return ACCEPT_NO;
02711 }
02712 
02713 
02714 EAcceptance LLToolDragAndDrop::dad3dGiveInventory(
02715         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02716 {
02717         lldebugs << "LLToolDragAndDrop::dad3dGiveInventory()" << llendl;
02718         // item has to be in agent inventory.
02719         if(mSource != SOURCE_AGENT) return ACCEPT_NO;
02720         LLViewerInventoryItem* item;
02721         LLViewerInventoryCategory* cat;
02722         locateInventory(item, cat);
02723         if(!item || !item->isComplete()) return ACCEPT_NO;
02724         if(!isInventoryGiveAcceptable(item))
02725         {
02726                 return ACCEPT_NO;
02727         }
02728         if(drop && obj)
02729         {
02730                 giveInventory(obj->getID(), item);
02731         }
02732         // *TODO: deal with all the issues surrounding multi-object
02733         // inventory transfers.
02734         return ACCEPT_YES_SINGLE;
02735 }
02736 
02737 EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory(
02738         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02739 {
02740         lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryCategory()" << llendl;
02741         if(drop && obj)
02742         {
02743                 LLViewerInventoryItem* item;
02744                 LLViewerInventoryCategory* cat;
02745                 locateInventory(item, cat);
02746                 if(!cat) return ACCEPT_NO;
02747                 giveInventoryCategory(obj->getID(), cat);
02748         }
02749         // *TODO: deal with all the issues surrounding multi-object
02750         // inventory transfers.
02751         return ACCEPT_YES_SINGLE;
02752 }
02753 
02754 
02755 EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand(
02756         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02757 {
02758         lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnLand()" << llendl;
02759         LLViewerInventoryItem* item = NULL;
02760         LLViewerInventoryCategory* cat = NULL;
02761         locateInventory(item, cat);
02762         if(!item || !item->isComplete()) return ACCEPT_NO;
02763 
02764         if(!gAgent.allowOperation(PERM_COPY, item->getPermissions())
02765                 || !item->getPermissions().allowTransferTo(LLUUID::null))
02766         {
02767                 return ACCEPT_NO_LOCKED;
02768         }
02769         if(drop)
02770         {
02771                 dropObject(obj, TRUE, TRUE, FALSE);
02772         }
02773         return ACCEPT_YES_SINGLE;
02774 }
02775 
02776 EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject(
02777         LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
02778 {
02779         lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnObject()" << llendl;
02780         LLViewerInventoryItem* item;
02781         LLViewerInventoryCategory* cat;
02782         locateInventory(item, cat);
02783         if(!item || !item->isComplete()) return ACCEPT_NO;
02784         if((mask & MASK_CONTROL))
02785         {
02786                 // *HACK: In order to resolve SL-22177, we need to block drags
02787                 // from notecards and objects onto other objects.
02788                 return ACCEPT_NO;
02789 
02790                 // *HACK: uncomment this when appropriate
02791                 //EAcceptance rv = willObjectAcceptInventory(obj, item);
02792                 //if(drop && (ACCEPT_YES_SINGLE <= rv))
02793                 //{
02794                 //      dropInventory(obj, item, mSource, mSourceID);
02795                 //}
02796                 //return rv;
02797         }
02798         if(!item->getPermissions().allowCopyBy(gAgent.getID(),
02799                                                                                    gAgent.getGroupID())
02800            || !item->getPermissions().allowTransferTo(LLUUID::null))
02801         {
02802                 return ACCEPT_NO_LOCKED;
02803         }
02804         if(drop)
02805         {
02806                 dropObject(obj, FALSE, TRUE, FALSE);
02807         }
02808         return ACCEPT_YES_SINGLE;
02809 }
02810 
02811 EAcceptance LLToolDragAndDrop::dad3dCategoryOnLand(
02812         LLViewerObject *obj, S32 face, MASK mask, BOOL drop)
02813 {
02814         return ACCEPT_NO;
02815         /*
02816         lldebugs << "LLToolDragAndDrop::dad3dCategoryOnLand()" << llendl;
02817         LLInventoryItem* item;
02818         LLInventoryCategory* cat;
02819         locateInventory(item, cat);
02820         if(!cat) return ACCEPT_NO;
02821         EAcceptance rv = ACCEPT_NO;
02822 
02823         // find all the items in the category
02824         LLViewerInventoryCategory::cat_array_t cats;
02825         LLViewerInventoryItem::item_array_t items;
02826         LLDropCopyableItems droppable;
02827         gInventory.collectDescendentsIf(cat->getUUID(),
02828                                                                         cats,
02829                                                                         items,
02830                                                                         LLInventoryModel::EXCLUDE_TRASH,
02831                                                                         droppable);
02832         if(items.count() > 0)
02833         {
02834                 rv = ACCEPT_YES_SINGLE;
02835         }
02836         if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
02837         {
02838                 createContainer(items, cat->getName());
02839                 return ACCEPT_NO;
02840         }
02841         return rv;
02842         */
02843 }
02844 
02845 
02846 // This is based on ALOT of copied, special-cased code
02847 // This shortcuts alot of steps to make a basic object
02848 // w/ an inventory and a special permissions set
02849 EAcceptance LLToolDragAndDrop::dad3dAssetOnLand(
02850         LLViewerObject *obj, S32 face, MASK mask, BOOL drop)
02851 {
02852         return ACCEPT_NO;
02853         /*
02854         lldebugs << "LLToolDragAndDrop::dad3dAssetOnLand()" << llendl;
02855         LLViewerInventoryCategory::cat_array_t cats;
02856         LLViewerInventoryItem::item_array_t items;
02857         LLViewerInventoryItem::item_array_t copyable_items;
02858         locateMultipleInventory(items, cats);
02859         if(!items.count()) return ACCEPT_NO;
02860         EAcceptance rv = ACCEPT_NO;
02861         for (S32 i = 0; i < items.count(); i++)
02862         {
02863                 LLInventoryItem* item = items[i];
02864                 if(item->getPermissions().allowCopyBy(gAgent.getID()))
02865                 {
02866                         copyable_items.put(item);
02867                         rv = ACCEPT_YES_SINGLE;
02868                 }
02869         }
02870 
02871         if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
02872         {
02873                 createContainer(copyable_items, NULL);
02874         }
02875 
02876         return rv;
02877         */
02878 }
02879 
02880 LLInventoryObject* LLToolDragAndDrop::locateInventory(
02881         LLViewerInventoryItem*& item,
02882         LLViewerInventoryCategory*& cat)
02883 {
02884         item = NULL;
02885         cat = NULL;
02886         if(mCargoIDs.empty()) return NULL;
02887         if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
02888         {
02889                 // The object should be in user inventory.
02890                 item = (LLViewerInventoryItem*)gInventory.getItem(mCargoIDs[mCurItemIndex]);
02891                 cat = (LLViewerInventoryCategory*)gInventory.getCategory(mCargoIDs[mCurItemIndex]);
02892         }
02893         else if(mSource == SOURCE_WORLD)
02894         {
02895                 // This object is in some task inventory somewhere.
02896                 LLViewerObject* obj = gObjectList.findObject(mSourceID);
02897                 if(obj)
02898                 {
02899                         if((mCargoTypes[mCurItemIndex] == DAD_CATEGORY)
02900                            || (mCargoTypes[mCurItemIndex] == DAD_ROOT_CATEGORY))
02901                         {
02902                                 cat = (LLViewerInventoryCategory*)obj->getInventoryObject(mCargoIDs[mCurItemIndex]);
02903                         }
02904                         else
02905                         {
02906                            item = (LLViewerInventoryItem*)obj->getInventoryObject(mCargoIDs[mCurItemIndex]);
02907                         }
02908                 }
02909         }
02910         else if(mSource == SOURCE_NOTECARD)
02911         {
02912                 LLPreviewNotecard* card;
02913                 card = (LLPreviewNotecard*)LLPreview::find(mSourceID);
02914                 if(card)
02915                 {
02916                         item = (LLViewerInventoryItem*)card->getDragItem();
02917                 }
02918         }
02919         if(item) return item;
02920         if(cat) return cat;
02921         return NULL;
02922 }
02923 
02924 /*
02925 LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats,
02926                                                                                                                           LLViewerInventoryItem::item_array_t& items)
02927 {
02928         if(mCargoIDs.count() == 0) return NULL;
02929         if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
02930         {
02931                 // The object should be in user inventory.
02932                 for (S32 i = 0; i < mCargoIDs.count(); i++)
02933                 {
02934                         LLInventoryItem* item = gInventory.getItem(mCargoIDs[i]);
02935                         if (item)
02936                         {
02937                                 items.put(item);
02938                         }
02939                         LLInventoryCategory* category = gInventory.getCategory(mCargoIDs[i]);
02940                         if (category)
02941                         {
02942                                 cats.put(category);
02943                         }
02944                 }
02945         }
02946         else if(mSource == SOURCE_WORLD)
02947         {
02948                 // This object is in some task inventory somewhere.
02949                 LLViewerObject* obj = gObjectList.findObject(mSourceID);
02950                 if(obj)
02951                 {
02952                         if((mCargoType == DAD_CATEGORY)
02953                            || (mCargoType == DAD_ROOT_CATEGORY))
02954                         {
02955                                 // The object should be in user inventory.
02956                                 for (S32 i = 0; i < mCargoIDs.count(); i++)
02957                                 {
02958                                         LLInventoryCategory* category = (LLInventoryCategory*)obj->getInventoryObject(mCargoIDs[i]);
02959                                         if (category)
02960                                         {
02961                                                 cats.put(category);
02962                                         }
02963                                 }
02964                         }
02965                         else
02966                         {
02967                                 for (S32 i = 0; i < mCargoIDs.count(); i++)
02968                                 {
02969                                         LLInventoryItem* item = (LLInventoryItem*)obj->getInventoryObject(mCargoIDs[i]);
02970                                         if (item)
02971                                         {
02972                                                 items.put(item);
02973                                         }
02974                                 }
02975                         }
02976                 }
02977         }
02978         else if(mSource == SOURCE_NOTECARD)
02979         {
02980                 LLPreviewNotecard* card;
02981                 card = (LLPreviewNotecard*)LLPreview::find(mSourceID);
02982                 if(card)
02983                 {
02984                         items.put((LLInventoryItem*)card->getDragItem());
02985                 }
02986         }
02987         if(items.count()) return items[0];
02988         if(cats.count()) return cats[0];
02989         return NULL;
02990 }
02991 */
02992 
02993 void LLToolDragAndDrop::createContainer(LLViewerInventoryItem::item_array_t &items, const char* preferred_name )
02994 {
02995         llwarns << "LLToolDragAndDrop::createContainer()" << llendl;
02996         return;
02997 }
02998 
02999 
03000 // utility functions
03001 
03002 void pack_permissions_slam(LLMessageSystem* msg, U32 flags, const LLPermissions& perms)
03003 {
03004         U32 group_mask          = perms.getMaskGroup();
03005         U32 everyone_mask       = perms.getMaskEveryone();
03006         U32 next_owner_mask     = perms.getMaskNextOwner();
03007         
03008         msg->addU32Fast(_PREHASH_ItemFlags, flags);
03009         msg->addU32Fast(_PREHASH_GroupMask, group_mask);
03010         msg->addU32Fast(_PREHASH_EveryoneMask, everyone_mask);
03011         msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_mask);
03012 }

Generated on Fri May 16 08:34:07 2008 for SecondLife by  doxygen 1.5.5