PageRenderTime 124ms CodeModel.GetById 32ms RepoModel.GetById 2ms app.codeStats 1ms

/indra/newview/llinventorybridge.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2423 lines | 1934 code | 297 blank | 192 comment | 447 complexity | 66041d855fcc39989ddec1ec50bf98f8 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llinventorybridge.cpp
  3. * @brief Implementation of the Inventory-Folder-View-Bridge classes.
  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 "llinventorybridge.h"
  28. // external projects
  29. #include "lltransfersourceasset.h"
  30. #include "llavatarnamecache.h" // IDEVO
  31. #include "llagent.h"
  32. #include "llagentcamera.h"
  33. #include "llagentwearables.h"
  34. #include "llappearancemgr.h"
  35. #include "llattachmentsmgr.h"
  36. #include "llavataractions.h"
  37. #include "llfloateropenobject.h"
  38. #include "llfloaterreg.h"
  39. #include "llfloatersidepanelcontainer.h"
  40. #include "llfloaterworldmap.h"
  41. #include "llfolderview.h"
  42. #include "llfriendcard.h"
  43. #include "llgesturemgr.h"
  44. #include "llgiveinventory.h"
  45. #include "llimfloater.h"
  46. #include "llimview.h"
  47. #include "llinventoryclipboard.h"
  48. #include "llinventorydefines.h"
  49. #include "llinventoryfunctions.h"
  50. #include "llinventorymodel.h"
  51. #include "llinventorymodelbackgroundfetch.h"
  52. #include "llinventorypanel.h"
  53. #include "llmarketplacefunctions.h"
  54. #include "llnotifications.h"
  55. #include "llnotificationsutil.h"
  56. #include "llpreviewanim.h"
  57. #include "llpreviewgesture.h"
  58. #include "llpreviewtexture.h"
  59. #include "llselectmgr.h"
  60. #include "llsidepanelappearance.h"
  61. #include "lltooldraganddrop.h"
  62. #include "lltrans.h"
  63. #include "llviewerassettype.h"
  64. #include "llviewerfoldertype.h"
  65. #include "llviewermenu.h"
  66. #include "llviewermessage.h"
  67. #include "llviewerobjectlist.h"
  68. #include "llviewerwindow.h"
  69. #include "llvoavatarself.h"
  70. #include "llwearablelist.h"
  71. // Marketplace outbox current disabled
  72. #define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU 1
  73. #define ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU 0
  74. #define BLOCK_WORN_ITEMS_IN_OUTBOX 1
  75. typedef std::pair<LLUUID, LLUUID> two_uuids_t;
  76. typedef std::list<two_uuids_t> two_uuids_list_t;
  77. struct LLMoveInv
  78. {
  79. LLUUID mObjectID;
  80. LLUUID mCategoryID;
  81. two_uuids_list_t mMoveList;
  82. void (*mCallback)(S32, void*);
  83. void* mUserData;
  84. };
  85. using namespace LLOldEvents;
  86. // Helpers
  87. // bug in busy count inc/dec right now, logic is complex... do we really need it?
  88. void inc_busy_count()
  89. {
  90. // gViewerWindow->getWindow()->incBusyCount();
  91. // check balance of these calls if this code is changed to ever actually
  92. // *do* something!
  93. }
  94. void dec_busy_count()
  95. {
  96. // gViewerWindow->getWindow()->decBusyCount();
  97. // check balance of these calls if this code is changed to ever actually
  98. // *do* something!
  99. }
  100. // Function declarations
  101. void remove_inventory_category_from_avatar(LLInventoryCategory* category);
  102. void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id);
  103. bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
  104. bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
  105. void teleport_via_landmark(const LLUUID& asset_id);
  106. static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
  107. // Helper functions
  108. bool isAddAction(const std::string& action)
  109. {
  110. return ("wear" == action || "attach" == action || "activate" == action);
  111. }
  112. bool isRemoveAction(const std::string& action)
  113. {
  114. return ("take_off" == action || "detach" == action || "deactivate" == action);
  115. }
  116. bool isMarketplaceCopyAction(const std::string& action)
  117. {
  118. return (("copy_to_outbox" == action) || ("move_to_outbox" == action));
  119. }
  120. bool isMarketplaceSendAction(const std::string& action)
  121. {
  122. return ("send_to_marketplace" == action);
  123. }
  124. // +=================================================+
  125. // | LLInvFVBridge |
  126. // +=================================================+
  127. LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory,
  128. LLFolderView* root,
  129. const LLUUID& uuid) :
  130. mUUID(uuid),
  131. mRoot(root),
  132. mInvType(LLInventoryType::IT_NONE),
  133. mIsLink(FALSE)
  134. {
  135. mInventoryPanel = inventory->getHandle();
  136. const LLInventoryObject* obj = getInventoryObject();
  137. mIsLink = obj && obj->getIsLinkType();
  138. }
  139. const std::string& LLInvFVBridge::getName() const
  140. {
  141. const LLInventoryObject* obj = getInventoryObject();
  142. if(obj)
  143. {
  144. return obj->getName();
  145. }
  146. return LLStringUtil::null;
  147. }
  148. const std::string& LLInvFVBridge::getDisplayName() const
  149. {
  150. return getName();
  151. }
  152. // Folders have full perms
  153. PermissionMask LLInvFVBridge::getPermissionMask() const
  154. {
  155. return PERM_ALL;
  156. }
  157. // virtual
  158. LLFolderType::EType LLInvFVBridge::getPreferredType() const
  159. {
  160. return LLFolderType::FT_NONE;
  161. }
  162. // Folders don't have creation dates.
  163. time_t LLInvFVBridge::getCreationDate() const
  164. {
  165. return 0;
  166. }
  167. // Can be destroyed (or moved to trash)
  168. BOOL LLInvFVBridge::isItemRemovable() const
  169. {
  170. return get_is_item_removable(getInventoryModel(), mUUID);
  171. }
  172. // Can be moved to another folder
  173. BOOL LLInvFVBridge::isItemMovable() const
  174. {
  175. return TRUE;
  176. }
  177. BOOL LLInvFVBridge::isLink() const
  178. {
  179. return mIsLink;
  180. }
  181. /*virtual*/
  182. /**
  183. * @brief Adds this item into clipboard storage
  184. */
  185. void LLInvFVBridge::cutToClipboard()
  186. {
  187. if(isItemMovable())
  188. {
  189. LLInventoryClipboard::instance().cut(mUUID);
  190. }
  191. }
  192. // *TODO: make sure this does the right thing
  193. void LLInvFVBridge::showProperties()
  194. {
  195. show_item_profile(mUUID);
  196. // Disable old properties floater; this is replaced by the sidepanel.
  197. /*
  198. LLFloaterReg::showInstance("properties", mUUID);
  199. */
  200. }
  201. void LLInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch)
  202. {
  203. // Deactivate gestures when moving them into Trash
  204. LLInvFVBridge* bridge;
  205. LLInventoryModel* model = getInventoryModel();
  206. LLViewerInventoryItem* item = NULL;
  207. LLViewerInventoryCategory* cat = NULL;
  208. LLInventoryModel::cat_array_t descendent_categories;
  209. LLInventoryModel::item_array_t descendent_items;
  210. S32 count = batch.count();
  211. S32 i,j;
  212. for(i = 0; i < count; ++i)
  213. {
  214. bridge = (LLInvFVBridge*)(batch.get(i));
  215. if(!bridge || !bridge->isItemRemovable()) continue;
  216. item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
  217. if (item)
  218. {
  219. if(LLAssetType::AT_GESTURE == item->getType())
  220. {
  221. LLGestureMgr::instance().deactivateGesture(item->getUUID());
  222. }
  223. }
  224. }
  225. for(i = 0; i < count; ++i)
  226. {
  227. bridge = (LLInvFVBridge*)(batch.get(i));
  228. if(!bridge || !bridge->isItemRemovable()) continue;
  229. cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
  230. if (cat)
  231. {
  232. gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, FALSE );
  233. for (j=0; j<descendent_items.count(); j++)
  234. {
  235. if(LLAssetType::AT_GESTURE == descendent_items[j]->getType())
  236. {
  237. LLGestureMgr::instance().deactivateGesture(descendent_items[j]->getUUID());
  238. }
  239. }
  240. }
  241. }
  242. removeBatchNoCheck(batch);
  243. }
  244. void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*>& batch)
  245. {
  246. // this method moves a bunch of items and folders to the trash. As
  247. // per design guidelines for the inventory model, the message is
  248. // built and the accounting is performed first. After all of that,
  249. // we call LLInventoryModel::moveObject() to move everything
  250. // around.
  251. LLInvFVBridge* bridge;
  252. LLInventoryModel* model = getInventoryModel();
  253. if(!model) return;
  254. LLMessageSystem* msg = gMessageSystem;
  255. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  256. LLViewerInventoryItem* item = NULL;
  257. uuid_vec_t move_ids;
  258. LLInventoryModel::update_map_t update;
  259. bool start_new_message = true;
  260. S32 count = batch.count();
  261. S32 i;
  262. // first, hide any 'preview' floaters that correspond to the items
  263. // being deleted.
  264. for(i = 0; i < count; ++i)
  265. {
  266. bridge = (LLInvFVBridge*)(batch.get(i));
  267. if(!bridge || !bridge->isItemRemovable()) continue;
  268. item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
  269. if(item)
  270. {
  271. LLPreview::hide(item->getUUID());
  272. }
  273. }
  274. // do the inventory move to trash
  275. for(i = 0; i < count; ++i)
  276. {
  277. bridge = (LLInvFVBridge*)(batch.get(i));
  278. if(!bridge || !bridge->isItemRemovable()) continue;
  279. item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
  280. if(item)
  281. {
  282. if(item->getParentUUID() == trash_id) continue;
  283. move_ids.push_back(item->getUUID());
  284. --update[item->getParentUUID()];
  285. ++update[trash_id];
  286. if(start_new_message)
  287. {
  288. start_new_message = false;
  289. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  290. msg->nextBlockFast(_PREHASH_AgentData);
  291. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  292. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  293. msg->addBOOLFast(_PREHASH_Stamp, TRUE);
  294. }
  295. msg->nextBlockFast(_PREHASH_InventoryData);
  296. msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
  297. msg->addUUIDFast(_PREHASH_FolderID, trash_id);
  298. msg->addString("NewName", NULL);
  299. if(msg->isSendFullFast(_PREHASH_InventoryData))
  300. {
  301. start_new_message = true;
  302. gAgent.sendReliableMessage();
  303. gInventory.accountForUpdate(update);
  304. update.clear();
  305. }
  306. }
  307. }
  308. if(!start_new_message)
  309. {
  310. start_new_message = true;
  311. gAgent.sendReliableMessage();
  312. gInventory.accountForUpdate(update);
  313. update.clear();
  314. }
  315. for(i = 0; i < count; ++i)
  316. {
  317. bridge = (LLInvFVBridge*)(batch.get(i));
  318. if(!bridge || !bridge->isItemRemovable()) continue;
  319. LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
  320. if(cat)
  321. {
  322. if(cat->getParentUUID() == trash_id) continue;
  323. move_ids.push_back(cat->getUUID());
  324. --update[cat->getParentUUID()];
  325. ++update[trash_id];
  326. if(start_new_message)
  327. {
  328. start_new_message = false;
  329. msg->newMessageFast(_PREHASH_MoveInventoryFolder);
  330. msg->nextBlockFast(_PREHASH_AgentData);
  331. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  332. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  333. msg->addBOOL("Stamp", TRUE);
  334. }
  335. msg->nextBlockFast(_PREHASH_InventoryData);
  336. msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID());
  337. msg->addUUIDFast(_PREHASH_ParentID, trash_id);
  338. if(msg->isSendFullFast(_PREHASH_InventoryData))
  339. {
  340. start_new_message = true;
  341. gAgent.sendReliableMessage();
  342. gInventory.accountForUpdate(update);
  343. update.clear();
  344. }
  345. }
  346. }
  347. if(!start_new_message)
  348. {
  349. gAgent.sendReliableMessage();
  350. gInventory.accountForUpdate(update);
  351. }
  352. // move everything.
  353. uuid_vec_t::iterator it = move_ids.begin();
  354. uuid_vec_t::iterator end = move_ids.end();
  355. for(; it != end; ++it)
  356. {
  357. gInventory.moveObject((*it), trash_id);
  358. }
  359. // notify inventory observers.
  360. model->notifyObservers();
  361. }
  362. BOOL LLInvFVBridge::isClipboardPasteable() const
  363. {
  364. if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
  365. {
  366. return FALSE;
  367. }
  368. LLInventoryModel* model = getInventoryModel();
  369. if (!model)
  370. {
  371. return FALSE;
  372. }
  373. const LLUUID &agent_id = gAgent.getID();
  374. LLDynamicArray<LLUUID> objects;
  375. LLInventoryClipboard::instance().retrieve(objects);
  376. S32 count = objects.count();
  377. for(S32 i = 0; i < count; i++)
  378. {
  379. const LLUUID &item_id = objects.get(i);
  380. // Can't paste folders
  381. const LLInventoryCategory *cat = model->getCategory(item_id);
  382. if (cat)
  383. {
  384. return FALSE;
  385. }
  386. const LLInventoryItem *item = model->getItem(item_id);
  387. if (item)
  388. {
  389. if (!item->getPermissions().allowCopyBy(agent_id))
  390. {
  391. return FALSE;
  392. }
  393. }
  394. }
  395. return TRUE;
  396. }
  397. BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
  398. {
  399. if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
  400. {
  401. return FALSE;
  402. }
  403. const LLInventoryModel* model = getInventoryModel();
  404. if (!model)
  405. {
  406. return FALSE;
  407. }
  408. LLDynamicArray<LLUUID> objects;
  409. LLInventoryClipboard::instance().retrieve(objects);
  410. S32 count = objects.count();
  411. for(S32 i = 0; i < count; i++)
  412. {
  413. const LLInventoryItem *item = model->getItem(objects.get(i));
  414. if (item)
  415. {
  416. if (!LLAssetType::lookupCanLink(item->getActualType()))
  417. {
  418. return FALSE;
  419. }
  420. }
  421. const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i));
  422. if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
  423. {
  424. return FALSE;
  425. }
  426. }
  427. return TRUE;
  428. }
  429. void hide_context_entries(LLMenuGL& menu,
  430. const menuentry_vec_t &entries_to_show,
  431. const menuentry_vec_t &disabled_entries)
  432. {
  433. const LLView::child_list_t *list = menu.getChildList();
  434. // For removing double separators or leading separator. Start at true so that
  435. // if the first element is a separator, it will not be shown.
  436. bool is_previous_entry_separator = true;
  437. for (LLView::child_list_t::const_iterator itor = list->begin();
  438. itor != list->end();
  439. ++itor)
  440. {
  441. LLView *menu_item = (*itor);
  442. std::string name = menu_item->getName();
  443. // descend into split menus:
  444. LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item);
  445. if ((name == "More") && branchp)
  446. {
  447. hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries);
  448. }
  449. bool found = false;
  450. menuentry_vec_t::const_iterator itor2;
  451. for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2)
  452. {
  453. if (*itor2 == name)
  454. {
  455. found = true;
  456. break;
  457. }
  458. }
  459. // Don't allow multiple separators in a row (e.g. such as if there are no items
  460. // between two separators).
  461. if (found)
  462. {
  463. const bool is_entry_separator = (dynamic_cast<LLMenuItemSeparatorGL *>(menu_item) != NULL);
  464. found = !(is_entry_separator && is_previous_entry_separator);
  465. is_previous_entry_separator = is_entry_separator;
  466. }
  467. if (!found)
  468. {
  469. if (!menu_item->getLastVisible())
  470. {
  471. menu_item->setVisible(FALSE);
  472. }
  473. menu_item->setEnabled(FALSE);
  474. }
  475. else
  476. {
  477. menu_item->setVisible(TRUE);
  478. // A bit of a hack so we can remember that some UI element explicitly set this to be visible
  479. // so that some other UI element from multi-select doesn't later set this invisible.
  480. menu_item->pushVisible(TRUE);
  481. bool enabled = (menu_item->getEnabled() == TRUE);
  482. for (itor2 = disabled_entries.begin(); enabled && (itor2 != disabled_entries.end()); ++itor2)
  483. {
  484. enabled &= (*itor2 != name);
  485. }
  486. menu_item->setEnabled(enabled);
  487. }
  488. }
  489. }
  490. // Helper for commonly-used entries
  491. void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
  492. menuentry_vec_t &items,
  493. menuentry_vec_t &disabled_items, U32 flags)
  494. {
  495. const LLInventoryObject *obj = getInventoryObject();
  496. if (obj)
  497. {
  498. if (obj->getIsLinkType())
  499. {
  500. items.push_back(std::string("Find Original"));
  501. if (isLinkedObjectMissing())
  502. {
  503. disabled_items.push_back(std::string("Find Original"));
  504. }
  505. }
  506. else
  507. {
  508. if (LLAssetType::lookupCanLink(obj->getType()))
  509. {
  510. items.push_back(std::string("Find Links"));
  511. }
  512. if (!isInboxFolder())
  513. {
  514. items.push_back(std::string("Rename"));
  515. if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0)
  516. {
  517. disabled_items.push_back(std::string("Rename"));
  518. }
  519. }
  520. if (show_asset_id)
  521. {
  522. items.push_back(std::string("Copy Asset UUID"));
  523. bool is_asset_knowable = false;
  524. LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID);
  525. if (inv_item)
  526. {
  527. is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(inv_item->getType());
  528. }
  529. if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308
  530. || (! ( isItemPermissive() || gAgent.isGodlike() ) )
  531. || (flags & FIRST_SELECTED_ITEM) == 0)
  532. {
  533. disabled_items.push_back(std::string("Copy Asset UUID"));
  534. }
  535. }
  536. items.push_back(std::string("Copy Separator"));
  537. items.push_back(std::string("Copy"));
  538. if (!isItemCopyable())
  539. {
  540. disabled_items.push_back(std::string("Copy"));
  541. }
  542. if (canListOnMarketplace())
  543. {
  544. items.push_back(std::string("Marketplace Separator"));
  545. items.push_back(std::string("Merchant Copy"));
  546. if (!canListOnMarketplaceNow())
  547. {
  548. disabled_items.push_back(std::string("Merchant Copy"));
  549. }
  550. }
  551. }
  552. }
  553. // Don't allow items to be pasted directly into the COF or the inbox/outbox
  554. if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder())
  555. {
  556. items.push_back(std::string("Paste"));
  557. }
  558. if (!isClipboardPasteable() || ((flags & FIRST_SELECTED_ITEM) == 0))
  559. {
  560. disabled_items.push_back(std::string("Paste"));
  561. }
  562. if (gSavedSettings.getBOOL("InventoryLinking"))
  563. {
  564. items.push_back(std::string("Paste As Link"));
  565. if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0)
  566. {
  567. disabled_items.push_back(std::string("Paste As Link"));
  568. }
  569. }
  570. items.push_back(std::string("Paste Separator"));
  571. addDeleteContextMenuOptions(items, disabled_items);
  572. // If multiple items are selected, disable properties (if it exists).
  573. if ((flags & FIRST_SELECTED_ITEM) == 0)
  574. {
  575. disabled_items.push_back(std::string("Properties"));
  576. }
  577. }
  578. void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
  579. {
  580. lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl;
  581. menuentry_vec_t items;
  582. menuentry_vec_t disabled_items;
  583. if(isItemInTrash())
  584. {
  585. addTrashContextMenuOptions(items, disabled_items);
  586. }
  587. else if(isOutboxFolder())
  588. {
  589. addOutboxContextMenuOptions(flags, items, disabled_items);
  590. }
  591. else
  592. {
  593. items.push_back(std::string("Share"));
  594. if (!canShare())
  595. {
  596. disabled_items.push_back(std::string("Share"));
  597. }
  598. addOpenRightClickMenuOption(items);
  599. items.push_back(std::string("Properties"));
  600. getClipboardEntries(true, items, disabled_items, flags);
  601. }
  602. hide_context_entries(menu, items, disabled_items);
  603. }
  604. void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items,
  605. menuentry_vec_t &disabled_items)
  606. {
  607. const LLInventoryObject *obj = getInventoryObject();
  608. if (obj && obj->getIsLinkType())
  609. {
  610. items.push_back(std::string("Find Original"));
  611. if (isLinkedObjectMissing())
  612. {
  613. disabled_items.push_back(std::string("Find Original"));
  614. }
  615. }
  616. items.push_back(std::string("Purge Item"));
  617. if (!isItemRemovable())
  618. {
  619. disabled_items.push_back(std::string("Purge Item"));
  620. }
  621. items.push_back(std::string("Restore Item"));
  622. }
  623. void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
  624. menuentry_vec_t &disabled_items)
  625. {
  626. const LLInventoryObject *obj = getInventoryObject();
  627. // Don't allow delete as a direct option from COF folder.
  628. if (obj && obj->getIsLinkType() && isCOFFolder() && get_is_item_worn(mUUID))
  629. {
  630. return;
  631. }
  632. // "Remove link" and "Delete" are the same operation.
  633. if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID))
  634. {
  635. items.push_back(std::string("Remove Link"));
  636. }
  637. else
  638. {
  639. items.push_back(std::string("Delete"));
  640. }
  641. if (!isItemRemovable())
  642. {
  643. disabled_items.push_back(std::string("Delete"));
  644. }
  645. }
  646. void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items)
  647. {
  648. const LLInventoryObject *obj = getInventoryObject();
  649. const BOOL is_link = (obj && obj->getIsLinkType());
  650. if (is_link)
  651. items.push_back(std::string("Open Original"));
  652. else
  653. items.push_back(std::string("Open"));
  654. }
  655. void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags,
  656. menuentry_vec_t &items,
  657. menuentry_vec_t &disabled_items)
  658. {
  659. items.push_back(std::string("Rename"));
  660. items.push_back(std::string("Delete"));
  661. if ((flags & FIRST_SELECTED_ITEM) == 0)
  662. {
  663. disabled_items.push_back(std::string("Rename"));
  664. }
  665. #if ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU
  666. if (isOutboxFolderDirectParent())
  667. {
  668. items.push_back(std::string("Marketplace Separator"));
  669. items.push_back(std::string("Marketplace Send"));
  670. if ((flags & FIRST_SELECTED_ITEM) == 0)
  671. {
  672. disabled_items.push_back(std::string("Marketplace Send"));
  673. }
  674. }
  675. #endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU
  676. }
  677. // *TODO: remove this
  678. BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
  679. {
  680. BOOL rv = FALSE;
  681. const LLInventoryObject* obj = getInventoryObject();
  682. if(obj)
  683. {
  684. *type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
  685. if(*type == DAD_NONE)
  686. {
  687. return FALSE;
  688. }
  689. *id = obj->getUUID();
  690. //object_ids.put(obj->getUUID());
  691. if (*type == DAD_CATEGORY)
  692. {
  693. LLInventoryModelBackgroundFetch::instance().start(obj->getUUID());
  694. }
  695. rv = TRUE;
  696. }
  697. return rv;
  698. }
  699. LLInventoryObject* LLInvFVBridge::getInventoryObject() const
  700. {
  701. LLInventoryObject* obj = NULL;
  702. LLInventoryModel* model = getInventoryModel();
  703. if(model)
  704. {
  705. obj = (LLInventoryObject*)model->getObject(mUUID);
  706. }
  707. return obj;
  708. }
  709. LLInventoryModel* LLInvFVBridge::getInventoryModel() const
  710. {
  711. LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
  712. return panel ? panel->getModel() : NULL;
  713. }
  714. BOOL LLInvFVBridge::isItemInTrash() const
  715. {
  716. LLInventoryModel* model = getInventoryModel();
  717. if(!model) return FALSE;
  718. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  719. return model->isObjectDescendentOf(mUUID, trash_id);
  720. }
  721. BOOL LLInvFVBridge::isLinkedObjectInTrash() const
  722. {
  723. if (isItemInTrash()) return TRUE;
  724. const LLInventoryObject *obj = getInventoryObject();
  725. if (obj && obj->getIsLinkType())
  726. {
  727. LLInventoryModel* model = getInventoryModel();
  728. if(!model) return FALSE;
  729. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  730. return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id);
  731. }
  732. return FALSE;
  733. }
  734. BOOL LLInvFVBridge::isLinkedObjectMissing() const
  735. {
  736. const LLInventoryObject *obj = getInventoryObject();
  737. if (!obj)
  738. {
  739. return TRUE;
  740. }
  741. if (obj->getIsLinkType() && LLAssetType::lookupIsLinkType(obj->getType()))
  742. {
  743. return TRUE;
  744. }
  745. return FALSE;
  746. }
  747. BOOL LLInvFVBridge::isAgentInventory() const
  748. {
  749. const LLInventoryModel* model = getInventoryModel();
  750. if(!model) return FALSE;
  751. if(gInventory.getRootFolderID() == mUUID) return TRUE;
  752. return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
  753. }
  754. BOOL LLInvFVBridge::isCOFFolder() const
  755. {
  756. return LLAppearanceMgr::instance().getIsInCOF(mUUID);
  757. }
  758. BOOL LLInvFVBridge::isInboxFolder() const
  759. {
  760. const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false);
  761. if (inbox_id.isNull())
  762. {
  763. return FALSE;
  764. }
  765. return gInventory.isObjectDescendentOf(mUUID, inbox_id);
  766. }
  767. BOOL LLInvFVBridge::isOutboxFolder() const
  768. {
  769. const LLUUID outbox_id = getOutboxFolder();
  770. if (outbox_id.isNull())
  771. {
  772. return FALSE;
  773. }
  774. return gInventory.isObjectDescendentOf(mUUID, outbox_id);
  775. }
  776. BOOL LLInvFVBridge::isOutboxFolderDirectParent() const
  777. {
  778. BOOL outbox_is_parent = FALSE;
  779. const LLInventoryCategory *cat = gInventory.getCategory(mUUID);
  780. if (cat)
  781. {
  782. const LLUUID outbox_id = getOutboxFolder();
  783. outbox_is_parent = (outbox_id.notNull() && (outbox_id == cat->getParentUUID()));
  784. }
  785. return outbox_is_parent;
  786. }
  787. const LLUUID LLInvFVBridge::getOutboxFolder() const
  788. {
  789. const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false);
  790. return outbox_id;
  791. }
  792. BOOL LLInvFVBridge::isItemPermissive() const
  793. {
  794. return FALSE;
  795. }
  796. // static
  797. void LLInvFVBridge::changeItemParent(LLInventoryModel* model,
  798. LLViewerInventoryItem* item,
  799. const LLUUID& new_parent_id,
  800. BOOL restamp)
  801. {
  802. change_item_parent(model, item, new_parent_id, restamp);
  803. }
  804. // static
  805. void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
  806. LLViewerInventoryCategory* cat,
  807. const LLUUID& new_parent_id,
  808. BOOL restamp)
  809. {
  810. change_category_parent(model, cat, new_parent_id, restamp);
  811. }
  812. LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
  813. LLAssetType::EType actual_asset_type,
  814. LLInventoryType::EType inv_type,
  815. LLInventoryPanel* inventory,
  816. LLFolderView* root,
  817. const LLUUID& uuid,
  818. U32 flags)
  819. {
  820. LLInvFVBridge* new_listener = NULL;
  821. switch(asset_type)
  822. {
  823. case LLAssetType::AT_TEXTURE:
  824. if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
  825. {
  826. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  827. }
  828. new_listener = new LLTextureBridge(inventory, root, uuid, inv_type);
  829. break;
  830. case LLAssetType::AT_SOUND:
  831. if(!(inv_type == LLInventoryType::IT_SOUND))
  832. {
  833. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  834. }
  835. new_listener = new LLSoundBridge(inventory, root, uuid);
  836. break;
  837. case LLAssetType::AT_LANDMARK:
  838. if(!(inv_type == LLInventoryType::IT_LANDMARK))
  839. {
  840. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  841. }
  842. new_listener = new LLLandmarkBridge(inventory, root, uuid, flags);
  843. break;
  844. case LLAssetType::AT_CALLINGCARD:
  845. if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
  846. {
  847. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  848. }
  849. new_listener = new LLCallingCardBridge(inventory, root, uuid);
  850. break;
  851. case LLAssetType::AT_SCRIPT:
  852. if(!(inv_type == LLInventoryType::IT_LSL))
  853. {
  854. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  855. }
  856. new_listener = new LLItemBridge(inventory, root, uuid);
  857. break;
  858. case LLAssetType::AT_OBJECT:
  859. if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
  860. {
  861. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  862. }
  863. new_listener = new LLObjectBridge(inventory, root, uuid, inv_type, flags);
  864. break;
  865. case LLAssetType::AT_NOTECARD:
  866. if(!(inv_type == LLInventoryType::IT_NOTECARD))
  867. {
  868. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  869. }
  870. new_listener = new LLNotecardBridge(inventory, root, uuid);
  871. break;
  872. case LLAssetType::AT_ANIMATION:
  873. if(!(inv_type == LLInventoryType::IT_ANIMATION))
  874. {
  875. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  876. }
  877. new_listener = new LLAnimationBridge(inventory, root, uuid);
  878. break;
  879. case LLAssetType::AT_GESTURE:
  880. if(!(inv_type == LLInventoryType::IT_GESTURE))
  881. {
  882. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  883. }
  884. new_listener = new LLGestureBridge(inventory, root, uuid);
  885. break;
  886. case LLAssetType::AT_LSL_TEXT:
  887. if(!(inv_type == LLInventoryType::IT_LSL))
  888. {
  889. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  890. }
  891. new_listener = new LLLSLTextBridge(inventory, root, uuid);
  892. break;
  893. case LLAssetType::AT_CLOTHING:
  894. case LLAssetType::AT_BODYPART:
  895. if(!(inv_type == LLInventoryType::IT_WEARABLE))
  896. {
  897. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  898. }
  899. new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags);
  900. break;
  901. case LLAssetType::AT_CATEGORY:
  902. if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
  903. {
  904. // Create a link folder handler instead.
  905. new_listener = new LLLinkFolderBridge(inventory, root, uuid);
  906. break;
  907. }
  908. new_listener = new LLFolderBridge(inventory, root, uuid);
  909. break;
  910. case LLAssetType::AT_LINK:
  911. case LLAssetType::AT_LINK_FOLDER:
  912. // Only should happen for broken links.
  913. new_listener = new LLLinkItemBridge(inventory, root, uuid);
  914. break;
  915. case LLAssetType::AT_MESH:
  916. if(!(inv_type == LLInventoryType::IT_MESH))
  917. {
  918. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
  919. }
  920. new_listener = new LLMeshBridge(inventory, root, uuid);
  921. break;
  922. case LLAssetType::AT_IMAGE_TGA:
  923. case LLAssetType::AT_IMAGE_JPEG:
  924. //llwarns << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << llendl;
  925. break;
  926. default:
  927. llinfos << "Unhandled asset type (llassetstorage.h): "
  928. << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << llendl;
  929. break;
  930. }
  931. if (new_listener)
  932. {
  933. new_listener->mInvType = inv_type;
  934. }
  935. return new_listener;
  936. }
  937. void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
  938. {
  939. LLInventoryCategory* cat = model->getCategory(uuid);
  940. if (cat)
  941. {
  942. model->purgeDescendentsOf(uuid);
  943. model->notifyObservers();
  944. }
  945. LLInventoryObject* obj = model->getObject(uuid);
  946. if (obj)
  947. {
  948. model->purgeObject(uuid);
  949. model->notifyObservers();
  950. }
  951. }
  952. bool LLInvFVBridge::canShare() const
  953. {
  954. bool can_share = false;
  955. if (isAgentInventory())
  956. {
  957. const LLInventoryModel* model = getInventoryModel();
  958. if (model)
  959. {
  960. const LLViewerInventoryItem *item = model->getItem(mUUID);
  961. if (item)
  962. {
  963. if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item))
  964. {
  965. can_share = LLGiveInventory::isInventoryGiveAcceptable(item);
  966. }
  967. }
  968. else
  969. {
  970. // Categories can be given.
  971. can_share = (model->getCategory(mUUID) != NULL);
  972. }
  973. }
  974. }
  975. return can_share;
  976. }
  977. bool LLInvFVBridge::canListOnMarketplace() const
  978. {
  979. #if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU
  980. LLInventoryModel * model = getInventoryModel();
  981. const LLViewerInventoryCategory * cat = model->getCategory(mUUID);
  982. if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
  983. {
  984. return false;
  985. }
  986. if (!isAgentInventory())
  987. {
  988. return false;
  989. }
  990. if (getOutboxFolder().isNull())
  991. {
  992. return false;
  993. }
  994. if (isInboxFolder() || isOutboxFolder())
  995. {
  996. return false;
  997. }
  998. LLViewerInventoryItem * item = model->getItem(mUUID);
  999. if (item)
  1000. {
  1001. if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
  1002. {
  1003. return false;
  1004. }
  1005. if (LLAssetType::AT_CALLINGCARD == item->getType())
  1006. {
  1007. return false;
  1008. }
  1009. }
  1010. return true;
  1011. #else
  1012. return false;
  1013. #endif
  1014. }
  1015. bool LLInvFVBridge::canListOnMarketplaceNow() const
  1016. {
  1017. #if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU
  1018. bool can_list = true;
  1019. // Do not allow listing while import is in progress
  1020. if (LLMarketplaceInventoryImporter::instanceExists())
  1021. {
  1022. can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress();
  1023. }
  1024. const LLInventoryObject* obj = getInventoryObject();
  1025. can_list &= (obj != NULL);
  1026. if (can_list)
  1027. {
  1028. const LLUUID& object_id = obj->getLinkedUUID();
  1029. can_list = object_id.notNull();
  1030. if (can_list)
  1031. {
  1032. LLFolderViewFolder * object_folderp = mRoot->getFolderByID(object_id);
  1033. if (object_folderp)
  1034. {
  1035. can_list = !object_folderp->isLoading();
  1036. }
  1037. }
  1038. if (can_list)
  1039. {
  1040. // Get outbox id
  1041. const LLUUID & outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
  1042. LLFolderViewItem * outbox_itemp = mRoot->getItemByID(outbox_id);
  1043. if (outbox_itemp)
  1044. {
  1045. MASK mask = 0x0;
  1046. BOOL drop = FALSE;
  1047. EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
  1048. void * cargo_data = (void *) obj;
  1049. std::string tooltip_msg;
  1050. can_list = outbox_itemp->getListener()->dragOrDrop(mask, drop, cargo_type, cargo_data, tooltip_msg);
  1051. }
  1052. }
  1053. }
  1054. return can_list;
  1055. #else
  1056. return false;
  1057. #endif
  1058. }
  1059. // +=================================================+
  1060. // | InventoryFVBridgeBuilder |
  1061. // +=================================================+
  1062. LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type,
  1063. LLAssetType::EType actual_asset_type,
  1064. LLInventoryType::EType inv_type,
  1065. LLInventoryPanel* inventory,
  1066. LLFolderView* root,
  1067. const LLUUID& uuid,
  1068. U32 flags /* = 0x00 */) const
  1069. {
  1070. return LLInvFVBridge::createBridge(asset_type,
  1071. actual_asset_type,
  1072. inv_type,
  1073. inventory,
  1074. root,
  1075. uuid,
  1076. flags);
  1077. }
  1078. // +=================================================+
  1079. // | LLItemBridge |
  1080. // +=================================================+
  1081. void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
  1082. {
  1083. if ("goto" == action)
  1084. {
  1085. gotoItem();
  1086. }
  1087. if ("open" == action || "open_original" == action)
  1088. {
  1089. openItem();
  1090. return;
  1091. }
  1092. else if ("properties" == action)
  1093. {
  1094. showProperties();
  1095. return;
  1096. }
  1097. else if ("purge" == action)
  1098. {
  1099. purgeItem(model, mUUID);
  1100. return;
  1101. }
  1102. else if ("restoreToWorld" == action)
  1103. {
  1104. restoreToWorld();
  1105. return;
  1106. }
  1107. else if ("restore" == action)
  1108. {
  1109. restoreItem();
  1110. return;
  1111. }
  1112. else if ("copy_uuid" == action)
  1113. {
  1114. // Single item only
  1115. LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
  1116. if(!item) return;
  1117. LLUUID asset_id = item->getProtectedAssetUUID();
  1118. std::string buffer;
  1119. asset_id.toString(buffer);
  1120. gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));
  1121. return;
  1122. }
  1123. else if ("copy" == action)
  1124. {
  1125. copyToClipboard();
  1126. return;
  1127. }
  1128. else if ("paste" == action)
  1129. {
  1130. // Single item only
  1131. LLInventoryItem* itemp = model->getItem(mUUID);
  1132. if (!itemp) return;
  1133. LLFolderViewItem* folder_view_itemp = mRoot->getItemByID(itemp->getParentUUID());
  1134. if (!folder_view_itemp) return;
  1135. folder_view_itemp->getListener()->pasteFromClipboard();
  1136. return;
  1137. }
  1138. else if ("paste_link" == action)
  1139. {
  1140. // Single item only
  1141. LLInventoryItem* itemp = model->getItem(mUUID);
  1142. if (!itemp) return;
  1143. LLFolderViewItem* folder_view_itemp = mRoot->getItemByID(itemp->getParentUUID());
  1144. if (!folder_view_itemp) return;
  1145. folder_view_itemp->getListener()->pasteLinkFromClipboard();
  1146. return;
  1147. }
  1148. else if (isMarketplaceCopyAction(action))
  1149. {
  1150. llinfos << "Copy item to marketplace action!" << llendl;
  1151. LLInventoryItem* itemp = model->getItem(mUUID);
  1152. if (!itemp) return;
  1153. const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false);
  1154. copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId());
  1155. }
  1156. }
  1157. void LLItemBridge::selectItem()
  1158. {
  1159. LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
  1160. if(item && !item->isFinished())
  1161. {
  1162. item->fetchFromServer();
  1163. //LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false);
  1164. }
  1165. }
  1166. void LLItemBridge::restoreItem()
  1167. {
  1168. LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
  1169. if(item)
  1170. {
  1171. LLInventoryModel* model = getInventoryModel();
  1172. const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType()));
  1173. // do not restamp on restore.
  1174. LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
  1175. }
  1176. }
  1177. void LLItemBridge::restoreToWorld()
  1178. {
  1179. //Similar functionality to the drag and drop rez logic
  1180. bool remove_from_inventory = false;
  1181. LLViewerInventoryItem* itemp = static_cast<LLViewerInventoryItem*>(getItem());
  1182. if (itemp)
  1183. {
  1184. LLMessageSystem* msg = gMessageSystem;
  1185. msg->newMessage("RezRestoreToWorld");
  1186. msg->nextBlockFast(_PREHASH_AgentData);
  1187. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1188. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1189. msg->nextBlockFast(_PREHASH_InventoryData);
  1190. itemp->packMessage(msg);
  1191. msg->sendReliable(gAgent.getRegion()->getHost());
  1192. //remove local inventory copy, sim will deal with permissions and removing the item
  1193. //from the actual inventory if its a no-copy etc
  1194. if(!itemp->getPermissions().allowCopyBy(gAgent.getID()))
  1195. {
  1196. remove_from_inventory = true;
  1197. }
  1198. // Check if it's in the trash. (again similar to the normal rez logic)
  1199. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1200. if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id))
  1201. {
  1202. remove_from_inventory = true;
  1203. }
  1204. }
  1205. if(remove_from_inventory)
  1206. {
  1207. gInventory.deleteObject(itemp->getUUID());
  1208. gInventory.notifyObservers();
  1209. }
  1210. }
  1211. void LLItemBridge::gotoItem()
  1212. {
  1213. LLInventoryObject *obj = getInventoryObject();
  1214. if (obj && obj->getIsLinkType())
  1215. {
  1216. LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
  1217. if (active_panel)
  1218. {
  1219. active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO);
  1220. }
  1221. }
  1222. }
  1223. LLUIImagePtr LLItemBridge::getIcon() const
  1224. {
  1225. LLInventoryObject *obj = getInventoryObject();
  1226. if (obj)
  1227. {
  1228. return LLInventoryIcon::getIcon(obj->getType(),
  1229. LLInventoryType::IT_NONE,
  1230. mIsLink);
  1231. }
  1232. return LLInventoryIcon::getIcon(LLInventoryIcon::ICONNAME_OBJECT);
  1233. }
  1234. PermissionMask LLItemBridge::getPermissionMask() const
  1235. {
  1236. LLViewerInventoryItem* item = getItem();
  1237. PermissionMask perm_mask = 0;
  1238. if (item) perm_mask = item->getPermissionMask();
  1239. return perm_mask;
  1240. }
  1241. const std::string& LLItemBridge::getDisplayName() const
  1242. {
  1243. if(mDisplayName.empty())
  1244. {
  1245. buildDisplayName(getItem(), mDisplayName);
  1246. }
  1247. return mDisplayName;
  1248. }
  1249. void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name)
  1250. {
  1251. if(item)
  1252. {
  1253. name.assign(item->getName());
  1254. }
  1255. else
  1256. {
  1257. name.assign(LLStringUtil::null);
  1258. }
  1259. }
  1260. LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
  1261. {
  1262. U8 font = LLFontGL::NORMAL;
  1263. const LLViewerInventoryItem* item = getItem();
  1264. if (get_is_item_worn(mUUID))
  1265. {
  1266. // llinfos << "BOLD" << llendl;
  1267. font |= LLFontGL::BOLD;
  1268. }
  1269. else if(item && item->getIsLinkType())
  1270. {
  1271. font |= LLFontGL::ITALIC;
  1272. }
  1273. return (LLFontGL::StyleFlags)font;
  1274. }
  1275. std::string LLItemBridge::getLabelSuffix() const
  1276. {
  1277. // String table is loaded before login screen and inventory items are
  1278. // loaded after login, so LLTrans should be ready.
  1279. static std::string NO_COPY = LLTrans::getString("no_copy");
  1280. static std::string NO_MOD = LLTrans::getString("no_modify");
  1281. static std::string NO_XFER = LLTrans::getString("no_transfer");
  1282. static std::string LINK = LLTrans::getString("link");
  1283. static std::string BROKEN_LINK = LLTrans::getString("broken_link");
  1284. std::string suffix;
  1285. LLInventoryItem* item = getItem();
  1286. if(item)
  1287. {
  1288. // Any type can have the link suffix...
  1289. BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType());
  1290. if (broken_link) return BROKEN_LINK;
  1291. BOOL link = item->getIsLinkType();
  1292. if (link) return LINK;
  1293. // ...but it's a bit confusing to put nocopy/nomod/etc suffixes on calling cards.
  1294. if(LLAssetType::AT_CALLINGCARD != item->getType()
  1295. && item->getPermissions().getOwner() == gAgent.getID())
  1296. {
  1297. BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
  1298. if (!copy)
  1299. {
  1300. suffix += NO_COPY;
  1301. }
  1302. BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
  1303. if (!mod)
  1304. {
  1305. suffix += NO_MOD;
  1306. }
  1307. BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
  1308. gAgent.getID());
  1309. if (!xfer)
  1310. {
  1311. suffix += NO_XFER;
  1312. }
  1313. }
  1314. }
  1315. return suffix;
  1316. }
  1317. time_t LLItemBridge::getCreationDate() const
  1318. {
  1319. LLViewerInventoryItem* item = getItem();
  1320. if (item)
  1321. {
  1322. return item->getCreationDate();
  1323. }
  1324. return 0;
  1325. }
  1326. BOOL LLItemBridge::isItemRenameable() const
  1327. {
  1328. LLViewerInventoryItem* item = getItem();
  1329. if(item)
  1330. {
  1331. // (For now) Don't allow calling card rename since that may confuse users as to
  1332. // what the calling card points to.
  1333. if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
  1334. {
  1335. return FALSE;
  1336. }
  1337. if (!item->isFinished()) // EXT-8662
  1338. {
  1339. return FALSE;
  1340. }
  1341. if (isInboxFolder())
  1342. {
  1343. return FALSE;
  1344. }
  1345. return (item->getPermissions().allowModifyBy(gAgent.getID()));
  1346. }
  1347. return FALSE;
  1348. }
  1349. BOOL LLItemBridge::renameItem(const std::string& new_name)
  1350. {
  1351. if(!isItemRenameable())
  1352. return FALSE;
  1353. LLPreview::dirty(mUUID);
  1354. LLInventoryModel* model = getInventoryModel();
  1355. if(!model)
  1356. return FALSE;
  1357. LLViewerInventoryItem* item = getItem();
  1358. if(item && (item->getName() != new_name))
  1359. {
  1360. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  1361. new_item->rename(new_name);
  1362. buildDisplayName(new_item, mDisplayName);
  1363. new_item->updateServer(FALSE);
  1364. model->updateItem(new_item);
  1365. model->notifyObservers();
  1366. }
  1367. // return FALSE because we either notified observers (& therefore
  1368. // rebuilt) or we didn't update.
  1369. return FALSE;
  1370. }
  1371. BOOL LLItemBridge::removeItem()
  1372. {
  1373. if(!isItemRemovable())
  1374. {
  1375. return FALSE;
  1376. }
  1377. // move it to the trash
  1378. LLPreview::hide(mUUID, TRUE);
  1379. LLInventoryModel* model = getInventoryModel();
  1380. if(!model) return FALSE;
  1381. const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1382. LLViewerInventoryItem* item = getItem();
  1383. if (!item) return FALSE;
  1384. // Already in trash
  1385. if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE;
  1386. LLNotification::Params params("ConfirmItemDeleteHasLinks");
  1387. params.functor.function(boost::bind(&LLItemBridge::confirmRemoveItem, this, _1, _2));
  1388. // Check if this item has any links. If generic inventory linking is enabled,
  1389. // we can't do this check because we may have items in a folder somewhere that is
  1390. // not yet in memory, so we don't want false negatives. (If disabled, then we
  1391. // know we only have links in the Outfits folder which we explicitly fetch.)
  1392. if (!gSavedSettings.getBOOL("InventoryLinking"))
  1393. {
  1394. if (!item->getIsLinkType())
  1395. {
  1396. LLInventoryModel::cat_array_t cat_array;
  1397. LLInventoryModel::item_array_t item_array;
  1398. LLLinkedItemIDMatches is_linked_item_match(mUUID);
  1399. gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
  1400. cat_array,
  1401. item_array,
  1402. LLInventoryModel::INCLUDE_TRASH,
  1403. is_linked_item_match);
  1404. const U32 num_links = cat_array.size() + item_array.size();
  1405. if (num_links > 0)
  1406. {
  1407. // Warn if the user is will break any links when deleting this item.
  1408. LLNotifications::instance().add(params);
  1409. return FALSE;
  1410. }
  1411. }
  1412. }
  1413. LLNotifications::instance().forceResponse(params, 0);
  1414. return TRUE;
  1415. }
  1416. BOOL LLItemBridge::confirmRemoveItem(const LLSD& notification, const LLSD& response)
  1417. {
  1418. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  1419. if (option != 0) return FALSE;
  1420. LLInventoryModel* model = getInventoryModel();
  1421. if (!model) return FALSE;
  1422. LLViewerInventoryItem* item = getItem();
  1423. if (!item) return FALSE;
  1424. const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1425. // if item is not already in trash
  1426. if(item && !model->isObjectDescendentOf(mUUID, trash_id))
  1427. {
  1428. // move to trash, and restamp
  1429. LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE);
  1430. // delete was successful
  1431. return TRUE;
  1432. }
  1433. return FALSE;
  1434. }
  1435. BOOL LLItemBridge::isItemCopyable() const
  1436. {
  1437. LLViewerInventoryItem* item = getItem();
  1438. if (item)
  1439. {
  1440. // Can't copy worn objects. DEV-15183
  1441. if(get_is_item_worn(mUUID))
  1442. {
  1443. return FALSE;
  1444. }
  1445. // You can never copy a link.
  1446. if (item->getIsLinkType())
  1447. {
  1448. return FALSE;
  1449. }
  1450. return item->getPermissions().allowCopyBy(gAgent.getID()) || gSavedSettings.getBOOL("InventoryLinking");
  1451. }
  1452. return FALSE;
  1453. }
  1454. BOOL LLItemBridge::copyToClipboard() const
  1455. {
  1456. if(isItemCopyable())
  1457. {
  1458. LLInventoryClipboard::instance().add(mUUID);
  1459. return TRUE;
  1460. }
  1461. return FALSE;
  1462. }
  1463. LLViewerInventoryItem* LLItemBridge::getItem() const
  1464. {
  1465. LLViewerInventoryItem* item = NULL;
  1466. LLInventoryModel* model = getInventoryModel();
  1467. if(model)
  1468. {
  1469. item = (LLViewerInventoryItem*)model->getItem(mUUID);
  1470. }
  1471. return item;
  1472. }
  1473. BOOL LLItemBridge::isItemPermissive() const
  1474. {
  1475. LLViewerInventoryItem* item = getItem();
  1476. if(item)
  1477. {
  1478. return item->getIsFullPerm();
  1479. }
  1480. return FALSE;
  1481. }
  1482. // +=================================================+
  1483. // | LLFolderBridge |
  1484. // +=================================================+
  1485. LLHandle<LLFolderBridge> LLFolderBridge::sSelf;
  1486. // Can be moved to another folder
  1487. BOOL LLFolderBridge::isItemMovable() const
  1488. {
  1489. LLInventoryObject* obj = getInventoryObject();
  1490. if(obj)
  1491. {
  1492. return (!LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType()));
  1493. }
  1494. return FALSE;
  1495. }
  1496. void LLFolderBridge::selectItem()
  1497. {
  1498. }
  1499. // Iterate through a folder's children to determine if
  1500. // all the children are removable.
  1501. class LLIsItemRemovable : public LLFolderViewFunctor
  1502. {
  1503. public:
  1504. LLIsItemRemovable() : mPassed(TRUE) {}
  1505. virtual void doFolder(LLFolderViewFolder* folder)
  1506. {
  1507. mPassed &= folder->getListener()->isItemRemovable();
  1508. }
  1509. virtual void doItem(LLFolderViewItem* item)
  1510. {
  1511. mPassed &= item->getListener()->isItemRemovable();
  1512. }
  1513. BOOL mPassed;
  1514. };
  1515. // Can be destroyed (or moved to trash)
  1516. BOOL LLFolderBridge::isItemRemovable() const
  1517. {
  1518. if (!get_is_category_removable(getInventoryModel(), mUUID))
  1519. {
  1520. return FALSE;
  1521. }
  1522. LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
  1523. LLFolderViewFolder* folderp = dynamic_cast<LLFolderViewFolder*>(panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL);
  1524. if (folderp)
  1525. {
  1526. LLIsItemRemovable folder_test;
  1527. folderp->applyFunctorToChildren(folder_test);
  1528. if (!folder_test.mPassed)
  1529. {
  1530. return FALSE;
  1531. }
  1532. }
  1533. return TRUE;
  1534. }
  1535. BOOL LLFolderBridge::isUpToDate() const
  1536. {
  1537. LLInventoryModel* model = getInventoryModel();
  1538. if(!model) return FALSE;
  1539. LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
  1540. if( !category )
  1541. {
  1542. return FALSE;
  1543. }
  1544. return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;
  1545. }
  1546. BOOL LLFolderBridge::isItemCopyable() const
  1547. {
  1548. // Can copy folders to paste-as-link, but not for straight paste.
  1549. return gSavedSettings.getBOOL("InventoryLinking");
  1550. }
  1551. BOOL LLFolderBridge::copyToClipboard() const
  1552. {
  1553. if(isItemCopyable())
  1554. {
  1555. LLInventoryClipboard::instance().add(mUUID);
  1556. return TRUE;
  1557. }
  1558. return FALSE;
  1559. }
  1560. BOOL LLFolderBridge::isClipboardPasteable() const
  1561. {
  1562. if ( ! LLInvFVBridge::isClipboardPasteable() )
  1563. return FALSE;
  1564. // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
  1565. if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) )
  1566. {
  1567. LLInventoryModel* model = getInventoryModel();
  1568. if ( !model )
  1569. {
  1570. return FALSE;
  1571. }
  1572. LLDynamicArray<LLUUID> objects;
  1573. LLInventoryClipboard::instance().retrieve(objects);
  1574. const LLViewerInventoryCategory *current_cat = getCategory();
  1575. // Search for the direct descendent of current Friends subfolder among all pasted items,
  1576. // and return false if is found.
  1577. for(S32 i = objects.count() - 1; i >= 0; --i)
  1578. {
  1579. const LLUUID &obj_id = objects.get(i);
  1580. if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
  1581. {
  1582. return FALSE;
  1583. }
  1584. }
  1585. }
  1586. return TRUE;
  1587. }
  1588. BOOL LLFolderBridge::isClipboardPasteableAsLink() const
  1589. {
  1590. // Check normal paste-as-link permissions
  1591. if (!LLInvFVBridge::isClipboardPasteableAsLink())
  1592. {
  1593. return FALSE;
  1594. }
  1595. const LLInventoryModel* model = getInventoryModel();
  1596. if (!model)
  1597. {
  1598. return FALSE;
  1599. }
  1600. const LLViewerInventoryCategory *current_cat = getCategory();
  1601. if (current_cat)
  1602. {
  1603. const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat );
  1604. const LLUUID &current_cat_id = current_cat->getUUID();
  1605. LLDynamicArray<LLUUID> objects;
  1606. LLInventoryClipboard::instance().retrieve(objects);
  1607. S32 count = objects.count();
  1608. for(S32 i = 0; i < count; i++)
  1609. {
  1610. const LLUUID &obj_id = objects.get(i);
  1611. const LLInventoryCategory *cat = model->getCategory(obj_id);
  1612. if (cat)
  1613. {
  1614. const LLUUID &cat_id = cat->getUUID();
  1615. // Don't allow recursive pasting
  1616. if ((cat_id == current_cat_id) ||
  1617. model->isObjectDescendentOf(current_cat_id, cat_id))
  1618. {
  1619. return FALSE;
  1620. }
  1621. }
  1622. // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
  1623. if ( is_in_friend_folder )
  1624. {
  1625. // If object is direct descendent of current Friends subfolder than return false.
  1626. // Note: We can't use 'const LLInventoryCategory *cat', because it may be null
  1627. // in case type of obj_id is LLInventoryItem.
  1628. if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
  1629. {
  1630. return FALSE;
  1631. }
  1632. }
  1633. }
  1634. }
  1635. return TRUE;
  1636. }
  1637. static BOOL can_move_to_outbox(LLInventoryItem* inv_item, std::string& tooltip_msg)
  1638. {
  1639. // Collapse links directly to items/folders
  1640. LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
  1641. LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem();
  1642. if (linked_item != NULL)
  1643. {
  1644. inv_item = linked_item;
  1645. }
  1646. bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID());
  1647. if (!allow_transfer)
  1648. {
  1649. tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer");
  1650. return false;
  1651. }
  1652. #if BLOCK_WORN_ITEMS_IN_OUTBOX
  1653. bool worn = get_is_item_worn(inv_item->getUUID());
  1654. if (worn)
  1655. {
  1656. tooltip_msg = LLTrans::getString("TooltipOutboxWorn");
  1657. return false;
  1658. }
  1659. #endif
  1660. bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType());
  1661. if (calling_card)
  1662. {
  1663. tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard");
  1664. return false;
  1665. }
  1666. return true;
  1667. }
  1668. int get_folder_levels(LLInventoryCategory* inv_cat)
  1669. {
  1670. LLInventoryModel::cat_array_t* cats;
  1671. LLInventoryModel::item_array_t* items;
  1672. gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items);
  1673. int max_child_levels = 0;
  1674. for (S32 i=0; i < cats->count(); ++i)
  1675. {
  1676. LLInventoryCategory* category = cats->get(i);
  1677. max_child_levels = llmax(max_child_levels, get_folder_levels(category));
  1678. }
  1679. return 1 + max_child_levels;
  1680. }
  1681. int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id)
  1682. {
  1683. int depth = 0;
  1684. if (ancestor_id == descendant_id) return depth;
  1685. const LLInventoryCategory* category = gInventory.getCategory(descendant_id);
  1686. while(category)
  1687. {
  1688. LLUUID parent_id = category->getParentUUID();
  1689. if (parent_id.isNull()) break;
  1690. depth++;
  1691. if (parent_id == ancestor_id) return depth;
  1692. category = gInventory.getCategory(parent_id);
  1693. }
  1694. llwarns << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << llendl;
  1695. return -1;
  1696. }
  1697. BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
  1698. BOOL drop,
  1699. std::string& tooltip_msg)
  1700. {
  1701. LLInventoryModel* model = getInventoryModel();
  1702. if (!inv_cat) return FALSE; // shouldn't happen, but in case item is incorrectly parented in which case inv_cat will be NULL
  1703. if (!model) return FALSE;
  1704. if (!isAgentAvatarValid()) return FALSE;
  1705. if (!isAgentInventory()) return FALSE; // cannot drag categories into library
  1706. const LLUUID &cat_id = inv_cat->getUUID();
  1707. const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
  1708. const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
  1709. const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
  1710. const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
  1711. const BOOL move_is_from_outbox = model->isObjectDescendentOf(cat_id, outbox_id);
  1712. // check to make sure source is agent inventory, and is represented there.
  1713. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
  1714. const BOOL is_agent_inventory = (model->getCategory(cat_id) != NULL)
  1715. && (LLToolDragAndDrop::SOURCE_AGENT == source);
  1716. BOOL accept = FALSE;
  1717. if (is_agent_inventory)
  1718. {
  1719. const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false);
  1720. const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
  1721. const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
  1722. const BOOL move_is_into_outfit = getCategory() && (getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT);
  1723. const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
  1724. //--------------------------------------------------------------------------------
  1725. // Determine if folder can be moved.
  1726. //
  1727. BOOL is_movable = TRUE;
  1728. if (is_movable && (mUUID == cat_id))
  1729. {
  1730. is_movable = FALSE;
  1731. tooltip_msg = LLTrans::getString("TooltipDragOntoSelf");
  1732. }
  1733. if (is_movable && (model->isObjectDescendentOf(mUUID, cat_id)))
  1734. {
  1735. is_movable = FALSE;
  1736. tooltip_msg = LLTrans::getString("TooltipDragOntoOwnChild");
  1737. }
  1738. if (is_movable && LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
  1739. {
  1740. is_movable = FALSE;
  1741. // tooltip?
  1742. }
  1743. if (is_movable && move_is_into_outfit)
  1744. {
  1745. is_movable = FALSE;
  1746. // tooltip?
  1747. }
  1748. if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
  1749. {
  1750. is_movable = FALSE;
  1751. // tooltip?
  1752. }
  1753. LLInventoryModel::cat_array_t descendent_categories;
  1754. LLInventoryModel::item_array_t descendent_items;
  1755. if (is_movable)
  1756. {
  1757. model->collectDescendents(cat_id, descendent_categories, descendent_items, FALSE);
  1758. for (S32 i=0; i < descendent_categories.count(); ++i)
  1759. {
  1760. LLInventoryCategory* category = descendent_categories[i];
  1761. if(LLFolderType::lookupIsProtectedType(category->getPreferredType()))
  1762. {
  1763. // Can't move "special folders" (e.g. Textures Folder).
  1764. is_movable = FALSE;
  1765. break;
  1766. }
  1767. }
  1768. }
  1769. if (is_movable && move_is_into_trash)
  1770. {
  1771. for (S32 i=0; i < descendent_items.count(); ++i)
  1772. {
  1773. LLInventoryItem* item = descendent_items[i];
  1774. if (get_is_item_worn(item->getUUID()))
  1775. {
  1776. is_movable = FALSE;
  1777. break; // It's generally movable, but not into the trash.
  1778. }
  1779. }
  1780. }
  1781. if (is_movable && move_is_into_landmarks)
  1782. {
  1783. for (S32 i=0; i < descendent_items.count(); ++i)
  1784. {
  1785. LLViewerInventoryItem* item = descendent_items[i];
  1786. // Don't move anything except landmarks and categories into Landmarks folder.
  1787. // We use getType() instead of getActua;Type() to allow links to landmarks and folders.
  1788. if (LLAssetType::AT_LANDMARK != item->getType() && LLAssetType::AT_CATEGORY != item->getType())
  1789. {
  1790. is_movable = FALSE;
  1791. break; // It's generally movable, but not into Landmarks.
  1792. }
  1793. }
  1794. }
  1795. if (is_movable && move_is_into_outbox)
  1796. {
  1797. const int nested_folder_levels = get_folder_path_length(outbox_id, mUUID) + get_folder_levels(inv_cat);
  1798. if (nested_folder_levels > gSavedSettings.getU32("InventoryOutboxMaxFolderDepth"))
  1799. {
  1800. tooltip_msg = LLTrans::getString("TooltipOutboxFolderLevels");
  1801. is_movable = FALSE;
  1802. }
  1803. else
  1804. {
  1805. int dragged_folder_count = descendent_categories.count();
  1806. int existing_item_count = 0;
  1807. int existing_folder_count = 0;
  1808. const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID);
  1809. if (master_folder != NULL)
  1810. {
  1811. if (model->isObjectDescendentOf(cat_id, master_folder->getUUID()))
  1812. {
  1813. // Don't use count because we're already inside the same category anyway
  1814. dragged_folder_count = 0;
  1815. }
  1816. else
  1817. {
  1818. existing_folder_count = 1; // Include the master folder in the count!
  1819. // If we're in the drop operation as opposed to the drag without drop, we are doing a
  1820. // single category at a time so don't block based on the total amount of cargo data items
  1821. if (drop)
  1822. {
  1823. dragged_folder_count += 1;
  1824. }
  1825. else
  1826. {
  1827. // NOTE: The cargo id's count is a total of categories AND items but we err on the side of
  1828. // prevention rather than letting too many folders into the hierarchy of the outbox,
  1829. // when we're dragging the item to a new parent
  1830. dragged_folder_count += LLToolDragAndDrop::instance().getCargoIDsCount();
  1831. }
  1832. }
  1833. // Tally the total number of categories and items inside the master folder
  1834. LLInventoryModel::cat_array_t existing_categories;
  1835. LLInventoryModel::item_array_t existing_items;
  1836. model->collectDescendents(master_folder->getUUID(), existing_categories, existing_items, FALSE);
  1837. existing_folder_count += existing_categories.count();
  1838. existing_item_count += existing_items.count();
  1839. }
  1840. else
  1841. {
  1842. // Assume a single category is being dragged to the outbox since we evaluate one at a time
  1843. // when not putting them under a parent item.
  1844. dragged_folder_count += 1;
  1845. }
  1846. const int nested_folder_count = existing_folder_count + dragged_folder_count;
  1847. const int nested_item_count = existing_item_count + descendent_items.count();
  1848. if (nested_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount"))
  1849. {
  1850. tooltip_msg = LLTrans::getString("TooltipOutboxTooManyFolders");
  1851. is_movable = FALSE;
  1852. }
  1853. else if (nested_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount"))
  1854. {
  1855. tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects");
  1856. is_movable = FALSE;
  1857. }
  1858. if (is_movable == TRUE)
  1859. {
  1860. for (S32 i=0; i < descendent_items.count(); ++i)
  1861. {
  1862. LLInventoryItem* item = descendent_items[i];
  1863. if (!can_move_to_outbox(item, tooltip_msg))
  1864. {
  1865. is_movable = FALSE;
  1866. break;
  1867. }
  1868. }
  1869. }
  1870. }
  1871. }
  1872. //
  1873. //--------------------------------------------------------------------------------
  1874. accept = is_movable;
  1875. if (accept && drop)
  1876. {
  1877. // Look for any gestures and deactivate them
  1878. if (move_is_into_trash)
  1879. {
  1880. for (S32 i=0; i < descendent_items.count(); i++)
  1881. {
  1882. LLInventoryItem* item = descendent_items[i];
  1883. if (item->getType() == LLAssetType::AT_GESTURE
  1884. && LLGestureMgr::instance().isGestureActive(item->getUUID()))
  1885. {
  1886. LLGestureMgr::instance().deactivateGesture(item->getUUID());
  1887. }
  1888. }
  1889. }
  1890. // if target is an outfit or current outfit folder we use link
  1891. if (move_is_into_current_outfit || move_is_into_outfit)
  1892. {
  1893. if (inv_cat->getPreferredType() == LLFolderType::FT_NONE)
  1894. {
  1895. if (move_is_into_current_outfit)
  1896. {
  1897. // traverse category and add all contents to currently worn.
  1898. BOOL append = true;
  1899. LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
  1900. }
  1901. else
  1902. {
  1903. // Recursively create links in target outfit.
  1904. LLInventoryModel::cat_array_t cats;
  1905. LLInventoryModel::item_array_t items;
  1906. model->collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
  1907. LLAppearanceMgr::instance().linkAll(mUUID,items,NULL);
  1908. }
  1909. }
  1910. else
  1911. {
  1912. #if SUPPORT_ENSEMBLES
  1913. // BAP - should skip if dup.
  1914. if (move_is_into_current_outfit)
  1915. {
  1916. LLAppearanceMgr::instance().addEnsembleLink(inv_cat);
  1917. }
  1918. else
  1919. {
  1920. LLPointer<LLInventoryCallback> cb = NULL;
  1921. const std::string empty_description = "";
  1922. link_inventory_item(
  1923. gAgent.getID(),
  1924. cat_id,
  1925. mUUID,
  1926. inv_cat->getName(),
  1927. empty_description,
  1928. LLAssetType::AT_LINK_FOLDER,
  1929. cb);
  1930. }
  1931. #endif
  1932. }
  1933. }
  1934. else if (move_is_into_outbox && !move_is_from_outbox)
  1935. {
  1936. copy_folder_to_outbox(inv_cat, mUUID, cat_id, LLToolDragAndDrop::getOperationId());
  1937. }
  1938. else
  1939. {
  1940. if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false)))
  1941. {
  1942. set_dad_inbox_object(cat_id);
  1943. }
  1944. // Reparent the folder and restamp children if it's moving
  1945. // into trash.
  1946. LLInvFVBridge::changeCategoryParent(
  1947. model,
  1948. (LLViewerInventoryCategory*)inv_cat,
  1949. mUUID,
  1950. move_is_into_trash);
  1951. }
  1952. }
  1953. }
  1954. else if (LLToolDragAndDrop::SOURCE_WORLD == source)
  1955. {
  1956. if (move_is_into_outbox)
  1957. {
  1958. tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
  1959. accept = FALSE;
  1960. }
  1961. else
  1962. {
  1963. accept = move_inv_category_world_to_agent(cat_id, mUUID, drop);
  1964. }
  1965. }
  1966. else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
  1967. {
  1968. if (move_is_into_outbox)
  1969. {
  1970. tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
  1971. accept = FALSE;
  1972. }
  1973. else
  1974. {
  1975. // Accept folders that contain complete outfits.
  1976. accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id);
  1977. }
  1978. if (accept && drop)
  1979. {
  1980. LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, true, false);
  1981. }
  1982. }
  1983. return accept;
  1984. }
  1985. void warn_move_inventory(LLViewerObject* object, LLMoveInv* move_inv)
  1986. {
  1987. const char* dialog = NULL;
  1988. if (object->flagScripted())
  1989. {
  1990. dialog = "MoveInventoryFromScriptedObject";
  1991. }
  1992. else
  1993. {
  1994. dialog = "MoveInventoryFromObject";
  1995. }
  1996. LLNotificationsUtil::add(dialog, LLSD(), LLSD(), boost::bind(move_task_inventory_callback, _1, _2, move_inv));
  1997. }
  1998. // Move/copy all inventory items from the Contents folder of an in-world
  1999. // object to the agent's inventory, inside a given category.
  2000. BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
  2001. const LLUUID& category_id,
  2002. BOOL drop,
  2003. void (*callback)(S32, void*),
  2004. void* user_data)
  2005. {
  2006. // Make sure the object exists. If we allowed dragging from
  2007. // anonymous objects, it would be possible to bypass
  2008. // permissions.
  2009. // content category has same ID as object itself
  2010. LLViewerObject* object = gObjectList.findObject(object_id);
  2011. if(!object)
  2012. {
  2013. llinfos << "Object not found for drop." << llendl;
  2014. return FALSE;
  2015. }
  2016. // this folder is coming from an object, as there is only one folder in an object, the root,
  2017. // we need to collect the entire contents and handle them as a group
  2018. LLInventoryObject::object_list_t inventory_objects;
  2019. object->getInventoryContents(inventory_objects);
  2020. if (inventory_objects.empty())
  2021. {
  2022. llinfos << "Object contents not found for drop." << llendl;
  2023. return FALSE;
  2024. }
  2025. BOOL accept = TRUE;
  2026. BOOL is_move = FALSE;
  2027. // coming from a task. Need to figure out if the person can
  2028. // move/copy this item.
  2029. LLInventoryObject::object_list_t::iterator it = inventory_objects.begin();
  2030. LLInventoryObject::object_list_t::iterator end = inventory_objects.end();
  2031. for ( ; it != end; ++it)
  2032. {
  2033. // coming from a task. Need to figure out if the person can
  2034. // move/copy this item.
  2035. LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions());
  2036. if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
  2037. && perm.allowTransferTo(gAgent.getID())))
  2038. // || gAgent.isGodlike())
  2039. {
  2040. accept = TRUE;
  2041. }
  2042. else if(object->permYouOwner())
  2043. {
  2044. // If the object cannot be copied, but the object the
  2045. // inventory is owned by the agent, then the item can be
  2046. // moved from the task to agent inventory.
  2047. is_move = TRUE;
  2048. accept = TRUE;
  2049. }
  2050. else
  2051. {
  2052. accept = FALSE;
  2053. break;
  2054. }
  2055. }
  2056. if(drop && accept)
  2057. {
  2058. it = inventory_objects.begin();
  2059. LLInventoryObject::object_list_t::iterator first_it = inventory_objects.begin();
  2060. LLMoveInv* move_inv = new LLMoveInv;
  2061. move_inv->mObjectID = object_id;
  2062. move_inv->mCategoryID = category_id;
  2063. move_inv->mCallback = callback;
  2064. move_inv->mUserData = user_data;
  2065. for ( ; it != end; ++it)
  2066. {
  2067. two_uuids_t two(category_id, (*it)->getUUID());
  2068. move_inv->mMoveList.push_back(two);
  2069. }
  2070. if(is_move)
  2071. {
  2072. // Callback called from within here.
  2073. warn_move_inventory(object, move_inv);
  2074. }
  2075. else
  2076. {
  2077. LLNotification::Params params("MoveInventoryFromObject");
  2078. params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv));
  2079. LLNotifications::instance().forceResponse(params, 0);
  2080. }
  2081. }
  2082. return accept;
  2083. }
  2084. //Used by LLFolderBridge as callback for directory recursion.
  2085. class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver
  2086. {
  2087. public:
  2088. LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) :
  2089. LLInventoryFetchItemsObserver(ids),
  2090. mCopyItems(false)
  2091. { };
  2092. LLRightClickInventoryFetchObserver(const uuid_vec_t& ids,
  2093. const LLUUID& cat_id,
  2094. bool copy_items) :
  2095. LLInventoryFetchItemsObserver(ids),
  2096. mCatID(cat_id),
  2097. mCopyItems(copy_items)
  2098. { };
  2099. virtual void done()
  2100. {
  2101. // we've downloaded all the items, so repaint the dialog
  2102. LLFolderBridge::staticFolderOptionsMenu();
  2103. gInventory.removeObserver(this);
  2104. delete this;
  2105. }
  2106. protected:
  2107. LLUUID mCatID;
  2108. bool mCopyItems;
  2109. };
  2110. //Used by LLFolderBridge as callback for directory recursion.
  2111. class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
  2112. {
  2113. public:
  2114. LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids,
  2115. bool copy_items) :
  2116. LLInventoryFetchDescendentsObserver(ids),
  2117. mCopyItems(copy_items)
  2118. {}
  2119. ~LLRightClickInventoryFetchDescendentsObserver() {}
  2120. virtual void done();
  2121. protected:
  2122. bool mCopyItems;
  2123. };
  2124. void LLRightClickInventoryFetchDescendentsObserver::done()
  2125. {
  2126. // Avoid passing a NULL-r