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

Generated on Thu Jul 1 06:09:21 2010 for Second Life Viewer by  doxygen 1.4.7