/indra/newview/lltooldraganddrop.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 2332 lines · 1792 code · 213 blank · 327 comment · 373 complexity · 15e4b703e8f763512171ef56912241da MD5 · raw file

Large files are truncated click here to view the full file

  1. /**
  2. * @file lltooldraganddrop.cpp
  3. * @brief LLToolDragAndDrop class implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "lltooldraganddrop.h"
  28. // library headers
  29. #include "llnotificationsutil.h"
  30. // project headers
  31. #include "llagent.h"
  32. #include "llagentcamera.h"
  33. #include "llagentwearables.h"
  34. #include "llappearancemgr.h"
  35. #include "lldictionary.h"
  36. #include "llfloaterreg.h"
  37. #include "llfloatertools.h"
  38. #include "llgesturemgr.h"
  39. #include "llgiveinventory.h"
  40. #include "llhudmanager.h"
  41. #include "llhudeffecttrail.h"
  42. #include "llimview.h"
  43. #include "llinventorybridge.h"
  44. #include "llinventorydefines.h"
  45. #include "llinventoryfunctions.h"
  46. #include "llpreviewnotecard.h"
  47. #include "llrootview.h"
  48. #include "llselectmgr.h"
  49. #include "lltoolmgr.h"
  50. #include "lltooltip.h"
  51. #include "lltrans.h"
  52. #include "llviewerobjectlist.h"
  53. #include "llviewerregion.h"
  54. #include "llviewerstats.h"
  55. #include "llviewerwindow.h"
  56. #include "llvoavatarself.h"
  57. #include "llworld.h"
  58. #include "llclipboard.h"
  59. // syntactic sugar
  60. #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
  61. class LLNoPreferredType : public LLInventoryCollectFunctor
  62. {
  63. public:
  64. LLNoPreferredType() {}
  65. virtual ~LLNoPreferredType() {}
  66. virtual bool operator()(LLInventoryCategory* cat,
  67. LLInventoryItem* item)
  68. {
  69. if (cat && (cat->getPreferredType() == LLFolderType::FT_NONE))
  70. {
  71. return true;
  72. }
  73. return false;
  74. }
  75. };
  76. class LLNoPreferredTypeOrItem : public LLInventoryCollectFunctor
  77. {
  78. public:
  79. LLNoPreferredTypeOrItem() {}
  80. virtual ~LLNoPreferredTypeOrItem() {}
  81. virtual bool operator()(LLInventoryCategory* cat,
  82. LLInventoryItem* item)
  83. {
  84. if (item) return true;
  85. if (cat && (cat->getPreferredType() == LLFolderType::FT_NONE))
  86. {
  87. return true;
  88. }
  89. return false;
  90. }
  91. };
  92. class LLDroppableItem : public LLInventoryCollectFunctor
  93. {
  94. public:
  95. LLDroppableItem(BOOL is_transfer) :
  96. mCountLosing(0), mIsTransfer(is_transfer) {}
  97. virtual ~LLDroppableItem() {}
  98. virtual bool operator()(LLInventoryCategory* cat,
  99. LLInventoryItem* item);
  100. S32 countNoCopy() const { return mCountLosing; }
  101. protected:
  102. S32 mCountLosing;
  103. BOOL mIsTransfer;
  104. };
  105. bool LLDroppableItem::operator()(LLInventoryCategory* cat,
  106. LLInventoryItem* item)
  107. {
  108. bool allowed = false;
  109. if (item)
  110. {
  111. allowed = itemTransferCommonlyAllowed(item);
  112. if (allowed
  113. && mIsTransfer
  114. && !item->getPermissions().allowOperationBy(PERM_TRANSFER,
  115. gAgent.getID()))
  116. {
  117. allowed = false;
  118. }
  119. if (allowed && !item->getPermissions().allowCopyBy(gAgent.getID()))
  120. {
  121. ++mCountLosing;
  122. }
  123. }
  124. return allowed;
  125. }
  126. class LLDropCopyableItems : public LLInventoryCollectFunctor
  127. {
  128. public:
  129. LLDropCopyableItems() {}
  130. virtual ~LLDropCopyableItems() {}
  131. virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
  132. };
  133. bool LLDropCopyableItems::operator()(
  134. LLInventoryCategory* cat,
  135. LLInventoryItem* item)
  136. {
  137. bool allowed = false;
  138. if (item)
  139. {
  140. allowed = itemTransferCommonlyAllowed(item);
  141. if (allowed &&
  142. !item->getPermissions().allowCopyBy(gAgent.getID()))
  143. {
  144. // whoops, can't copy it - don't allow it.
  145. allowed = false;
  146. }
  147. }
  148. return allowed;
  149. }
  150. // Starts a fetch on folders and items. This is really not used
  151. // as an observer in the traditional sense; we're just using it to
  152. // request a fetch and we don't care about when/if the response arrives.
  153. class LLCategoryFireAndForget : public LLInventoryFetchComboObserver
  154. {
  155. public:
  156. LLCategoryFireAndForget(const uuid_vec_t& folder_ids,
  157. const uuid_vec_t& item_ids) :
  158. LLInventoryFetchComboObserver(folder_ids, item_ids)
  159. {}
  160. ~LLCategoryFireAndForget() {}
  161. virtual void done()
  162. {
  163. /* no-op: it's fire n forget right? */
  164. lldebugs << "LLCategoryFireAndForget::done()" << llendl;
  165. }
  166. };
  167. class LLCategoryDropObserver : public LLInventoryFetchItemsObserver
  168. {
  169. public:
  170. LLCategoryDropObserver(
  171. const uuid_vec_t& ids,
  172. const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
  173. LLInventoryFetchItemsObserver(ids),
  174. mObjectID(obj_id),
  175. mSource(src)
  176. {}
  177. ~LLCategoryDropObserver() {}
  178. virtual void done();
  179. protected:
  180. LLUUID mObjectID;
  181. LLToolDragAndDrop::ESource mSource;
  182. };
  183. void LLCategoryDropObserver::done()
  184. {
  185. gInventory.removeObserver(this);
  186. LLViewerObject* dst_obj = gObjectList.findObject(mObjectID);
  187. if (dst_obj)
  188. {
  189. // *FIX: coalesce these...
  190. LLInventoryItem* item = NULL;
  191. uuid_vec_t::iterator it = mComplete.begin();
  192. uuid_vec_t::iterator end = mComplete.end();
  193. for(; it < end; ++it)
  194. {
  195. item = gInventory.getItem(*it);
  196. if (item)
  197. {
  198. LLToolDragAndDrop::dropInventory(
  199. dst_obj,
  200. item,
  201. mSource,
  202. LLUUID::null);
  203. }
  204. }
  205. }
  206. delete this;
  207. }
  208. /* Doesn't seem to be used anymore.
  209. class LLCategoryDropDescendentsObserver : public LLInventoryFetchDescendentsObserver
  210. {
  211. public:
  212. LLCategoryDropDescendentsObserver(
  213. const LLUUID& obj_id, LLToolDragAndDrop::ESource src) :
  214. mObjectID(obj_id),
  215. mSource(src)
  216. {}
  217. ~LLCategoryDropDescendentsObserver() {}
  218. virtual void done();
  219. protected:
  220. LLUUID mObjectID;
  221. LLToolDragAndDrop::ESource mSource;
  222. };
  223. void LLCategoryDropDescendentsObserver::done()
  224. {
  225. gInventory.removeObserver(this);
  226. uuid_vec_t::iterator it = mComplete.begin();
  227. uuid_vec_t::iterator end = mComplete.end();
  228. LLViewerInventoryCategory::cat_array_t cats;
  229. LLViewerInventoryItem::item_array_t items;
  230. for(; it != end; ++it)
  231. {
  232. gInventory.collectDescendents(
  233. (*it),
  234. cats,
  235. items,
  236. LLInventoryModel::EXCLUDE_TRASH);
  237. }
  238. S32 count = items.count();
  239. if (count)
  240. {
  241. std::set<LLUUID> unique_ids;
  242. for(S32 i = 0; i < count; ++i)
  243. {
  244. unique_ids.insert(items.get(i)->getUUID());
  245. }
  246. uuid_vec_t ids;
  247. std::back_insert_iterator<uuid_vec_t> copier(ids);
  248. std::copy(unique_ids.begin(), unique_ids.end(), copier);
  249. LLCategoryDropObserver* dropper;
  250. dropper = new LLCategoryDropObserver(ids, mObjectID, mSource);
  251. dropper->startFetch();
  252. if (dropper->isDone())
  253. {
  254. dropper->done();
  255. }
  256. else
  257. {
  258. gInventory.addObserver(dropper);
  259. }
  260. }
  261. delete this;
  262. }
  263. */
  264. S32 LLToolDragAndDrop::sOperationId = 0;
  265. LLToolDragAndDrop::DragAndDropEntry::DragAndDropEntry(dragOrDrop3dImpl f_none,
  266. dragOrDrop3dImpl f_self,
  267. dragOrDrop3dImpl f_avatar,
  268. dragOrDrop3dImpl f_object,
  269. dragOrDrop3dImpl f_land) :
  270. LLDictionaryEntry("")
  271. {
  272. mFunctions[DT_NONE] = f_none;
  273. mFunctions[DT_SELF] = f_self;
  274. mFunctions[DT_AVATAR] = f_avatar;
  275. mFunctions[DT_OBJECT] = f_object;
  276. mFunctions[DT_LAND] = f_land;
  277. }
  278. LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::LLDragAndDropDictionary::get(EDragAndDropType dad_type, LLToolDragAndDrop::EDropTarget drop_target)
  279. {
  280. const DragAndDropEntry *entry = lookup(dad_type);
  281. if (entry)
  282. {
  283. return (entry->mFunctions[(U8)drop_target]);
  284. }
  285. return &LLToolDragAndDrop::dad3dNULL;
  286. }
  287. LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary()
  288. {
  289. // DT_NONE DT_SELF DT_AVATAR DT_OBJECT DT_LAND
  290. // |-------------------------------|----------------------------------------------|-----------------------------------------------|---------------------------------------------------|--------------------------------|
  291. addEntry(DAD_NONE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
  292. addEntry(DAD_TEXTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dTextureObject, &LLToolDragAndDrop::dad3dNULL));
  293. addEntry(DAD_SOUND, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  294. addEntry(DAD_CALLINGCARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  295. addEntry(DAD_LANDMARK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  296. addEntry(DAD_SCRIPT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dRezScript, &LLToolDragAndDrop::dad3dNULL));
  297. addEntry(DAD_CLOTHING, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  298. addEntry(DAD_OBJECT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dRezAttachmentFromInv, &LLToolDragAndDrop::dad3dGiveInventoryObject, &LLToolDragAndDrop::dad3dRezObjectOnObject, &LLToolDragAndDrop::dad3dRezObjectOnLand));
  299. addEntry(DAD_NOTECARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  300. addEntry(DAD_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory, &LLToolDragAndDrop::dad3dGiveInventoryCategory, &LLToolDragAndDrop::dad3dUpdateInventoryCategory, &LLToolDragAndDrop::dad3dNULL));
  301. addEntry(DAD_ROOT_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
  302. addEntry(DAD_BODYPART, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  303. addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  304. addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL));
  305. addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL));
  306. addEntry(DAD_MESH, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dMeshObject, &LLToolDragAndDrop::dad3dNULL));
  307. // TODO: animation on self could play it? edit it?
  308. // TODO: gesture on self could play it? edit it?
  309. };
  310. LLToolDragAndDrop::LLToolDragAndDrop()
  311. : LLTool(std::string("draganddrop"), NULL),
  312. mDragStartX(0),
  313. mDragStartY(0),
  314. mSource(SOURCE_AGENT),
  315. mCursor(UI_CURSOR_NO),
  316. mLastAccept(ACCEPT_NO),
  317. mDrop(FALSE),
  318. mCurItemIndex(0)
  319. {
  320. }
  321. void LLToolDragAndDrop::setDragStart(S32 x, S32 y)
  322. {
  323. mDragStartX = x;
  324. mDragStartY = y;
  325. }
  326. BOOL LLToolDragAndDrop::isOverThreshold(S32 x,S32 y)
  327. {
  328. static LLCachedControl<S32> drag_and_drop_threshold(gSavedSettings,"DragAndDropDistanceThreshold");
  329. S32 mouse_delta_x = x - mDragStartX;
  330. S32 mouse_delta_y = y - mDragStartY;
  331. return (mouse_delta_x * mouse_delta_x) + (mouse_delta_y * mouse_delta_y) > drag_and_drop_threshold * drag_and_drop_threshold;
  332. }
  333. void LLToolDragAndDrop::beginDrag(EDragAndDropType type,
  334. const LLUUID& cargo_id,
  335. ESource source,
  336. const LLUUID& source_id,
  337. const LLUUID& object_id)
  338. {
  339. if (type == DAD_NONE)
  340. {
  341. llwarns << "Attempted to start drag without a cargo type" << llendl;
  342. return;
  343. }
  344. mCargoTypes.clear();
  345. mCargoTypes.push_back(type);
  346. mCargoIDs.clear();
  347. mCargoIDs.push_back(cargo_id);
  348. mSource = source;
  349. mSourceID = source_id;
  350. mObjectID = object_id;
  351. setMouseCapture( TRUE );
  352. LLToolMgr::getInstance()->setTransientTool( this );
  353. mCursor = UI_CURSOR_NO;
  354. if ((mCargoTypes[0] == DAD_CATEGORY)
  355. && ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)))
  356. {
  357. LLInventoryCategory* cat = gInventory.getCategory(cargo_id);
  358. // go ahead and fire & forget the descendents if we are not
  359. // dragging a protected folder.
  360. if (cat)
  361. {
  362. LLViewerInventoryCategory::cat_array_t cats;
  363. LLViewerInventoryItem::item_array_t items;
  364. LLNoPreferredTypeOrItem is_not_preferred;
  365. uuid_vec_t folder_ids;
  366. uuid_vec_t item_ids;
  367. if (is_not_preferred(cat, NULL))
  368. {
  369. folder_ids.push_back(cargo_id);
  370. }
  371. gInventory.collectDescendentsIf(
  372. cargo_id,
  373. cats,
  374. items,
  375. LLInventoryModel::EXCLUDE_TRASH,
  376. is_not_preferred);
  377. S32 count = cats.count();
  378. S32 i;
  379. for(i = 0; i < count; ++i)
  380. {
  381. folder_ids.push_back(cats.get(i)->getUUID());
  382. }
  383. count = items.count();
  384. for(i = 0; i < count; ++i)
  385. {
  386. item_ids.push_back(items.get(i)->getUUID());
  387. }
  388. if (!folder_ids.empty() || !item_ids.empty())
  389. {
  390. LLCategoryFireAndForget *fetcher = new LLCategoryFireAndForget(folder_ids, item_ids);
  391. fetcher->startFetch();
  392. delete fetcher;
  393. }
  394. }
  395. }
  396. }
  397. void LLToolDragAndDrop::beginMultiDrag(
  398. const std::vector<EDragAndDropType> types,
  399. const uuid_vec_t& cargo_ids,
  400. ESource source,
  401. const LLUUID& source_id)
  402. {
  403. // assert on public api is evil
  404. //llassert( type != DAD_NONE );
  405. std::vector<EDragAndDropType>::const_iterator types_it;
  406. for (types_it = types.begin(); types_it != types.end(); ++types_it)
  407. {
  408. if (DAD_NONE == *types_it)
  409. {
  410. llwarns << "Attempted to start drag without a cargo type" << llendl;
  411. return;
  412. }
  413. }
  414. mCargoTypes = types;
  415. mCargoIDs = cargo_ids;
  416. mSource = source;
  417. mSourceID = source_id;
  418. setMouseCapture( TRUE );
  419. LLToolMgr::getInstance()->setTransientTool( this );
  420. mCursor = UI_CURSOR_NO;
  421. if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
  422. {
  423. // find categories (i.e. inventory folders) in the cargo.
  424. LLInventoryCategory* cat = NULL;
  425. S32 count = llmin(cargo_ids.size(), types.size());
  426. std::set<LLUUID> cat_ids;
  427. for(S32 i = 0; i < count; ++i)
  428. {
  429. cat = gInventory.getCategory(cargo_ids[i]);
  430. if (cat)
  431. {
  432. LLViewerInventoryCategory::cat_array_t cats;
  433. LLViewerInventoryItem::item_array_t items;
  434. LLNoPreferredType is_not_preferred;
  435. if (is_not_preferred(cat, NULL))
  436. {
  437. cat_ids.insert(cat->getUUID());
  438. }
  439. gInventory.collectDescendentsIf(
  440. cat->getUUID(),
  441. cats,
  442. items,
  443. LLInventoryModel::EXCLUDE_TRASH,
  444. is_not_preferred);
  445. S32 cat_count = cats.count();
  446. for(S32 i = 0; i < cat_count; ++i)
  447. {
  448. cat_ids.insert(cat->getUUID());
  449. }
  450. }
  451. }
  452. if (!cat_ids.empty())
  453. {
  454. uuid_vec_t folder_ids;
  455. uuid_vec_t item_ids;
  456. std::back_insert_iterator<uuid_vec_t> copier(folder_ids);
  457. std::copy(cat_ids.begin(), cat_ids.end(), copier);
  458. LLCategoryFireAndForget fetcher(folder_ids, item_ids);
  459. }
  460. }
  461. }
  462. void LLToolDragAndDrop::endDrag()
  463. {
  464. mEndDragSignal();
  465. LLSelectMgr::getInstance()->unhighlightAll();
  466. setMouseCapture(FALSE);
  467. }
  468. void LLToolDragAndDrop::onMouseCaptureLost()
  469. {
  470. // Called whenever the drag ends or if mouse capture is simply lost
  471. LLToolMgr::getInstance()->clearTransientTool();
  472. mCargoTypes.clear();
  473. mCargoIDs.clear();
  474. mSource = SOURCE_AGENT;
  475. mSourceID.setNull();
  476. mObjectID.setNull();
  477. }
  478. BOOL LLToolDragAndDrop::handleMouseUp( S32 x, S32 y, MASK mask )
  479. {
  480. if (hasMouseCapture())
  481. {
  482. EAcceptance acceptance = ACCEPT_NO;
  483. dragOrDrop( x, y, mask, TRUE, &acceptance );
  484. endDrag();
  485. }
  486. return TRUE;
  487. }
  488. ECursorType LLToolDragAndDrop::acceptanceToCursor( EAcceptance acceptance )
  489. {
  490. switch (acceptance)
  491. {
  492. case ACCEPT_YES_MULTI:
  493. if (mCargoIDs.size() > 1)
  494. {
  495. mCursor = UI_CURSOR_ARROWDRAGMULTI;
  496. }
  497. else
  498. {
  499. mCursor = UI_CURSOR_ARROWDRAG;
  500. }
  501. break;
  502. case ACCEPT_YES_SINGLE:
  503. if (mCargoIDs.size() > 1)
  504. {
  505. mToolTipMsg = LLTrans::getString("TooltipMustSingleDrop");
  506. mCursor = UI_CURSOR_NO;
  507. }
  508. else
  509. {
  510. mCursor = UI_CURSOR_ARROWDRAG;
  511. }
  512. break;
  513. case ACCEPT_NO_LOCKED:
  514. mCursor = UI_CURSOR_NOLOCKED;
  515. break;
  516. case ACCEPT_NO:
  517. mCursor = UI_CURSOR_NO;
  518. break;
  519. case ACCEPT_YES_COPY_MULTI:
  520. if (mCargoIDs.size() > 1)
  521. {
  522. mCursor = UI_CURSOR_ARROWCOPYMULTI;
  523. }
  524. else
  525. {
  526. mCursor = UI_CURSOR_ARROWCOPY;
  527. }
  528. break;
  529. case ACCEPT_YES_COPY_SINGLE:
  530. if (mCargoIDs.size() > 1)
  531. {
  532. mToolTipMsg = LLTrans::getString("TooltipMustSingleDrop");
  533. mCursor = UI_CURSOR_NO;
  534. }
  535. else
  536. {
  537. mCursor = UI_CURSOR_ARROWCOPY;
  538. }
  539. break;
  540. case ACCEPT_POSTPONED:
  541. break;
  542. default:
  543. llassert( FALSE );
  544. }
  545. return mCursor;
  546. }
  547. BOOL LLToolDragAndDrop::handleHover( S32 x, S32 y, MASK mask )
  548. {
  549. EAcceptance acceptance = ACCEPT_NO;
  550. dragOrDrop( x, y, mask, FALSE, &acceptance );
  551. ECursorType cursor = acceptanceToCursor(acceptance);
  552. gViewerWindow->getWindow()->setCursor( cursor );
  553. lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolDragAndDrop" << llendl;
  554. return TRUE;
  555. }
  556. BOOL LLToolDragAndDrop::handleKey(KEY key, MASK mask)
  557. {
  558. if (key == KEY_ESCAPE)
  559. {
  560. // cancel drag and drop operation
  561. endDrag();
  562. return TRUE;
  563. }
  564. return FALSE;
  565. }
  566. BOOL LLToolDragAndDrop::handleToolTip(S32 x, S32 y, MASK mask)
  567. {
  568. if (!mToolTipMsg.empty())
  569. {
  570. LLToolTipMgr::instance().unblockToolTips();
  571. LLToolTipMgr::instance().show(LLToolTip::Params()
  572. .message(mToolTipMsg)
  573. .delay_time(gSavedSettings.getF32( "DragAndDropToolTipDelay" )));
  574. return TRUE;
  575. }
  576. return FALSE;
  577. }
  578. void LLToolDragAndDrop::handleDeselect()
  579. {
  580. mToolTipMsg.clear();
  581. LLToolTipMgr::instance().blockToolTips();
  582. }
  583. // protected
  584. void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
  585. EAcceptance* acceptance)
  586. {
  587. *acceptance = ACCEPT_YES_MULTI;
  588. BOOL handled = FALSE;
  589. LLView* top_view = gFocusMgr.getTopCtrl();
  590. LLViewerInventoryItem* item;
  591. LLViewerInventoryCategory* cat;
  592. mToolTipMsg.clear();
  593. // Increment the operation id for every drop
  594. if (drop)
  595. {
  596. sOperationId++;
  597. }
  598. if (top_view)
  599. {
  600. handled = TRUE;
  601. for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
  602. {
  603. LLInventoryObject* cargo = locateInventory(item, cat);
  604. if (cargo)
  605. {
  606. S32 local_x, local_y;
  607. top_view->screenPointToLocal( x, y, &local_x, &local_y );
  608. EAcceptance item_acceptance = ACCEPT_NO;
  609. handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE,
  610. mCargoTypes[mCurItemIndex],
  611. (void*)cargo,
  612. &item_acceptance,
  613. mToolTipMsg);
  614. if (handled)
  615. {
  616. // use sort order to determine priority of acceptance
  617. *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
  618. }
  619. }
  620. else
  621. {
  622. return;
  623. }
  624. }
  625. // all objects passed, go ahead and perform drop if necessary
  626. if (handled && drop && (U32)*acceptance >= ACCEPT_YES_COPY_SINGLE)
  627. {
  628. if ((U32)*acceptance < ACCEPT_YES_COPY_MULTI &&
  629. mCargoIDs.size() > 1)
  630. {
  631. // tried to give multi-cargo to a single-acceptor - refuse and return.
  632. *acceptance = ACCEPT_NO;
  633. return;
  634. }
  635. for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
  636. {
  637. LLInventoryObject* cargo = locateInventory(item, cat);
  638. if (cargo)
  639. {
  640. S32 local_x, local_y;
  641. EAcceptance item_acceptance;
  642. top_view->screenPointToLocal( x, y, &local_x, &local_y );
  643. handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, TRUE,
  644. mCargoTypes[mCurItemIndex],
  645. (void*)cargo,
  646. &item_acceptance,
  647. mToolTipMsg);
  648. }
  649. }
  650. }
  651. if (handled)
  652. {
  653. mLastAccept = (EAcceptance)*acceptance;
  654. }
  655. }
  656. if (!handled)
  657. {
  658. handled = TRUE;
  659. LLRootView* root_view = gViewerWindow->getRootView();
  660. for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
  661. {
  662. LLInventoryObject* cargo = locateInventory(item, cat);
  663. // fix for EXT-3191
  664. if (NULL == cargo) return;
  665. EAcceptance item_acceptance = ACCEPT_NO;
  666. handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE,
  667. mCargoTypes[mCurItemIndex],
  668. (void*)cargo,
  669. &item_acceptance,
  670. mToolTipMsg);
  671. if (handled)
  672. {
  673. // use sort order to determine priority of acceptance
  674. *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
  675. }
  676. }
  677. // all objects passed, go ahead and perform drop if necessary
  678. if (handled && drop && (U32)*acceptance > ACCEPT_NO_LOCKED)
  679. {
  680. if ((U32)*acceptance < ACCEPT_YES_COPY_MULTI &&
  681. mCargoIDs.size() > 1)
  682. {
  683. // tried to give multi-cargo to a single-acceptor - refuse and return.
  684. *acceptance = ACCEPT_NO;
  685. return;
  686. }
  687. for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
  688. {
  689. LLInventoryObject* cargo = locateInventory(item, cat);
  690. if (cargo)
  691. {
  692. EAcceptance item_acceptance;
  693. handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE,
  694. mCargoTypes[mCurItemIndex],
  695. (void*)cargo,
  696. &item_acceptance,
  697. mToolTipMsg);
  698. }
  699. }
  700. }
  701. if (handled)
  702. {
  703. mLastAccept = (EAcceptance)*acceptance;
  704. }
  705. }
  706. if (!handled)
  707. {
  708. // Disallow drag and drop to 3D from the outbox
  709. const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false);
  710. if (outbox_id.notNull())
  711. {
  712. for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
  713. {
  714. if (gInventory.isObjectDescendentOf(mCargoIDs[item_index], outbox_id))
  715. {
  716. *acceptance = ACCEPT_NO;
  717. mToolTipMsg = LLTrans::getString("TooltipOutboxDragToWorld");
  718. return;
  719. }
  720. }
  721. }
  722. dragOrDrop3D( x, y, mask, drop, acceptance );
  723. }
  724. }
  725. void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* acceptance )
  726. {
  727. mDrop = drop;
  728. if (mDrop)
  729. {
  730. // don't allow drag and drop onto transparent objects
  731. pick(gViewerWindow->pickImmediate(x, y, FALSE));
  732. }
  733. else
  734. {
  735. // don't allow drag and drop onto transparent objects
  736. gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE);
  737. }
  738. *acceptance = mLastAccept;
  739. }
  740. void LLToolDragAndDrop::pickCallback(const LLPickInfo& pick_info)
  741. {
  742. if (getInstance() != NULL)
  743. {
  744. getInstance()->pick(pick_info);
  745. }
  746. }
  747. void LLToolDragAndDrop::pick(const LLPickInfo& pick_info)
  748. {
  749. EDropTarget target = DT_NONE;
  750. S32 hit_face = -1;
  751. LLViewerObject* hit_obj = pick_info.getObject();
  752. LLSelectMgr::getInstance()->unhighlightAll();
  753. bool highlight_object = false;
  754. // Treat attachments as part of the avatar they are attached to.
  755. if (hit_obj != NULL)
  756. {
  757. // don't allow drag and drop on grass, trees, etc.
  758. if (pick_info.mPickType == LLPickInfo::PICK_FLORA)
  759. {
  760. mCursor = UI_CURSOR_NO;
  761. gViewerWindow->getWindow()->setCursor( mCursor );
  762. return;
  763. }
  764. if (hit_obj->isAttachment() && !hit_obj->isHUDAttachment())
  765. {
  766. LLVOAvatar* avatar = LLVOAvatar::findAvatarFromAttachment( hit_obj );
  767. if (!avatar)
  768. {
  769. mLastAccept = ACCEPT_NO;
  770. mCursor = UI_CURSOR_NO;
  771. gViewerWindow->getWindow()->setCursor( mCursor );
  772. return;
  773. }
  774. hit_obj = avatar;
  775. }
  776. if (hit_obj->isAvatar())
  777. {
  778. if (((LLVOAvatar*) hit_obj)->isSelf())
  779. {
  780. target = DT_SELF;
  781. hit_face = -1;
  782. }
  783. else
  784. {
  785. target = DT_AVATAR;
  786. hit_face = -1;
  787. }
  788. }
  789. else
  790. {
  791. target = DT_OBJECT;
  792. hit_face = pick_info.mObjectFace;
  793. highlight_object = true;
  794. }
  795. }
  796. else if (pick_info.mPickType == LLPickInfo::PICK_LAND)
  797. {
  798. target = DT_LAND;
  799. hit_face = -1;
  800. }
  801. mLastAccept = ACCEPT_YES_MULTI;
  802. for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
  803. {
  804. const S32 item_index = mCurItemIndex;
  805. const EDragAndDropType dad_type = mCargoTypes[item_index];
  806. // Call the right implementation function
  807. mLastAccept = (EAcceptance)llmin(
  808. (U32)mLastAccept,
  809. (U32)callMemberFunction(*this,
  810. LLDragAndDropDictionary::instance().get(dad_type, target))
  811. (hit_obj, hit_face, pick_info.mKeyMask, FALSE));
  812. }
  813. if (mDrop && ((U32)mLastAccept >= ACCEPT_YES_COPY_SINGLE))
  814. {
  815. // if target allows multi-drop or there is only one item being dropped, go ahead
  816. if ((mLastAccept >= ACCEPT_YES_COPY_MULTI) || (mCargoIDs.size() == 1))
  817. {
  818. // Target accepts multi, or cargo is a single-drop
  819. for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
  820. {
  821. const S32 item_index = mCurItemIndex;
  822. const EDragAndDropType dad_type = mCargoTypes[item_index];
  823. // Call the right implementation function
  824. (U32)callMemberFunction(*this,
  825. LLDragAndDropDictionary::instance().get(dad_type, target))
  826. (hit_obj, hit_face, pick_info.mKeyMask, TRUE);
  827. }
  828. }
  829. else
  830. {
  831. // Target does not accept multi, but cargo is multi
  832. mLastAccept = ACCEPT_NO;
  833. }
  834. }
  835. if (highlight_object && mLastAccept > ACCEPT_NO_LOCKED)
  836. {
  837. // if any item being dragged will be applied to the object under our cursor
  838. // highlight that object
  839. for (S32 i = 0; i < (S32)mCargoIDs.size(); i++)
  840. {
  841. if (mCargoTypes[i] != DAD_OBJECT || (pick_info.mKeyMask & MASK_CONTROL))
  842. {
  843. LLSelectMgr::getInstance()->highlightObjectAndFamily(hit_obj);
  844. break;
  845. }
  846. }
  847. }
  848. ECursorType cursor = acceptanceToCursor( mLastAccept );
  849. gViewerWindow->getWindow()->setCursor( cursor );
  850. mLastHitPos = pick_info.mPosGlobal;
  851. mLastCameraPos = gAgentCamera.getCameraPositionGlobal();
  852. }
  853. // static
  854. BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
  855. LLInventoryItem* item,
  856. LLToolDragAndDrop::ESource source,
  857. const LLUUID& src_id)
  858. {
  859. // Always succeed if....
  860. // texture is from the library
  861. // or already in the contents of the object
  862. if (SOURCE_LIBRARY == source)
  863. {
  864. // dropping a texture from the library always just works.
  865. return TRUE;
  866. }
  867. // In case the inventory has not been updated (e.g. due to some recent operation
  868. // causing a dirty inventory), stall the user while fetching the inventory.
  869. if (hit_obj->isInventoryDirty())
  870. {
  871. hit_obj->fetchInventoryFromServer();
  872. LLSD args;
  873. args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again.";
  874. LLNotificationsUtil::add("ErrorMessage", args);
  875. return FALSE;
  876. }
  877. if (hit_obj->getInventoryItemByAsset(item->getAssetUUID()))
  878. {
  879. // if the asset is already in the object's inventory
  880. // then it can always be added to a side.
  881. // This saves some work if the task's inventory is already loaded
  882. // and ensures that the texture item is only added once.
  883. return TRUE;
  884. }
  885. if (!item) return FALSE;
  886. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  887. if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
  888. {
  889. // Check that we can add the texture as inventory to the object
  890. if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
  891. {
  892. return FALSE;
  893. }
  894. // make sure the object has the texture in it's inventory.
  895. if (SOURCE_AGENT == source)
  896. {
  897. // Remove the texture from local inventory. The server
  898. // will actually remove the item from agent inventory.
  899. gInventory.deleteObject(item->getUUID());
  900. gInventory.notifyObservers();
  901. }
  902. else if (SOURCE_WORLD == source)
  903. {
  904. // *FIX: if the objects are in different regions, and the
  905. // source region has crashed, you can bypass these
  906. // permissions.
  907. LLViewerObject* src_obj = gObjectList.findObject(src_id);
  908. if (src_obj)
  909. {
  910. src_obj->removeInventory(item->getUUID());
  911. }
  912. else
  913. {
  914. llwarns << "Unable to find source object." << llendl;
  915. return FALSE;
  916. }
  917. }
  918. // Add the texture item to the target object's inventory.
  919. hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
  920. // TODO: Check to see if adding the item was successful; if not, then
  921. // we should return false here.
  922. }
  923. else if (!item->getPermissions().allowOperationBy(PERM_TRANSFER,
  924. gAgent.getID()))
  925. {
  926. // Check that we can add the texture as inventory to the object
  927. if (willObjectAcceptInventory(hit_obj,item) < ACCEPT_YES_COPY_SINGLE )
  928. {
  929. return FALSE;
  930. }
  931. // *FIX: may want to make sure agent can paint hit_obj.
  932. // Add the texture item to the target object's inventory.
  933. hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
  934. // Force the object to update its refetch its inventory so it has this texture.
  935. hit_obj->fetchInventoryFromServer();
  936. // TODO: Check to see if adding the item was successful; if not, then
  937. // we should return false here.
  938. }
  939. return TRUE;
  940. }
  941. void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
  942. LLInventoryItem* item,
  943. LLToolDragAndDrop::ESource source,
  944. const LLUUID& src_id)
  945. {
  946. if (!item)
  947. {
  948. llwarns << "LLToolDragAndDrop::dropTextureAllFaces no texture item." << llendl;
  949. return;
  950. }
  951. LLUUID asset_id = item->getAssetUUID();
  952. BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
  953. if (!success)
  954. {
  955. return;
  956. }
  957. LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id);
  958. LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
  959. S32 num_faces = hit_obj->getNumTEs();
  960. for( S32 face = 0; face < num_faces; face++ )
  961. {
  962. // update viewer side image in anticipation of update from simulator
  963. hit_obj->setTEImage(face, image);
  964. dialog_refresh_all();
  965. }
  966. // send the update to the simulator
  967. hit_obj->sendTEUpdate();
  968. }
  969. void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
  970. LLInventoryItem* item,
  971. LLToolDragAndDrop::ESource source,
  972. const LLUUID& src_id)
  973. {
  974. if (!item)
  975. {
  976. llwarns << "no inventory item." << llendl;
  977. return;
  978. }
  979. LLUUID asset_id = item->getAssetUUID();
  980. BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
  981. if(!success)
  982. {
  983. return;
  984. }
  985. LLSculptParams sculpt_params;
  986. sculpt_params.setSculptTexture(asset_id);
  987. sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
  988. hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
  989. dialog_refresh_all();
  990. }
  991. /*
  992. void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
  993. {
  994. if (hit_face == -1) return;
  995. LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID());
  996. avatar->userSetOptionalTE( hit_face, image);
  997. }
  998. */
  999. void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
  1000. S32 hit_face,
  1001. LLInventoryItem* item,
  1002. LLToolDragAndDrop::ESource source,
  1003. const LLUUID& src_id)
  1004. {
  1005. if (hit_face == -1) return;
  1006. if (!item)
  1007. {
  1008. llwarns << "LLToolDragAndDrop::dropTextureOneFace no texture item." << llendl;
  1009. return;
  1010. }
  1011. LLUUID asset_id = item->getAssetUUID();
  1012. BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
  1013. if (!success)
  1014. {
  1015. return;
  1016. }
  1017. // update viewer side image in anticipation of update from simulator
  1018. LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id);
  1019. LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
  1020. hit_obj->setTEImage(hit_face, image);
  1021. dialog_refresh_all();
  1022. // send the update to the simulator
  1023. hit_obj->sendTEUpdate();
  1024. }
  1025. void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj,
  1026. LLInventoryItem* item,
  1027. BOOL active,
  1028. ESource source,
  1029. const LLUUID& src_id)
  1030. {
  1031. // *HACK: In order to resolve SL-22177, we need to block drags
  1032. // from notecards and objects onto other objects.
  1033. if ((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource)
  1034. || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource))
  1035. {
  1036. llwarns << "Call to LLToolDragAndDrop::dropScript() from world"
  1037. << " or notecard." << llendl;
  1038. return;
  1039. }
  1040. if (hit_obj && item)
  1041. {
  1042. LLPointer<LLViewerInventoryItem> new_script = new LLViewerInventoryItem(item);
  1043. if (!item->getPermissions().allowCopyBy(gAgent.getID()))
  1044. {
  1045. if (SOURCE_AGENT == source)
  1046. {
  1047. // Remove the script from local inventory. The server
  1048. // will actually remove the item from agent inventory.
  1049. gInventory.deleteObject(item->getUUID());
  1050. gInventory.notifyObservers();
  1051. }
  1052. else if (SOURCE_WORLD == source)
  1053. {
  1054. // *FIX: if the objects are in different regions, and
  1055. // the source region has crashed, you can bypass
  1056. // these permissions.
  1057. LLViewerObject* src_obj = gObjectList.findObject(src_id);
  1058. if (src_obj)
  1059. {
  1060. src_obj->removeInventory(item->getUUID());
  1061. }
  1062. else
  1063. {
  1064. llwarns << "Unable to find source object." << llendl;
  1065. return;
  1066. }
  1067. }
  1068. }
  1069. hit_obj->saveScript(new_script, active, true);
  1070. gFloaterTools->dirty();
  1071. // VEFFECT: SetScript
  1072. LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
  1073. effectp->setSourceObject(gAgentAvatarp);
  1074. effectp->setTargetObject(hit_obj);
  1075. effectp->setDuration(LL_HUD_DUR_SHORT);
  1076. effectp->setColor(LLColor4U(gAgent.getEffectColor()));
  1077. }
  1078. }
  1079. void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
  1080. BOOL bypass_sim_raycast,
  1081. BOOL from_task_inventory,
  1082. BOOL remove_from_inventory)
  1083. {
  1084. LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mLastHitPos);
  1085. if (!regionp)
  1086. {
  1087. llwarns << "Couldn't find region to rez object" << llendl;
  1088. return;
  1089. }
  1090. //llinfos << "Rezzing object" << llendl;
  1091. make_ui_sound("UISndObjectRezIn");
  1092. LLViewerInventoryItem* item;
  1093. LLViewerInventoryCategory* cat;
  1094. locateInventory(item, cat);
  1095. if (!item || !item->isFinished()) return;
  1096. //if (regionp
  1097. // && (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX))
  1098. //{
  1099. // LLFirstUse::useSandbox();
  1100. //}
  1101. // check if it cannot be copied, and mark as remove if it is -
  1102. // this will remove the object from inventory after rez. Only
  1103. // bother with this check if we would not normally remove from
  1104. // inventory.
  1105. if (!remove_from_inventory
  1106. && !item->getPermissions().allowCopyBy(gAgent.getID()))
  1107. {
  1108. remove_from_inventory = TRUE;
  1109. }
  1110. // Limit raycast to a single object.
  1111. // Speeds up server raycast + avoid problems with server ray
  1112. // hitting objects that were clipped by the near plane or culled
  1113. // on the viewer.
  1114. LLUUID ray_target_id;
  1115. if (raycast_target)
  1116. {
  1117. ray_target_id = raycast_target->getID();
  1118. }
  1119. else
  1120. {
  1121. ray_target_id.setNull();
  1122. }
  1123. // Check if it's in the trash.
  1124. bool is_in_trash = false;
  1125. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1126. if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
  1127. {
  1128. is_in_trash = true;
  1129. remove_from_inventory = TRUE;
  1130. }
  1131. LLUUID source_id = from_task_inventory ? mSourceID : LLUUID::null;
  1132. // Select the object only if we're editing.
  1133. BOOL rez_selected = LLToolMgr::getInstance()->inEdit();
  1134. LLVector3 ray_start = regionp->getPosRegionFromGlobal(mLastCameraPos);
  1135. LLVector3 ray_end = regionp->getPosRegionFromGlobal(mLastHitPos);
  1136. // currently the ray's end point is an approximation,
  1137. // and is sometimes too short (causing failure.) so we
  1138. // double the ray's length:
  1139. if (bypass_sim_raycast == FALSE)
  1140. {
  1141. LLVector3 ray_direction = ray_start - ray_end;
  1142. ray_end = ray_end - ray_direction;
  1143. }
  1144. // Message packing code should be it's own uninterrupted block
  1145. LLMessageSystem* msg = gMessageSystem;
  1146. if (mSource == SOURCE_NOTECARD)
  1147. {
  1148. msg->newMessageFast(_PREHASH_RezObjectFromNotecard);
  1149. }
  1150. else
  1151. {
  1152. msg->newMessageFast(_PREHASH_RezObject);
  1153. }
  1154. msg->nextBlockFast(_PREHASH_AgentData);
  1155. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1156. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1157. msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
  1158. msg->nextBlock("RezData");
  1159. // if it's being rezzed from task inventory, we need to enable
  1160. // saving it back into the task inventory.
  1161. // *FIX: We can probably compress this to a single byte, since I
  1162. // think folderid == mSourceID. This will be a later
  1163. // optimization.
  1164. msg->addUUIDFast(_PREHASH_FromTaskID, source_id);
  1165. msg->addU8Fast(_PREHASH_BypassRaycast, (U8) bypass_sim_raycast);
  1166. msg->addVector3Fast(_PREHASH_RayStart, ray_start);
  1167. msg->addVector3Fast(_PREHASH_RayEnd, ray_end);
  1168. msg->addUUIDFast(_PREHASH_RayTargetID, ray_target_id );
  1169. msg->addBOOLFast(_PREHASH_RayEndIsIntersection, FALSE);
  1170. msg->addBOOLFast(_PREHASH_RezSelected, rez_selected);
  1171. msg->addBOOLFast(_PREHASH_RemoveItem, remove_from_inventory);
  1172. // deal with permissions slam logic
  1173. pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
  1174. LLUUID folder_id = item->getParentUUID();
  1175. if ((SOURCE_LIBRARY == mSource) || (is_in_trash))
  1176. {
  1177. // since it's coming from the library or trash, we want to not
  1178. // 'take' it back to the same place.
  1179. item->setParent(LLUUID::null);
  1180. // *TODO this code isn't working - the parent (FolderID) is still
  1181. // set when the object is "taken". so code on the "take" side is
  1182. // checking for trash and library as well (llviewermenu.cpp)
  1183. }
  1184. if (mSource == SOURCE_NOTECARD)
  1185. {
  1186. msg->nextBlockFast(_PREHASH_NotecardData);
  1187. msg->addUUIDFast(_PREHASH_NotecardItemID, mSourceID);
  1188. msg->addUUIDFast(_PREHASH_ObjectID, mObjectID);
  1189. msg->nextBlockFast(_PREHASH_InventoryData);
  1190. msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
  1191. }
  1192. else
  1193. {
  1194. msg->nextBlockFast(_PREHASH_InventoryData);
  1195. item->packMessage(msg);
  1196. }
  1197. msg->sendReliable(regionp->getHost());
  1198. // back out the change. no actual internal changes take place.
  1199. item->setParent(folder_id);
  1200. // If we're going to select it, get ready for the incoming
  1201. // selected object.
  1202. if (rez_selected)
  1203. {
  1204. LLSelectMgr::getInstance()->deselectAll();
  1205. gViewerWindow->getWindow()->incBusyCount();
  1206. }
  1207. if (remove_from_inventory)
  1208. {
  1209. // Delete it from inventory immediately so that users cannot
  1210. // easily bypass copy protection in laggy situations. If the
  1211. // rez fails, we will put it back on the server.
  1212. gInventory.deleteObject(item->getUUID());
  1213. gInventory.notifyObservers();
  1214. }
  1215. // VEFFECT: DropObject
  1216. LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
  1217. effectp->setSourceObject(gAgentAvatarp);
  1218. effectp->setPositionGlobal(mLastHitPos);
  1219. effectp->setDuration(LL_HUD_DUR_SHORT);
  1220. effectp->setColor(LLColor4U(gAgent.getEffectColor()));
  1221. LLViewerStats::getInstance()->incStat(LLViewerStats::ST_REZ_COUNT);
  1222. }
  1223. void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj,
  1224. LLInventoryItem* item,
  1225. LLToolDragAndDrop::ESource source,
  1226. const LLUUID& src_id)
  1227. {
  1228. // *HACK: In order to resolve SL-22177, we need to block drags
  1229. // from notecards and objects onto other objects.
  1230. if ((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource)
  1231. || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource))
  1232. {
  1233. llwarns << "Call to LLToolDragAndDrop::dropInventory() from world"
  1234. << " or notecard." << llendl;
  1235. return;
  1236. }
  1237. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  1238. time_t creation_date = time_corrected();
  1239. new_item->setCreationDate(creation_date);
  1240. if (!item->getPermissions().allowCopyBy(gAgent.getID()))
  1241. {
  1242. if (SOURCE_AGENT == source)
  1243. {
  1244. // Remove the inventory item from local inventory. The
  1245. // server will actually remove the item from agent
  1246. // inventory.
  1247. gInventory.deleteObject(item->getUUID());
  1248. gInventory.notifyObservers();
  1249. }
  1250. else if (SOURCE_WORLD == source)
  1251. {
  1252. // *FIX: if the objects are in different regions, and the
  1253. // source region has crashed, you can bypass these
  1254. // permissions.
  1255. LLViewerObject* src_obj = gObjectList.findObject(src_id);
  1256. if (src_obj)
  1257. {
  1258. src_obj->removeInventory(item->getUUID());
  1259. }
  1260. else
  1261. {
  1262. llwarns << "Unable to find source object." << llendl;
  1263. return;
  1264. }
  1265. }
  1266. }
  1267. hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
  1268. if (LLFloaterReg::instanceVisible("build"))
  1269. {
  1270. // *FIX: only show this if panel not expanded?
  1271. LLFloaterReg::showInstance("build", "Content");
  1272. }
  1273. // VEFFECT: AddToInventory
  1274. LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
  1275. effectp->setSourceObject(gAgentAvatarp);
  1276. effectp->setTargetObject(hit_obj);
  1277. effectp->setDuration(LL_HUD_DUR_SHORT);
  1278. effectp->setColor(LLColor4U(gAgent.getEffectColor()));
  1279. gFloaterTools->dirty();
  1280. }
  1281. // accessor that looks at permissions, copyability, and names of
  1282. // inventory items to determine if a drop would be ok.
  1283. EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item)
  1284. {
  1285. // check the basics
  1286. if (!item || !obj) return ACCEPT_NO;
  1287. // HACK: downcast
  1288. LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item;
  1289. if (!vitem->isFinished()) return ACCEPT_NO;
  1290. if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links
  1291. // deny attempts to drop from an object onto itself. This is to
  1292. // help make sure that drops that are from an object to an object
  1293. // don't have to worry about order of evaluation. Think of this
  1294. // like check for self in assignment.
  1295. if(obj->getID() == item->getParentUUID())
  1296. {
  1297. return ACCEPT_NO;
  1298. }
  1299. //BOOL copy = (perm.allowCopyBy(gAgent.getID(),
  1300. // gAgent.getGroupID())
  1301. // && (obj->mPermModify || obj->mFlagAllowInventoryAdd));
  1302. BOOL worn = FALSE;
  1303. LLVOAvatarSelf* my_avatar = NULL;
  1304. switch(item->getType())
  1305. {
  1306. case LLAssetType::AT_OBJECT:
  1307. my_avatar = gAgentAvatarp;
  1308. if(my_avatar && my_avatar->isWearingAttachment(item->getUUID()))
  1309. {
  1310. worn = TRUE;
  1311. }
  1312. break;
  1313. case LLAssetType::AT_BODYPART:
  1314. case LLAssetType::AT_CLOTHING:
  1315. if(gAgentWearables.isWearingItem(item->getUUID()))
  1316. {
  1317. worn = TRUE;
  1318. }
  1319. break;
  1320. case LLAssetType::AT_CALLINGCARD:
  1321. // Calling Cards in object are disabled for now
  1322. // because of incomplete LSL support. See STORM-1117.
  1323. return ACCEPT_NO;
  1324. default:
  1325. break;
  1326. }
  1327. const LLPermissions& perm = item->getPermissions();
  1328. BOOL modify = (obj->permModify() || obj->flagAllowInventoryAdd());
  1329. BOOL transfer = FALSE;
  1330. if((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
  1331. || perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
  1332. {
  1333. transfer = TRUE;
  1334. }
  1335. BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
  1336. BOOL attached = obj->isAttachment();
  1337. BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
  1338. if(attached && !unrestricted)
  1339. {
  1340. return ACCEPT_NO_LOCKED;
  1341. }
  1342. else if(modify && transfer && volume && !worn)
  1343. {
  1344. return ACCEPT_YES_MULTI;
  1345. }
  1346. else if(!modify)
  1347. {
  1348. return ACCEPT_NO_LOCKED;
  1349. }
  1350. return ACCEPT_NO;
  1351. }
  1352. static void give_inventory_cb(const LLSD& notification, const LLSD& response)
  1353. {
  1354. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1355. // if Cancel pressed
  1356. if (option == 1)
  1357. {
  1358. return;
  1359. }
  1360. LLSD payload = notification["payload"];
  1361. const LLUUID& session_id = payload["session_id"];
  1362. const LLUUID& agent_id = payload["agent_id"];
  1363. LLViewerInventoryItem * inv_item = gInventory.getItem(payload["item_id"]);
  1364. if (NULL == inv_item)
  1365. {
  1366. llassert(NULL != inv_item);
  1367. return;
  1368. }
  1369. if (LLGiveInventory::doGiveInventoryItem(agent_id, inv_item, session_id))
  1370. {
  1371. if ("avatarpicker" == payload["d&d_dest"].asString())
  1372. {
  1373. LLFloaterReg::hideInstance("avatar_picker");
  1374. }
  1375. LLNotificationsUtil::add("ItemsShared");
  1376. }
  1377. }
  1378. static void show_item_sharing_confirmation(const std::string name,
  1379. LLViewerInventoryItem* inv_item,
  1380. const LLSD& dest,
  1381. const LLUUID& dest_agent,
  1382. const LLUUID& session_id = LLUUID::null)
  1383. {
  1384. if (!inv_item)
  1385. {
  1386. llassert(NULL != inv_item);
  1387. return;
  1388. }
  1389. LLSD substitutions;
  1390. substitutions["RESIDENTS"] = name;
  1391. substitutions["ITEMS"] = inv_item->getName();
  1392. LLSD payload;
  1393. payload["agent_id"] = dest_agent;
  1394. payload["item_id"] = inv_item->getUUID();
  1395. payload["session_id"] = session_id;
  1396. payload["d&d_dest"] = dest.asString();
  1397. LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, payload, &give_inventory_cb);
  1398. }
  1399. static void get_name_cb(const LLUUID& id,
  1400. const std::string& full_name,
  1401. LLViewerInventoryItem* inv_item,
  1402. const LLSD& dest,
  1403. const LLUUID& dest_agent)
  1404. {
  1405. show_item_sharing_confirmation(full_name,
  1406. inv_item,
  1407. dest,
  1408. id,
  1409. LLUUID::null);
  1410. }
  1411. // function used as drag-and-drop handler for simple agent give inventory requests
  1412. //static
  1413. bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_id, BOOL drop,
  1414. EDragAndDropType cargo_type,
  1415. void* cargo_data,
  1416. EAcceptance* accept,
  1417. const LLSD& dest)
  1418. {
  1419. // check the type
  1420. switch(cargo_type)
  1421. {
  1422. case DAD_TEXTURE:
  1423. case DAD_SOUND:
  1424. case DAD_LANDMARK:
  1425. case DAD_SCRIPT:
  1426. case DAD_OBJECT:
  1427. case DAD_NOTECARD:
  1428. case DAD_CLOTHING:
  1429. case DAD_BODYPART:
  1430. case DAD_ANIMATION:
  1431. case DAD_GESTURE:
  1432. case DAD_CALLINGCARD:
  1433. case DAD_MESH:
  1434. {
  1435. LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
  1436. if(gInventory.getItem(inv_item->getUUID())
  1437. && LLGiveInventory::isInventoryGiveAcceptable(inv_item))
  1438. {
  1439. // *TODO: get multiple object transfers working
  1440. *accept = ACCEPT_YES_COPY_SINGLE;
  1441. if(drop)
  1442. {
  1443. LLIMModel::LLIMSession * session = LLIMModel::instance().findIMSession(session_id);
  1444. // If no IM session found get the destination agent's name by id.
  1445. if (NULL == session)
  1446. {
  1447. std::string fullname;
  1448. // If destination agent's name is found in cash proceed to showing the confirmation dialog.
  1449. // Otherwise set up a callback to show the dialog when the name arrives.
  1450. if (gCacheName->getFullName(dest_agent, fullname))
  1451. {
  1452. show_item_sharing_confirmation(fullname, inv_item, dest, dest_agent, LLUUID::null);
  1453. }
  1454. else
  1455. {
  1456. gCacheName->get(dest_agent, false, boost::bind(&get_name_cb, _1, _2, inv_item, dest, dest_agent));
  1457. }
  1458. return true;
  1459. }
  1460. // If an IM session with destination agent is found item offer will be logged in this session.
  1461. show_item_sharing_confirmation(session->mName, inv_item, dest, dest_agent, session_id);
  1462. }
  1463. }
  1464. else
  1465. {
  1466. // It's not in the user's inventory (it's probably
  1467. // in an object's contents), so disallow dragging
  1468. // it here. You can't give something you don't
  1469. // yet have.
  1470. *accept = ACCEPT_NO;
  1471. }
  1472. break;
  1473. }
  1474. case DAD_CATEGORY:
  1475. {
  1476. LLViewerInventoryCategory* inv_cat = (LLViewerInventoryCategory*)cargo_data;
  1477. if( gInventory.getCategory( inv_cat->getUUID() ) )
  1478. {
  1479. // *TODO: get multiple object transfers working
  1480. *accept = ACCEPT_YES_COPY_SINGLE;
  1481. if(drop)
  1482. {
  1483. LLGiveInventory::doGiveInventoryCategory(dest_agent, inv_cat, session_id);
  1484. }
  1485. }
  1486. else
  1487. {
  1488. // It's not in the user's inventory (it's probably
  1489. // in an object's contents), so disallow dragging
  1490. // it here. You can't give something you don't
  1491. // yet have.
  1492. *accept = ACCEPT_NO;
  1493. }
  1494. break;
  1495. }
  1496. default:
  1497. *accept = ACCEPT_NO;
  1498. break;
  1499. }
  1500. return TRUE;
  1501. }
  1502. ///
  1503. /// Methods called in the drag & drop array
  1504. ///
  1505. EAcceptance LLToolDragAndDrop::dad3dNULL(
  1506. LLViewerObject*, S32, MASK, BOOL)
  1507. {
  1508. lldebugs << "LLToolDragAndDrop::dad3dNULL()" << llendl;
  1509. return ACCEPT_NO;
  1510. }
  1511. EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
  1512. LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
  1513. {
  1514. lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl;
  1515. // must be in the user's inventory
  1516. if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
  1517. {
  1518. return ACCEPT_NO;
  1519. }
  1520. LLViewerInventoryItem* item;
  1521. LLViewerInventoryCategory* cat;
  1522. locateInventory(item, cat);
  1523. if (!item || !item->isFinished()) return ACCEPT_NO;
  1524. // must not be in the trash
  1525. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1526. if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
  1527. {
  1528. return ACCEPT_NO;
  1529. }
  1530. // must not be already wearing it
  1531. LLVOAvatarSelf* avatar = gAgentAvatarp;
  1532. if( !avatar || avatar->isWearingAttachment(item->getUUID()) )
  1533. {
  1534. return ACCEPT_NO;
  1535. }
  1536. const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
  1537. if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id))
  1538. {
  1539. return ACCEPT_NO;
  1540. }
  1541. if( drop )
  1542. {
  1543. if(mSource == SOURCE_LIBRARY)
  1544. {
  1545. LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
  1546. copy_inventory_item(
  1547. gAgent.getID(),
  1548. item->getPermissions().getOwner(),
  1549. item->getUUID(),
  1550. LLUUID::null,
  1551. std::string(),
  1552. cb);
  1553. }
  1554. else
  1555. {
  1556. rez_attachment(item, 0);
  1557. }
  1558. }
  1559. return ACCEPT_YES_SINGLE;
  1560. }
  1561. EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
  1562. LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
  1563. {
  1564. if (mSource == SOURCE_WORLD)
  1565. {
  1566. return dad3dRezFromObjectOnLand(obj, face, mask, drop);
  1567. }
  1568. lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnLan…