llinventorybridge.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:140k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file llinventorybridge.cpp
  3.  * @brief Implementation of the Inventory-Folder-View-Bridge classes.
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llinventorybridge.h"
  34. #include "llagent.h"
  35. #include "llagentwearables.h"
  36. #include "llappearancemgr.h"
  37. #include "llavataractions.h"
  38. #include "llfloatercustomize.h"
  39. #include "llfloateropenobject.h"
  40. #include "llfloaterreg.h"
  41. #include "llfloaterworldmap.h"
  42. #include "llfriendcard.h"
  43. #include "llgesturemgr.h"
  44. #include "llimfloater.h"
  45. #include "llimview.h"
  46. #include "llinventoryclipboard.h"
  47. #include "llinventoryfunctions.h"
  48. #include "llinventorymodel.h"
  49. #include "llinventorypanel.h"
  50. #include "llnotifications.h"
  51. #include "llnotificationsutil.h"
  52. #include "llpreviewanim.h"
  53. #include "llpreviewgesture.h"
  54. #include "llpreviewtexture.h"
  55. #include "llselectmgr.h"
  56. #include "llsidetray.h"
  57. #include "lltrans.h"
  58. #include "llviewerassettype.h"
  59. #include "llviewermessage.h"
  60. #include "llviewerobjectlist.h"
  61. #include "llviewerwindow.h"
  62. #include "llvoavatarself.h"
  63. #include "llwearablelist.h"
  64. #include "llpaneloutfitsinventory.h"
  65. using namespace LLOldEvents;
  66. // Helpers
  67. // bug in busy count inc/dec right now, logic is complex... do we really need it?
  68. void inc_busy_count()
  69. {
  70. //  gViewerWindow->getWindow()->incBusyCount();
  71. //  check balance of these calls if this code is changed to ever actually
  72. //  *do* something!
  73. }
  74. void dec_busy_count()
  75. {
  76. //  gViewerWindow->getWindow()->decBusyCount();
  77. //  check balance of these calls if this code is changed to ever actually
  78. //  *do* something!
  79. }
  80. // Function declarations
  81. void wear_add_inventory_item_on_avatar(LLInventoryItem* item);
  82. void remove_inventory_category_from_avatar(LLInventoryCategory* category);
  83. void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id);
  84. bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
  85. bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response);
  86. std::string ICON_NAME[ICON_NAME_COUNT] =
  87. {
  88. "Inv_Texture",
  89. "Inv_Sound",
  90. "Inv_CallingCard",
  91. "Inv_CallingCard",
  92. "Inv_Landmark",
  93. "Inv_Landmark",
  94. "Inv_Script",
  95. "Inv_Clothing",
  96. "Inv_Object",
  97. "Inv_Object",
  98. "Inv_Notecard",
  99. "Inv_Skin",
  100. "Inv_Snapshot",
  101. "Inv_BodyShape",
  102. "Inv_Skin",
  103. "Inv_Hair",
  104. "Inv_Eye",
  105. "Inv_Shirt",
  106. "Inv_Pants",
  107. "Inv_Shoe",
  108. "Inv_Socks",
  109. "Inv_Jacket",
  110. "Inv_Gloves",
  111. "Inv_Undershirt",
  112. "Inv_Underpants",
  113. "Inv_Skirt",
  114. "Inv_Alpha",
  115. "Inv_Tattoo",
  116. "Inv_Animation",
  117. "Inv_Gesture",
  118. "Inv_LinkItem",
  119. "Inv_LinkFolder"
  120. };
  121. // +=================================================+
  122. // |        LLInvFVBridge                            |
  123. // +=================================================+
  124. LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) :
  125. mUUID(uuid), mInvType(LLInventoryType::IT_NONE)
  126. {
  127. mInventoryPanel = inventory->getHandle();
  128. }
  129. const std::string& LLInvFVBridge::getName() const
  130. {
  131. LLInventoryObject* obj = getInventoryObject();
  132. if(obj)
  133. {
  134. return obj->getName();
  135. }
  136. return LLStringUtil::null;
  137. }
  138. const std::string& LLInvFVBridge::getDisplayName() const
  139. {
  140. return getName();
  141. }
  142. // Folders have full perms
  143. PermissionMask LLInvFVBridge::getPermissionMask() const
  144. {
  145. return PERM_ALL;
  146. }
  147. // virtual
  148. LLFolderType::EType LLInvFVBridge::getPreferredType() const
  149. {
  150. return LLFolderType::FT_NONE;
  151. }
  152. // Folders don't have creation dates.
  153. time_t LLInvFVBridge::getCreationDate() const
  154. {
  155. return 0;
  156. }
  157. // Can be destroyed (or moved to trash)
  158. BOOL LLInvFVBridge::isItemRemovable() const
  159. {
  160. const LLInventoryModel* model = getInventoryModel();
  161. if(!model) 
  162. {
  163. return FALSE;
  164. }
  165. // Can't delete an item that's in the library.
  166. if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()))
  167. {
  168. return FALSE;
  169. }
  170. // Disable delete from COF folder; have users explicitly choose "detach/take off".
  171. if (LLAppearanceManager::instance().getIsProtectedCOFItem(mUUID))
  172. {
  173. return FALSE;
  174. }
  175. const LLInventoryObject *obj = model->getItem(mUUID);
  176. if (obj && obj->getIsLinkType())
  177. {
  178. return TRUE;
  179. }
  180. if (get_is_item_worn(mUUID))
  181. {
  182. return FALSE;
  183. }
  184. return TRUE;
  185. }
  186. // Can be moved to another folder
  187. BOOL LLInvFVBridge::isItemMovable() const
  188. {
  189. return TRUE;
  190. }
  191. /*virtual*/
  192. /**
  193.  * @brief Adds this item into clipboard storage
  194.  */
  195. void LLInvFVBridge::cutToClipboard()
  196. {
  197. if(isItemMovable())
  198. {
  199. LLInventoryClipboard::instance().cut(mUUID);
  200. }
  201. }
  202. // *TODO: make sure this does the right thing
  203. void LLInvFVBridge::showProperties()
  204. {
  205. LLSD key;
  206. key["id"] = mUUID;
  207. LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
  208. // Disable old properties floater; this is replaced by the sidepanel.
  209. /*
  210. LLFloaterReg::showInstance("properties", mUUID);
  211. */
  212. }
  213. void LLInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch)
  214. {
  215. // Deactivate gestures when moving them into Trash
  216. LLInvFVBridge* bridge;
  217. LLInventoryModel* model = getInventoryModel();
  218. LLViewerInventoryItem* item = NULL;
  219. LLViewerInventoryCategory* cat = NULL;
  220. LLInventoryModel::cat_array_t descendent_categories;
  221. LLInventoryModel::item_array_t descendent_items;
  222. S32 count = batch.count();
  223. S32 i,j;
  224. for(i = 0; i < count; ++i)
  225. {
  226. bridge = (LLInvFVBridge*)(batch.get(i));
  227. if(!bridge || !bridge->isItemRemovable()) continue;
  228. item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
  229. if (item)
  230. {
  231. if(LLAssetType::AT_GESTURE == item->getType())
  232. {
  233. LLGestureManager::instance().deactivateGesture(item->getUUID());
  234. }
  235. }
  236. }
  237. for(i = 0; i < count; ++i)
  238. {
  239. bridge = (LLInvFVBridge*)(batch.get(i));
  240. if(!bridge || !bridge->isItemRemovable()) continue;
  241. cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
  242. if (cat)
  243. {
  244. gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, FALSE );
  245. for (j=0; j<descendent_items.count(); j++)
  246. {
  247. if(LLAssetType::AT_GESTURE == descendent_items[j]->getType())
  248. {
  249. LLGestureManager::instance().deactivateGesture(descendent_items[j]->getUUID());
  250. }
  251. }
  252. }
  253. }
  254. removeBatchNoCheck(batch);
  255. }
  256. void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*>& batch)
  257. {
  258. // this method moves a bunch of items and folders to the trash. As
  259. // per design guidelines for the inventory model, the message is
  260. // built and the accounting is performed first. After all of that,
  261. // we call LLInventoryModel::moveObject() to move everything
  262. // around.
  263. LLInvFVBridge* bridge;
  264. LLInventoryModel* model = getInventoryModel();
  265. if(!model) return;
  266. LLMessageSystem* msg = gMessageSystem;
  267. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  268. LLViewerInventoryItem* item = NULL;
  269. std::vector<LLUUID> move_ids;
  270. LLInventoryModel::update_map_t update;
  271. bool start_new_message = true;
  272. S32 count = batch.count();
  273. S32 i;
  274. // first, hide any 'preview' floaters that correspond to the items
  275. // being deleted.
  276. for(i = 0; i < count; ++i)
  277. {
  278. bridge = (LLInvFVBridge*)(batch.get(i));
  279. if(!bridge || !bridge->isItemRemovable()) continue;
  280. item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
  281. if(item)
  282. {
  283. LLPreview::hide(item->getUUID());
  284. }
  285. }
  286. // do the inventory move to trash
  287. for(i = 0; i < count; ++i)
  288. {
  289. bridge = (LLInvFVBridge*)(batch.get(i));
  290. if(!bridge || !bridge->isItemRemovable()) continue;
  291. item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
  292. if(item)
  293. {
  294. if(item->getParentUUID() == trash_id) continue;
  295. move_ids.push_back(item->getUUID());
  296. --update[item->getParentUUID()];
  297. ++update[trash_id];
  298. if(start_new_message)
  299. {
  300. start_new_message = false;
  301. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  302. msg->nextBlockFast(_PREHASH_AgentData);
  303. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  304. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  305. msg->addBOOLFast(_PREHASH_Stamp, TRUE);
  306. }
  307. msg->nextBlockFast(_PREHASH_InventoryData);
  308. msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
  309. msg->addUUIDFast(_PREHASH_FolderID, trash_id);
  310. msg->addString("NewName", NULL);
  311. if(msg->isSendFullFast(_PREHASH_InventoryData))
  312. {
  313. start_new_message = true;
  314. gAgent.sendReliableMessage();
  315. gInventory.accountForUpdate(update);
  316. update.clear();
  317. }
  318. }
  319. }
  320. if(!start_new_message)
  321. {
  322. start_new_message = true;
  323. gAgent.sendReliableMessage();
  324. gInventory.accountForUpdate(update);
  325. update.clear();
  326. }
  327. for(i = 0; i < count; ++i)
  328. {
  329. bridge = (LLInvFVBridge*)(batch.get(i));
  330. if(!bridge || !bridge->isItemRemovable()) continue;
  331. LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
  332. if(cat)
  333. {
  334. if(cat->getParentUUID() == trash_id) continue;
  335. move_ids.push_back(cat->getUUID());
  336. --update[cat->getParentUUID()];
  337. ++update[trash_id];
  338. if(start_new_message)
  339. {
  340. start_new_message = false;
  341. msg->newMessageFast(_PREHASH_MoveInventoryFolder);
  342. msg->nextBlockFast(_PREHASH_AgentData);
  343. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  344. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  345. msg->addBOOL("Stamp", TRUE);
  346. }
  347. msg->nextBlockFast(_PREHASH_InventoryData);
  348. msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID());
  349. msg->addUUIDFast(_PREHASH_ParentID, trash_id);
  350. if(msg->isSendFullFast(_PREHASH_InventoryData))
  351. {
  352. start_new_message = true;
  353. gAgent.sendReliableMessage();
  354. gInventory.accountForUpdate(update);
  355. update.clear();
  356. }
  357. }
  358. }
  359. if(!start_new_message)
  360. {
  361. gAgent.sendReliableMessage();
  362. gInventory.accountForUpdate(update);
  363. }
  364. // move everything.
  365. std::vector<LLUUID>::iterator it = move_ids.begin();
  366. std::vector<LLUUID>::iterator end = move_ids.end();
  367. for(; it != end; ++it)
  368. {
  369. gInventory.moveObject((*it), trash_id);
  370. }
  371. // notify inventory observers.
  372. model->notifyObservers();
  373. }
  374. BOOL LLInvFVBridge::isClipboardPasteable() const
  375. {
  376. if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
  377. {
  378. return FALSE;
  379. }
  380. LLInventoryModel* model = getInventoryModel();
  381. if (!model)
  382. {
  383. return FALSE;
  384. }
  385. const LLUUID &agent_id = gAgent.getID();
  386. LLDynamicArray<LLUUID> objects;
  387. LLInventoryClipboard::instance().retrieve(objects);
  388. S32 count = objects.count();
  389. for(S32 i = 0; i < count; i++)
  390. {
  391. const LLUUID &item_id = objects.get(i);
  392. // Can't paste folders
  393. const LLInventoryCategory *cat = model->getCategory(item_id);
  394. if (cat)
  395. {
  396. return FALSE;
  397. }
  398. const LLInventoryItem *item = model->getItem(item_id);
  399. if (item)
  400. {
  401. if (!item->getPermissions().allowCopyBy(agent_id))
  402. {
  403. return FALSE;
  404. }
  405. }
  406. }
  407. return TRUE;
  408. }
  409. BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
  410. {
  411. if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory())
  412. {
  413. return FALSE;
  414. }
  415. const LLInventoryModel* model = getInventoryModel();
  416. if (!model)
  417. {
  418. return FALSE;
  419. }
  420. LLDynamicArray<LLUUID> objects;
  421. LLInventoryClipboard::instance().retrieve(objects);
  422. S32 count = objects.count();
  423. for(S32 i = 0; i < count; i++)
  424. {
  425. const LLInventoryItem *item = model->getItem(objects.get(i));
  426. if (item)
  427. {
  428. if (!LLAssetType::lookupCanLink(item->getActualType()))
  429. {
  430. return FALSE;
  431. }
  432. }
  433. const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i));
  434. if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
  435. {
  436. return FALSE;
  437. }
  438. }
  439. return TRUE;
  440. }
  441. void hide_context_entries(LLMenuGL& menu, 
  442. const menuentry_vec_t &entries_to_show,
  443. const menuentry_vec_t &disabled_entries)
  444. {
  445. const LLView::child_list_t *list = menu.getChildList();
  446. // For removing double separators or leading separator.  Start at true so that
  447. // if the first element is a separator, it will not be shown.
  448. BOOL is_previous_entry_separator = TRUE;
  449. LLView::child_list_t::const_iterator itor;
  450. for (itor = list->begin(); itor != list->end(); ++itor)
  451. {
  452. std::string name = (*itor)->getName();
  453. // descend into split menus:
  454. LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(*itor);
  455. if ((name == "More") && branchp)
  456. {
  457. hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries);
  458. }
  459. bool found = false;
  460. menuentry_vec_t::const_iterator itor2;
  461. for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2)
  462. {
  463. if (*itor2 == name)
  464. {
  465. found = true;
  466. }
  467. }
  468. // Don't allow multiple separators in a row (e.g. such as if there are no items
  469. // between two separators).
  470. if (found)
  471. {
  472. const BOOL is_entry_separator = (dynamic_cast<LLMenuItemSeparatorGL *>(*itor) != NULL);
  473. if (is_entry_separator && is_previous_entry_separator)
  474. found = false;
  475. is_previous_entry_separator = is_entry_separator;
  476. }
  477. if (!found)
  478. {
  479. (*itor)->setVisible(FALSE);
  480. }
  481. else
  482. {
  483. (*itor)->setVisible(TRUE);
  484. for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2)
  485. {
  486. if (*itor2 == name)
  487. {
  488. (*itor)->setEnabled(FALSE);
  489. }
  490. }
  491. }
  492. }
  493. }
  494. // Helper for commonly-used entries
  495. void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
  496. menuentry_vec_t &items,
  497. menuentry_vec_t &disabled_items, U32 flags)
  498. {
  499. const LLInventoryObject *obj = getInventoryObject();
  500. bool is_sidepanel = isInOutfitsSidePanel();
  501. if (is_sidepanel)
  502. {
  503. // Sidepanel includes restricted menu.
  504. if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID))
  505. {
  506. items.push_back(std::string("Remove Link"));
  507. }
  508. return;
  509. }
  510. if (obj)
  511. {
  512. if (obj->getIsLinkType())
  513. {
  514. items.push_back(std::string("Find Original"));
  515. if (isLinkedObjectMissing())
  516. {
  517. disabled_items.push_back(std::string("Find Original"));
  518. }
  519. }
  520. else
  521. {
  522. if (LLAssetType::lookupCanLink(obj->getType()))
  523. {
  524. items.push_back(std::string("Find Links"));
  525. }
  526. items.push_back(std::string("Rename"));
  527. if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0)
  528. {
  529. disabled_items.push_back(std::string("Rename"));
  530. }
  531. if (show_asset_id)
  532. {
  533. items.push_back(std::string("Copy Asset UUID"));
  534. if ( (! ( isItemPermissive() || gAgent.isGodlike() ) )
  535.  || (flags & FIRST_SELECTED_ITEM) == 0)
  536. {
  537. disabled_items.push_back(std::string("Copy Asset UUID"));
  538. }
  539. }
  540. items.push_back(std::string("Copy Separator"));
  541. items.push_back(std::string("Copy"));
  542. if (!isItemCopyable())
  543. {
  544. disabled_items.push_back(std::string("Copy"));
  545. }
  546. }
  547. }
  548. // Don't allow items to be pasted directly into the COF.
  549. if (!isCOFFolder())
  550. {
  551. items.push_back(std::string("Paste"));
  552. }
  553. if (!isClipboardPasteable() || ((flags & FIRST_SELECTED_ITEM) == 0))
  554. {
  555. disabled_items.push_back(std::string("Paste"));
  556. }
  557. if (gAgent.isGodlike())
  558. {
  559. items.push_back(std::string("Paste As Link"));
  560. if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0)
  561. {
  562. disabled_items.push_back(std::string("Paste As Link"));
  563. }
  564. }
  565. items.push_back(std::string("Paste Separator"));
  566. addDeleteContextMenuOptions(items, disabled_items);
  567. // If multiple items are selected, disable properties (if it exists).
  568. if ((flags & FIRST_SELECTED_ITEM) == 0)
  569. {
  570. disabled_items.push_back(std::string("Properties"));
  571. }
  572. }
  573. void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
  574. {
  575. lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl;
  576. menuentry_vec_t items;
  577. menuentry_vec_t disabled_items;
  578. if(isItemInTrash())
  579. {
  580. addTrashContextMenuOptions(items, disabled_items);
  581. }
  582. else
  583. {
  584. items.push_back(std::string("Open"));
  585. items.push_back(std::string("Properties"));
  586. getClipboardEntries(true, items, disabled_items, flags);
  587. }
  588. hide_context_entries(menu, items, disabled_items);
  589. }
  590. void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items,
  591.    menuentry_vec_t &disabled_items)
  592. {
  593. const LLInventoryObject *obj = getInventoryObject();
  594. if (obj && obj->getIsLinkType())
  595. {
  596. items.push_back(std::string("Find Original"));
  597. if (isLinkedObjectMissing())
  598. {
  599. disabled_items.push_back(std::string("Find Original"));
  600. }
  601. }
  602. items.push_back(std::string("Purge Item"));
  603. if (!isItemRemovable())
  604. {
  605. disabled_items.push_back(std::string("Purge Item"));
  606. }
  607. items.push_back(std::string("Restore Item"));
  608. }
  609. void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
  610. menuentry_vec_t &disabled_items)
  611. {
  612. // Don't allow delete as a direct option from COF folder.
  613. if (isCOFFolder())
  614. {
  615. return;
  616. }
  617. const LLInventoryObject *obj = getInventoryObject();
  618. // "Remove link" and "Delete" are the same operation.
  619. if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID))
  620. {
  621. items.push_back(std::string("Remove Link"));
  622. }
  623. else
  624. {
  625. items.push_back(std::string("Delete"));
  626. }
  627. if (!isItemRemovable())
  628. {
  629. disabled_items.push_back(std::string("Delete"));
  630. }
  631. }
  632. // *TODO: remove this
  633. BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
  634. {
  635. BOOL rv = FALSE;
  636. const LLInventoryObject* obj = getInventoryObject();
  637. if(obj)
  638. {
  639. *type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
  640. if(*type == DAD_NONE)
  641. {
  642. return FALSE;
  643. }
  644. *id = obj->getUUID();
  645. //object_ids.put(obj->getUUID());
  646. if (*type == DAD_CATEGORY)
  647. {
  648. gInventory.startBackgroundFetch(obj->getUUID());
  649. }
  650. rv = TRUE;
  651. }
  652. return rv;
  653. }
  654. LLInventoryObject* LLInvFVBridge::getInventoryObject() const
  655. {
  656. LLInventoryObject* obj = NULL;
  657. LLInventoryModel* model = getInventoryModel();
  658. if(model)
  659. {
  660. obj = (LLInventoryObject*)model->getObject(mUUID);
  661. }
  662. return obj;
  663. }
  664. LLInventoryModel* LLInvFVBridge::getInventoryModel() const
  665. {
  666. LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
  667. return panel ? panel->getModel() : NULL;
  668. }
  669. BOOL LLInvFVBridge::isItemInTrash() const
  670. {
  671. LLInventoryModel* model = getInventoryModel();
  672. if(!model) return FALSE;
  673. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  674. return model->isObjectDescendentOf(mUUID, trash_id);
  675. }
  676. BOOL LLInvFVBridge::isLinkedObjectInTrash() const
  677. {
  678. if (isItemInTrash()) return TRUE;
  679. const LLInventoryObject *obj = getInventoryObject();
  680. if (obj && obj->getIsLinkType())
  681. {
  682. LLInventoryModel* model = getInventoryModel();
  683. if(!model) return FALSE;
  684. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  685. return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id);
  686. }
  687. return FALSE;
  688. }
  689. BOOL LLInvFVBridge::isLinkedObjectMissing() const
  690. {
  691. const LLInventoryObject *obj = getInventoryObject();
  692. if (!obj)
  693. {
  694. return TRUE;
  695. }
  696. if (obj->getIsLinkType() && LLAssetType::lookupIsLinkType(obj->getType()))
  697. {
  698. return TRUE;
  699. }
  700. return FALSE;
  701. }
  702. BOOL LLInvFVBridge::isAgentInventory() const
  703. {
  704. const LLInventoryModel* model = getInventoryModel();
  705. if(!model) return FALSE;
  706. if(gInventory.getRootFolderID() == mUUID) return TRUE;
  707. return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
  708. }
  709. BOOL LLInvFVBridge::isCOFFolder() const
  710. {
  711. return LLAppearanceManager::instance().getIsInCOF(mUUID);
  712. }
  713. BOOL LLInvFVBridge::isItemPermissive() const
  714. {
  715. return FALSE;
  716. }
  717. // static
  718. void LLInvFVBridge::changeItemParent(LLInventoryModel* model,
  719.  LLViewerInventoryItem* item,
  720.  const LLUUID& new_parent_id,
  721.  BOOL restamp)
  722. {
  723. if (item->getParentUUID() != new_parent_id)
  724. {
  725. LLInventoryModel::update_list_t update;
  726. LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
  727. update.push_back(old_folder);
  728. LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
  729. update.push_back(new_folder);
  730. gInventory.accountForUpdate(update);
  731. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  732. new_item->setParent(new_parent_id);
  733. new_item->updateParentOnServer(restamp);
  734. model->updateItem(new_item);
  735. model->notifyObservers();
  736. }
  737. }
  738. // static
  739. void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
  740.  LLViewerInventoryCategory* cat,
  741.  const LLUUID& new_parent_id,
  742.  BOOL restamp)
  743. {
  744. // Can't move a folder into a child of itself.
  745. if (model->isObjectDescendentOf(new_parent_id, cat->getUUID()))
  746. {
  747. return;
  748. }
  749. LLInventoryModel::update_list_t update;
  750. LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
  751. update.push_back(old_folder);
  752. LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
  753. update.push_back(new_folder);
  754. model->accountForUpdate(update);
  755. LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
  756. new_cat->setParent(new_parent_id);
  757. new_cat->updateParentOnServer(restamp);
  758. model->updateCategory(new_cat);
  759. model->notifyObservers();
  760. }
  761. const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type)
  762. {
  763. const std::string rv= LLInventoryType::lookup(inv_type);
  764. if(rv.empty())
  765. {
  766. return std::string("<invalid>");
  767. }
  768. return rv;
  769. }
  770. LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
  771.    LLAssetType::EType actual_asset_type,
  772.    LLInventoryType::EType inv_type,
  773.    LLInventoryPanel* inventory,
  774.    const LLUUID& uuid,
  775.    U32 flags)
  776. {
  777. LLInvFVBridge* new_listener = NULL;
  778. switch(asset_type)
  779. {
  780. case LLAssetType::AT_TEXTURE:
  781. if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
  782. {
  783. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  784. }
  785. new_listener = new LLTextureBridge(inventory, uuid, inv_type);
  786. break;
  787. case LLAssetType::AT_SOUND:
  788. if(!(inv_type == LLInventoryType::IT_SOUND))
  789. {
  790. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  791. }
  792. new_listener = new LLSoundBridge(inventory, uuid);
  793. break;
  794. case LLAssetType::AT_LANDMARK:
  795. if(!(inv_type == LLInventoryType::IT_LANDMARK))
  796. {
  797. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  798. }
  799. new_listener = new LLLandmarkBridge(inventory, uuid, flags);
  800. break;
  801. case LLAssetType::AT_CALLINGCARD:
  802. if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
  803. {
  804. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  805. }
  806. new_listener = new LLCallingCardBridge(inventory, uuid);
  807. break;
  808. case LLAssetType::AT_SCRIPT:
  809. if(!(inv_type == LLInventoryType::IT_LSL))
  810. {
  811. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  812. }
  813. new_listener = new LLScriptBridge(inventory, uuid);
  814. break;
  815. case LLAssetType::AT_OBJECT:
  816. if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
  817. {
  818. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  819. }
  820. new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags);
  821. break;
  822. case LLAssetType::AT_NOTECARD:
  823. if(!(inv_type == LLInventoryType::IT_NOTECARD))
  824. {
  825. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  826. }
  827. new_listener = new LLNotecardBridge(inventory, uuid);
  828. break;
  829. case LLAssetType::AT_ANIMATION:
  830. if(!(inv_type == LLInventoryType::IT_ANIMATION))
  831. {
  832. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  833. }
  834. new_listener = new LLAnimationBridge(inventory, uuid);
  835. break;
  836. case LLAssetType::AT_GESTURE:
  837. if(!(inv_type == LLInventoryType::IT_GESTURE))
  838. {
  839. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  840. }
  841. new_listener = new LLGestureBridge(inventory, uuid);
  842. break;
  843. case LLAssetType::AT_LSL_TEXT:
  844. if(!(inv_type == LLInventoryType::IT_LSL))
  845. {
  846. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  847. }
  848. new_listener = new LLLSLTextBridge(inventory, uuid);
  849. break;
  850. case LLAssetType::AT_CLOTHING:
  851. case LLAssetType::AT_BODYPART:
  852. if(!(inv_type == LLInventoryType::IT_WEARABLE))
  853. {
  854. llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
  855. }
  856. new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags);
  857. break;
  858. case LLAssetType::AT_CATEGORY:
  859. if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
  860. {
  861. // Create a link folder handler instead.
  862. new_listener = new LLLinkFolderBridge(inventory, uuid);
  863. break;
  864. }
  865. new_listener = new LLFolderBridge(inventory, uuid);
  866. break;
  867. case LLAssetType::AT_LINK:
  868. case LLAssetType::AT_LINK_FOLDER:
  869. // Only should happen for broken links.
  870. new_listener = new LLLinkItemBridge(inventory, uuid);
  871. break;
  872. default:
  873. llinfos << "Unhandled asset type (llassetstorage.h): "
  874. << (S32)asset_type << llendl;
  875. break;
  876. }
  877. if (new_listener)
  878. {
  879. new_listener->mInvType = inv_type;
  880. }
  881. return new_listener;
  882. }
  883. void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
  884. {
  885. LLInventoryCategory* cat = model->getCategory(uuid);
  886. if (cat)
  887. {
  888. model->purgeDescendentsOf(uuid);
  889. model->notifyObservers();
  890. }
  891. LLInventoryObject* obj = model->getObject(uuid);
  892. if (obj)
  893. {
  894. model->purgeObject(uuid);
  895. model->notifyObservers();
  896. }
  897. }
  898. bool LLInvFVBridge::isInOutfitsSidePanel() const
  899. {
  900. LLInventoryPanel *my_panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
  901. LLPanelOutfitsInventory *outfit_panel =
  902. dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
  903. if (!outfit_panel)
  904. return false;
  905. return outfit_panel->isTabPanel(my_panel);
  906. }
  907. // +=================================================+
  908. // |        InventoryFVBridgeBuilder                 |
  909. // +=================================================+
  910. LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type,
  911. LLAssetType::EType actual_asset_type,
  912. LLInventoryType::EType inv_type,
  913. LLInventoryPanel* inventory,
  914. const LLUUID& uuid,
  915. U32 flags /* = 0x00 */) const
  916. {
  917. return LLInvFVBridge::createBridge(asset_type,
  918. actual_asset_type,
  919. inv_type,
  920. inventory,
  921. uuid,
  922. flags);
  923. }
  924. // +=================================================+
  925. // |        LLItemBridge                             |
  926. // +=================================================+
  927. void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action)
  928. {
  929. if ("goto" == action)
  930. {
  931. gotoItem(folder);
  932. }
  933. if ("open" == action)
  934. {
  935. openItem();
  936. return;
  937. }
  938. else if ("properties" == action)
  939. {
  940. showProperties();
  941. return;
  942. }
  943. else if ("purge" == action)
  944. {
  945. purgeItem(model, mUUID);
  946. return;
  947. }
  948. else if ("restoreToWorld" == action)
  949. {
  950. restoreToWorld();
  951. return;
  952. }
  953. else if ("restore" == action)
  954. {
  955. restoreItem();
  956. return;
  957. }
  958. else if ("copy_uuid" == action)
  959. {
  960. // Single item only
  961. LLInventoryItem* item = model->getItem(mUUID);
  962. if(!item) return;
  963. LLUUID asset_id = item->getAssetUUID();
  964. std::string buffer;
  965. asset_id.toString(buffer);
  966. gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer));
  967. return;
  968. }
  969. else if ("copy" == action)
  970. {
  971. copyToClipboard();
  972. return;
  973. }
  974. else if ("paste" == action)
  975. {
  976. // Single item only
  977. LLInventoryItem* itemp = model->getItem(mUUID);
  978. if (!itemp) return;
  979. LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID());
  980. if (!folder_view_itemp) return;
  981. folder_view_itemp->getListener()->pasteFromClipboard();
  982. return;
  983. }
  984. else if ("paste_link" == action)
  985. {
  986. // Single item only
  987. LLInventoryItem* itemp = model->getItem(mUUID);
  988. if (!itemp) return;
  989. LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID());
  990. if (!folder_view_itemp) return;
  991. folder_view_itemp->getListener()->pasteLinkFromClipboard();
  992. return;
  993. }
  994. }
  995. void LLItemBridge::selectItem()
  996. {
  997. LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
  998. if(item && !item->isComplete())
  999. {
  1000. item->fetchFromServer();
  1001. }
  1002. }
  1003. void LLItemBridge::restoreItem()
  1004. {
  1005. LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
  1006. if(item)
  1007. {
  1008. LLInventoryModel* model = getInventoryModel();
  1009. const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType()));
  1010. // do not restamp on restore.
  1011. LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
  1012. }
  1013. }
  1014. void LLItemBridge::restoreToWorld()
  1015. {
  1016. //Similar functionality to the drag and drop rez logic
  1017. bool remove_from_inventory = false;
  1018. LLViewerInventoryItem* itemp = (LLViewerInventoryItem*)getItem();
  1019. if (itemp)
  1020. {
  1021. LLMessageSystem* msg = gMessageSystem;
  1022. msg->newMessage("RezRestoreToWorld");
  1023. msg->nextBlockFast(_PREHASH_AgentData);
  1024. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1025. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1026. msg->nextBlockFast(_PREHASH_InventoryData);
  1027. itemp->packMessage(msg);
  1028. msg->sendReliable(gAgent.getRegion()->getHost());
  1029. //remove local inventory copy, sim will deal with permissions and removing the item
  1030. //from the actual inventory if its a no-copy etc
  1031. if(!itemp->getPermissions().allowCopyBy(gAgent.getID()))
  1032. {
  1033. remove_from_inventory = true;
  1034. }
  1035. // Check if it's in the trash. (again similar to the normal rez logic)
  1036. const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1037. if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id))
  1038. {
  1039. remove_from_inventory = true;
  1040. }
  1041. }
  1042. if(remove_from_inventory)
  1043. {
  1044. gInventory.deleteObject(itemp->getUUID());
  1045. gInventory.notifyObservers();
  1046. }
  1047. }
  1048. void LLItemBridge::gotoItem(LLFolderView *folder)
  1049. {
  1050. LLInventoryObject *obj = getInventoryObject();
  1051. if (obj && obj->getIsLinkType())
  1052. {
  1053. LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
  1054. if (active_panel)
  1055. {
  1056. active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO);
  1057. }
  1058. }
  1059. }
  1060. LLUIImagePtr LLItemBridge::getIcon() const
  1061. {
  1062. return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]);
  1063. }
  1064. PermissionMask LLItemBridge::getPermissionMask() const
  1065. {
  1066. LLViewerInventoryItem* item = getItem();
  1067. PermissionMask perm_mask = 0;
  1068. if(item)
  1069. {
  1070. BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
  1071. BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
  1072. BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
  1073. gAgent.getID());
  1074. if (copy) perm_mask |= PERM_COPY;
  1075. if (mod)  perm_mask |= PERM_MODIFY;
  1076. if (xfer) perm_mask |= PERM_TRANSFER;
  1077. }
  1078. return perm_mask;
  1079. }
  1080. const std::string& LLItemBridge::getDisplayName() const
  1081. {
  1082. if(mDisplayName.empty())
  1083. {
  1084. buildDisplayName(getItem(), mDisplayName);
  1085. }
  1086. return mDisplayName;
  1087. }
  1088. void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name)
  1089. {
  1090. if(item)
  1091. {
  1092. name.assign(item->getName());
  1093. }
  1094. else
  1095. {
  1096. name.assign(LLStringUtil::null);
  1097. }
  1098. }
  1099. LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
  1100. {
  1101. U8 font = LLFontGL::NORMAL;
  1102. if (get_is_item_worn(mUUID))
  1103. {
  1104. // llinfos << "BOLD" << llendl;
  1105. font |= LLFontGL::BOLD;
  1106. }
  1107. const LLViewerInventoryItem* item = getItem();
  1108. if (item && item->getIsLinkType())
  1109. {
  1110. font |= LLFontGL::ITALIC;
  1111. }
  1112. return (LLFontGL::StyleFlags)font;
  1113. }
  1114. std::string LLItemBridge::getLabelSuffix() const
  1115. {
  1116. // String table is loaded before login screen and inventory items are
  1117. // loaded after login, so LLTrans should be ready.
  1118. static std::string NO_COPY =LLTrans::getString("no_copy");
  1119. static std::string NO_MOD = LLTrans::getString("no_modify");
  1120. static std::string NO_XFER = LLTrans::getString("no_transfer");
  1121. static std::string LINK = LLTrans::getString("link");
  1122. static std::string BROKEN_LINK = LLTrans::getString("broken_link");
  1123. std::string suffix;
  1124. LLInventoryItem* item = getItem();
  1125. if(item)
  1126. {
  1127. // it's a bit confusing to put nocopy/nomod/etc on calling cards.
  1128. if(LLAssetType::AT_CALLINGCARD != item->getType()
  1129.    && item->getPermissions().getOwner() == gAgent.getID())
  1130. {
  1131. BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType());
  1132. if (broken_link) return BROKEN_LINK;
  1133. BOOL link = item->getIsLinkType();
  1134. if (link) return LINK;
  1135. BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
  1136. if (!copy)
  1137. {
  1138. suffix += NO_COPY;
  1139. }
  1140. BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
  1141. if (!mod)
  1142. {
  1143. suffix += NO_MOD;
  1144. }
  1145. BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
  1146. gAgent.getID());
  1147. if (!xfer)
  1148. {
  1149. suffix += NO_XFER;
  1150. }
  1151. }
  1152. }
  1153. return suffix;
  1154. }
  1155. time_t LLItemBridge::getCreationDate() const
  1156. {
  1157. LLViewerInventoryItem* item = getItem();
  1158. if (item)
  1159. {
  1160. return item->getCreationDate();
  1161. }
  1162. return 0;
  1163. }
  1164. BOOL LLItemBridge::isItemRenameable() const
  1165. {
  1166. LLViewerInventoryItem* item = getItem();
  1167. if(item)
  1168. {
  1169. // (For now) Don't allow calling card rename since that may confuse users as to
  1170. // what the calling card points to.
  1171. if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
  1172. {
  1173. return FALSE;
  1174. }
  1175. return (item->getPermissions().allowModifyBy(gAgent.getID()));
  1176. }
  1177. return FALSE;
  1178. }
  1179. BOOL LLItemBridge::renameItem(const std::string& new_name)
  1180. {
  1181. if(!isItemRenameable())
  1182. return FALSE;
  1183. LLPreview::dirty(mUUID);
  1184. LLInventoryModel* model = getInventoryModel();
  1185. if(!model)
  1186. return FALSE;
  1187. LLViewerInventoryItem* item = getItem();
  1188. if(item && (item->getName() != new_name))
  1189. {
  1190. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  1191. new_item->rename(new_name);
  1192. buildDisplayName(new_item, mDisplayName);
  1193. new_item->updateServer(FALSE);
  1194. model->updateItem(new_item);
  1195. model->notifyObservers();
  1196. }
  1197. // return FALSE because we either notified observers (& therefore
  1198. // rebuilt) or we didn't update.
  1199. return FALSE;
  1200. }
  1201. BOOL LLItemBridge::removeItem()
  1202. {
  1203. if(!isItemRemovable())
  1204. {
  1205. return FALSE;
  1206. }
  1207. // move it to the trash
  1208. LLPreview::hide(mUUID, TRUE);
  1209. LLInventoryModel* model = getInventoryModel();
  1210. if(!model) return FALSE;
  1211. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1212. LLViewerInventoryItem* item = getItem();
  1213. // if item is not already in trash
  1214. if(item && !model->isObjectDescendentOf(mUUID, trash_id))
  1215. {
  1216. // move to trash, and restamp
  1217. LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE);
  1218. // delete was successful
  1219. return TRUE;
  1220. }
  1221. else
  1222. {
  1223. // tried to delete already item in trash (should purge?)
  1224. return FALSE;
  1225. }
  1226. }
  1227. BOOL LLItemBridge::isItemCopyable() const
  1228. {
  1229. LLViewerInventoryItem* item = getItem();
  1230. if (item)
  1231. {
  1232. // Can't copy worn objects. DEV-15183
  1233. if(get_is_item_worn(mUUID))
  1234. {
  1235. return FALSE;
  1236. }
  1237. // You can never copy a link.
  1238. if (item->getIsLinkType())
  1239. {
  1240. return FALSE;
  1241. }
  1242. if (gAgent.isGodlike())
  1243. {
  1244. // All items can be copied in god mode since you can
  1245. // at least paste-as-link the item, though you 
  1246. // still may not be able paste the item.
  1247. return TRUE;
  1248. }
  1249. else
  1250. {
  1251. return (item->getPermissions().allowCopyBy(gAgent.getID()));
  1252. }
  1253. }
  1254. return FALSE;
  1255. }
  1256. BOOL LLItemBridge::copyToClipboard() const
  1257. {
  1258. if(isItemCopyable())
  1259. {
  1260. LLInventoryClipboard::instance().add(mUUID);
  1261. return TRUE;
  1262. }
  1263. return FALSE;
  1264. }
  1265. LLViewerInventoryItem* LLItemBridge::getItem() const
  1266. {
  1267. LLViewerInventoryItem* item = NULL;
  1268. LLInventoryModel* model = getInventoryModel();
  1269. if(model)
  1270. {
  1271. item = (LLViewerInventoryItem*)model->getItem(mUUID);
  1272. }
  1273. return item;
  1274. }
  1275. BOOL LLItemBridge::isItemPermissive() const
  1276. {
  1277. LLViewerInventoryItem* item = getItem();
  1278. if(item)
  1279. {
  1280. U32 mask = item->getPermissions().getMaskBase();
  1281. if((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
  1282. {
  1283. return TRUE;
  1284. }
  1285. }
  1286. return FALSE;
  1287. }
  1288. bool LLItemBridge::isAddAction(std::string action) const
  1289. {
  1290. return ("wear" == action || "attach" == action || "activate" == action);
  1291. }
  1292. bool LLItemBridge::isRemoveAction(std::string action) const
  1293. {
  1294. return ("take_off" == action || "detach" == action || "deactivate" == action);
  1295. }
  1296. // +=================================================+
  1297. // |        LLFolderBridge                           |
  1298. // +=================================================+
  1299. LLFolderBridge* LLFolderBridge::sSelf=NULL;
  1300. // Can be moved to another folder
  1301. BOOL LLFolderBridge::isItemMovable() const
  1302. {
  1303. LLInventoryObject* obj = getInventoryObject();
  1304. if(obj)
  1305. {
  1306. return (!LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType()));
  1307. }
  1308. return FALSE;
  1309. }
  1310. void LLFolderBridge::selectItem()
  1311. {
  1312. }
  1313. // Iterate through a folder's children to determine if
  1314. // all the children are removable.
  1315. class LLIsItemRemovable : public LLFolderViewFunctor
  1316. {
  1317. public:
  1318. LLIsItemRemovable() : mPassed(TRUE) {}
  1319. virtual void doFolder(LLFolderViewFolder* folder)
  1320. {
  1321. mPassed &= folder->getListener()->isItemRemovable();
  1322. }
  1323. virtual void doItem(LLFolderViewItem* item)
  1324. {
  1325. mPassed &= item->getListener()->isItemRemovable();
  1326. }
  1327. BOOL mPassed;
  1328. };
  1329. // Can be destroyed (or moved to trash)
  1330. BOOL LLFolderBridge::isItemRemovable() const
  1331. {
  1332. LLInventoryModel* model = getInventoryModel();
  1333. if(!model)
  1334. {
  1335. return FALSE;
  1336. }
  1337. if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()))
  1338. {
  1339. return FALSE;
  1340. }
  1341. LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
  1342. if( !avatar )
  1343. {
  1344. return FALSE;
  1345. }
  1346. LLInventoryCategory* category = model->getCategory(mUUID);
  1347. if( !category )
  1348. {
  1349. return FALSE;
  1350. }
  1351. if(LLFolderType::lookupIsProtectedType(category->getPreferredType()))
  1352. {
  1353. return FALSE;
  1354. }
  1355. LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get());
  1356. LLFolderViewFolder* folderp = dynamic_cast<LLFolderViewFolder*>(panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL);
  1357. if (folderp)
  1358. {
  1359. LLIsItemRemovable folder_test;
  1360. folderp->applyFunctorToChildren(folder_test);
  1361. if (!folder_test.mPassed)
  1362. {
  1363. return FALSE;
  1364. }
  1365. }
  1366. return TRUE;
  1367. }
  1368. BOOL LLFolderBridge::isUpToDate() const
  1369. {
  1370. LLInventoryModel* model = getInventoryModel();
  1371. if(!model) return FALSE;
  1372. LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
  1373. if( !category )
  1374. {
  1375. return FALSE;
  1376. }
  1377. return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;
  1378. }
  1379. BOOL LLFolderBridge::isItemCopyable() const
  1380. {
  1381. return FALSE;
  1382. }
  1383. BOOL LLFolderBridge::copyToClipboard() const
  1384. {
  1385. if(isItemCopyable())
  1386. {
  1387. LLInventoryClipboard::instance().add(mUUID);
  1388. return TRUE;
  1389. }
  1390. return FALSE;
  1391. }
  1392. BOOL LLFolderBridge::isClipboardPasteable() const
  1393. {
  1394. if ( ! LLInvFVBridge::isClipboardPasteable() )
  1395. return FALSE;
  1396. // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
  1397. if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) )
  1398. {
  1399. LLInventoryModel* model = getInventoryModel();
  1400. if ( !model )
  1401. {
  1402. return FALSE;
  1403. }
  1404. LLDynamicArray<LLUUID> objects;
  1405. LLInventoryClipboard::instance().retrieve(objects);
  1406. const LLViewerInventoryCategory *current_cat = getCategory();
  1407. // Search for the direct descendent of current Friends subfolder among all pasted items,
  1408. // and return false if is found.
  1409. for(S32 i = objects.count() - 1; i >= 0; --i)
  1410. {
  1411. const LLUUID &obj_id = objects.get(i);
  1412. if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
  1413. {
  1414. return FALSE;
  1415. }
  1416. }
  1417. }
  1418. return TRUE;
  1419. }
  1420. BOOL LLFolderBridge::isClipboardPasteableAsLink() const
  1421. {
  1422. // Check normal paste-as-link permissions
  1423. if (!LLInvFVBridge::isClipboardPasteableAsLink())
  1424. {
  1425. return FALSE;
  1426. }
  1427. const LLInventoryModel* model = getInventoryModel();
  1428. if (!model)
  1429. {
  1430. return FALSE;
  1431. }
  1432. const LLViewerInventoryCategory *current_cat = getCategory();
  1433. if (current_cat)
  1434. {
  1435. const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat );
  1436. const LLUUID &current_cat_id = current_cat->getUUID();
  1437. LLDynamicArray<LLUUID> objects;
  1438. LLInventoryClipboard::instance().retrieve(objects);
  1439. S32 count = objects.count();
  1440. for(S32 i = 0; i < count; i++)
  1441. {
  1442. const LLUUID &obj_id = objects.get(i);
  1443. const LLInventoryCategory *cat = model->getCategory(obj_id);
  1444. if (cat)
  1445. {
  1446. const LLUUID &cat_id = cat->getUUID();
  1447. // Don't allow recursive pasting
  1448. if ((cat_id == current_cat_id) ||
  1449. model->isObjectDescendentOf(current_cat_id, cat_id))
  1450. {
  1451. return FALSE;
  1452. }
  1453. }
  1454. // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
  1455. if ( is_in_friend_folder )
  1456. {
  1457. // If object is direct descendent of current Friends subfolder than return false.
  1458. // Note: We can't use 'const LLInventoryCategory *cat', because it may be null
  1459. // in case type of obj_id is LLInventoryItem.
  1460. if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
  1461. {
  1462. return FALSE;
  1463. }
  1464. }
  1465. }
  1466. }
  1467. return TRUE;
  1468. }
  1469. BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
  1470. BOOL drop)
  1471. {
  1472. // This should never happen, but if an inventory item is incorrectly parented,
  1473. // the UI will get confused and pass in a NULL.
  1474. if(!inv_cat) return FALSE;
  1475. LLInventoryModel* model = getInventoryModel();
  1476. if(!model) return FALSE;
  1477. LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
  1478. if(!avatar) return FALSE;
  1479. // cannot drag categories into library
  1480. if(!isAgentInventory())
  1481. {
  1482. return FALSE;
  1483. }
  1484. // check to make sure source is agent inventory, and is represented there.
  1485. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
  1486. BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL)
  1487. && (LLToolDragAndDrop::SOURCE_AGENT == source);
  1488. BOOL accept = FALSE;
  1489. S32 i;
  1490. LLInventoryModel::cat_array_t descendent_categories;
  1491. LLInventoryModel::item_array_t descendent_items;
  1492. if(is_agent_inventory)
  1493. {
  1494. const LLUUID& cat_id = inv_cat->getUUID();
  1495. // Is the destination the trash?
  1496. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  1497. BOOL move_is_into_trash = (mUUID == trash_id)
  1498. || model->isObjectDescendentOf(mUUID, trash_id);
  1499. BOOL is_movable = (!LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()));
  1500. const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
  1501. BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
  1502. BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
  1503. if (move_is_into_current_outfit || move_is_into_outfit)
  1504. {
  1505. // BAP - restrictions?
  1506. is_movable = true;
  1507. }
  1508. if (mUUID == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE))
  1509. {
  1510. is_movable = FALSE; // It's generally movable but not into Favorites folder. EXT-1604
  1511. }
  1512. if( is_movable )
  1513. {
  1514. gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE );
  1515. for( i = 0; i < descendent_categories.count(); i++ )
  1516. {
  1517. LLInventoryCategory* category = descendent_categories[i];
  1518. if(LLFolderType::lookupIsProtectedType(category->getPreferredType()))
  1519. {
  1520. // ...can't move "special folders" like Textures
  1521. is_movable = FALSE;
  1522. break;
  1523. }
  1524. }
  1525. if( is_movable )
  1526. {
  1527. if( move_is_into_trash )
  1528. {
  1529. for( i = 0; i < descendent_items.count(); i++ )
  1530. {
  1531. LLInventoryItem* item = descendent_items[i];
  1532. if (get_is_item_worn(item->getUUID()))
  1533. {
  1534. is_movable = FALSE;
  1535. break; // It's generally movable, but not into the trash!
  1536. }
  1537. }
  1538. }
  1539. }
  1540. }
  1541. accept = is_movable
  1542. && (mUUID != cat_id) // Can't move a folder into itself
  1543. && (mUUID != inv_cat->getParentUUID()) // Avoid moves that would change nothing
  1544. && !(model->isObjectDescendentOf(mUUID, cat_id)); // Avoid circularity
  1545. if(accept && drop)
  1546. {
  1547. // Look for any gestures and deactivate them
  1548. if (move_is_into_trash)
  1549. {
  1550. for (i = 0; i < descendent_items.count(); i++)
  1551. {
  1552. LLInventoryItem* item = descendent_items[i];
  1553. if (item->getType() == LLAssetType::AT_GESTURE
  1554. && LLGestureManager::instance().isGestureActive(item->getUUID()))
  1555. {
  1556. LLGestureManager::instance().deactivateGesture(item->getUUID());
  1557. }
  1558. }
  1559. }
  1560. // if target is an outfit or current outfit folder we use link
  1561. if (move_is_into_current_outfit || move_is_into_outfit)
  1562. {
  1563. if (inv_cat->getPreferredType() == LLFolderType::FT_NONE)
  1564. {
  1565. if (move_is_into_current_outfit)
  1566. {
  1567. // traverse category and add all contents to currently worn.
  1568. BOOL append = true;
  1569. LLAppearanceManager::instance().wearInventoryCategory(inv_cat, false, append);
  1570. }
  1571. else
  1572. {
  1573. // Recursively create links in target outfit.
  1574. LLInventoryModel::cat_array_t cats;
  1575. LLInventoryModel::item_array_t items;
  1576. gInventory.collectDescendents(inv_cat->getUUID(), cats, items, LLInventoryModel::EXCLUDE_TRASH);
  1577. LLAppearanceManager::instance().linkAll(mUUID,items,NULL);
  1578. }
  1579. }
  1580. else
  1581. {
  1582. #if SUPPORT_ENSEMBLES
  1583. // BAP - should skip if dup.
  1584. if (move_is_into_current_outfit)
  1585. {
  1586. LLAppearanceManager::instance().addEnsembleLink(inv_cat);
  1587. }
  1588. else
  1589. {
  1590. LLPointer<LLInventoryCallback> cb = NULL;
  1591. link_inventory_item(
  1592. gAgent.getID(),
  1593. inv_cat->getUUID(),
  1594. mUUID,
  1595. inv_cat->getName(),
  1596. LLAssetType::AT_LINK_FOLDER,
  1597. cb);
  1598. }
  1599. #endif
  1600. }
  1601. }
  1602. else
  1603. {
  1604. // Reparent the folder and restamp children if it's moving
  1605. // into trash.
  1606. LLInvFVBridge::changeCategoryParent(
  1607. model,
  1608. (LLViewerInventoryCategory*)inv_cat,
  1609. mUUID,
  1610. move_is_into_trash);
  1611. }
  1612. }
  1613. }
  1614. else if(LLToolDragAndDrop::SOURCE_WORLD == source)
  1615. {
  1616. // content category has same ID as object itself
  1617. LLUUID object_id = inv_cat->getUUID();
  1618. LLUUID category_id = mUUID;
  1619. accept = move_inv_category_world_to_agent(object_id, category_id, drop);
  1620. }
  1621. return accept;
  1622. }
  1623. void warn_move_inventory(LLViewerObject* object, LLMoveInv* move_inv)
  1624. {
  1625. const char* dialog = NULL;
  1626. if (object->flagScripted())
  1627. {
  1628. dialog = "MoveInventoryFromScriptedObject";
  1629. }
  1630. else
  1631. {
  1632. dialog = "MoveInventoryFromObject";
  1633. }
  1634. LLNotificationsUtil::add(dialog, LLSD(), LLSD(), boost::bind(move_task_inventory_callback, _1, _2, move_inv));
  1635. }
  1636. // Move/copy all inventory items from the Contents folder of an in-world
  1637. // object to the agent's inventory, inside a given category.
  1638. BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
  1639.   const LLUUID& category_id,
  1640.   BOOL drop,
  1641.   void (*callback)(S32, void*),
  1642.   void* user_data)
  1643. {
  1644. // Make sure the object exists. If we allowed dragging from
  1645. // anonymous objects, it would be possible to bypass
  1646. // permissions.
  1647. // content category has same ID as object itself
  1648. LLViewerObject* object = gObjectList.findObject(object_id);
  1649. if(!object)
  1650. {
  1651. llinfos << "Object not found for drop." << llendl;
  1652. return FALSE;
  1653. }
  1654. // this folder is coming from an object, as there is only one folder in an object, the root,
  1655. // we need to collect the entire contents and handle them as a group
  1656. InventoryObjectList inventory_objects;
  1657. object->getInventoryContents(inventory_objects);
  1658. if (inventory_objects.empty())
  1659. {
  1660. llinfos << "Object contents not found for drop." << llendl;
  1661. return FALSE;
  1662. }
  1663. BOOL accept = TRUE;
  1664. BOOL is_move = FALSE;
  1665. // coming from a task. Need to figure out if the person can
  1666. // move/copy this item.
  1667. InventoryObjectList::iterator it = inventory_objects.begin();
  1668. InventoryObjectList::iterator end = inventory_objects.end();
  1669. for ( ; it != end; ++it)
  1670. {
  1671. // coming from a task. Need to figure out if the person can
  1672. // move/copy this item.
  1673. LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions());
  1674. if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
  1675. && perm.allowTransferTo(gAgent.getID())))
  1676. // || gAgent.isGodlike())
  1677. {
  1678. accept = TRUE;
  1679. }
  1680. else if(object->permYouOwner())
  1681. {
  1682. // If the object cannot be copied, but the object the
  1683. // inventory is owned by the agent, then the item can be
  1684. // moved from the task to agent inventory.
  1685. is_move = TRUE;
  1686. accept = TRUE;
  1687. }
  1688. else
  1689. {
  1690. accept = FALSE;
  1691. break;
  1692. }
  1693. }
  1694. if(drop && accept)
  1695. {
  1696. it = inventory_objects.begin();
  1697. InventoryObjectList::iterator first_it = inventory_objects.begin();
  1698. LLMoveInv* move_inv = new LLMoveInv;
  1699. move_inv->mObjectID = object_id;
  1700. move_inv->mCategoryID = category_id;
  1701. move_inv->mCallback = callback;
  1702. move_inv->mUserData = user_data;
  1703. for ( ; it != end; ++it)
  1704. {
  1705. two_uuids_t two(category_id, (*it)->getUUID());
  1706. move_inv->mMoveList.push_back(two);
  1707. }
  1708. if(is_move)
  1709. {
  1710. // Callback called from within here.
  1711. warn_move_inventory(object, move_inv);
  1712. }
  1713. else
  1714. {
  1715. LLNotification::Params params("MoveInventoryFromObject");
  1716. params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv));
  1717. LLNotifications::instance().forceResponse(params, 0);
  1718. }
  1719. }
  1720. return accept;
  1721. }
  1722. bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat,
  1723.  LLInventoryItem* item)
  1724. {
  1725. // Valid COF items are:
  1726. // - links to wearables (body parts or clothing)
  1727. // - links to attachments
  1728. // - links to gestures
  1729. // - links to ensemble folders
  1730. LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); // BAP - safe?
  1731. if (linked_item)
  1732. {
  1733. LLAssetType::EType type = linked_item->getType();
  1734. return (type == LLAssetType::AT_CLOTHING ||
  1735. type == LLAssetType::AT_BODYPART ||
  1736. type == LLAssetType::AT_GESTURE ||
  1737. type == LLAssetType::AT_OBJECT);
  1738. }
  1739. else
  1740. {
  1741. LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); // BAP - safe?
  1742. // BAP remove AT_NONE support after ensembles are fully working?
  1743. return (linked_category &&
  1744. ((linked_category->getPreferredType() == LLFolderType::FT_NONE) ||
  1745.  (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType()))));
  1746. }
  1747. }
  1748. bool LLFindWearables::operator()(LLInventoryCategory* cat,
  1749.  LLInventoryItem* item)
  1750. {
  1751. if(item)
  1752. {
  1753. if((item->getType() == LLAssetType::AT_CLOTHING)
  1754.    || (item->getType() == LLAssetType::AT_BODYPART))
  1755. {
  1756. return TRUE;
  1757. }
  1758. }
  1759. return FALSE;
  1760. }
  1761. //Used by LLFolderBridge as callback for directory recursion.
  1762. class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver
  1763. {
  1764. public:
  1765. LLRightClickInventoryFetchObserver() :
  1766. mCopyItems(false)
  1767. { };
  1768. LLRightClickInventoryFetchObserver(const LLUUID& cat_id, bool copy_items) :
  1769. mCatID(cat_id),
  1770. mCopyItems(copy_items)
  1771. { };
  1772. virtual void done()
  1773. {
  1774. // we've downloaded all the items, so repaint the dialog
  1775. LLFolderBridge::staticFolderOptionsMenu();
  1776. gInventory.removeObserver(this);
  1777. delete this;
  1778. }
  1779. protected:
  1780. LLUUID mCatID;
  1781. bool mCopyItems;
  1782. };
  1783. //Used by LLFolderBridge as callback for directory recursion.
  1784. class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
  1785. {
  1786. public:
  1787. LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {}
  1788. ~LLRightClickInventoryFetchDescendentsObserver() {}
  1789. virtual void done();
  1790. protected:
  1791. bool mCopyItems;
  1792. };
  1793. void LLRightClickInventoryFetchDescendentsObserver::done()
  1794. {
  1795. // Avoid passing a NULL-ref as mCompleteFolders.front() down to
  1796. // gInventory.collectDescendents()
  1797. if( mCompleteFolders.empty() )
  1798. {
  1799. llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl;
  1800. dec_busy_count();
  1801. gInventory.removeObserver(this);
  1802. delete this;
  1803. return;
  1804. }
  1805. // What we do here is get the complete information on the items in
  1806. // the library, and set up an observer that will wait for that to
  1807. // happen.
  1808. LLInventoryModel::cat_array_t cat_array;
  1809. LLInventoryModel::item_array_t item_array;
  1810. gInventory.collectDescendents(mCompleteFolders.front(),
  1811.   cat_array,
  1812.   item_array,
  1813.   LLInventoryModel::EXCLUDE_TRASH);
  1814. S32 count = item_array.count();
  1815. #if 0 // HACK/TODO: Why?
  1816. // This early causes a giant menu to get produced, and doesn't seem to be needed.
  1817. if(!count)
  1818. {
  1819. llwarns << "Nothing fetched in category " << mCompleteFolders.front()
  1820. << llendl;
  1821. dec_busy_count();
  1822. gInventory.removeObserver(this);
  1823. delete this;
  1824. return;
  1825. }
  1826. #endif
  1827. LLRightClickInventoryFetchObserver* outfit;
  1828. outfit = new LLRightClickInventoryFetchObserver(mCompleteFolders.front(), mCopyItems);
  1829. LLInventoryFetchObserver::item_ref_t ids;
  1830. for(S32 i = 0; i < count; ++i)
  1831. {
  1832. ids.push_back(item_array.get(i)->getUUID());
  1833. }
  1834. // clean up, and remove this as an observer since the call to the
  1835. // outfit could notify observers and throw us into an infinite
  1836. // loop.
  1837. dec_busy_count();
  1838. gInventory.removeObserver(this);
  1839. delete this;
  1840. // increment busy count and either tell the inventory to check &
  1841. // call done, or add this object to the inventory for observation.
  1842. inc_busy_count();
  1843. // do the fetch
  1844. outfit->fetchItems(ids);
  1845. outfit->done(); //Not interested in waiting and this will be right 99% of the time.
  1846. //Uncomment the following code for laggy Inventory UI.
  1847. /* if(outfit->isEverythingComplete())
  1848. {
  1849. // everything is already here - call done.
  1850. outfit->done();
  1851. }
  1852. else
  1853. {
  1854. // it's all on it's way - add an observer, and the inventory
  1855. // will call done for us when everything is here.
  1856. gInventory.addObserver(outfit);
  1857. }*/
  1858. }
  1859. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1860. // Class LLInventoryWearObserver
  1861. //
  1862. // Observer for "copy and wear" operation to support knowing
  1863. // when the all of the contents have been added to inventory.
  1864. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1865. class LLInventoryCopyAndWearObserver : public LLInventoryObserver
  1866. {
  1867. public:
  1868. LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count) :mCatID(cat_id), mContentsCount(count), mFolderAdded(FALSE) {}
  1869. virtual ~LLInventoryCopyAndWearObserver() {}
  1870. virtual void changed(U32 mask);
  1871. protected:
  1872. LLUUID mCatID;
  1873. int    mContentsCount;
  1874. BOOL   mFolderAdded;
  1875. };
  1876. void LLInventoryCopyAndWearObserver::changed(U32 mask)
  1877. {
  1878. if((mask & (LLInventoryObserver::ADD)) != 0)
  1879. {
  1880. if (!mFolderAdded)
  1881. {
  1882. const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
  1883. std::set<LLUUID>::const_iterator id_it = changed_items.begin();
  1884. std::set<LLUUID>::const_iterator id_end = changed_items.end();
  1885. for (;id_it != id_end; ++id_it)
  1886. {
  1887. if ((*id_it) == mCatID)
  1888. {
  1889. mFolderAdded = TRUE;
  1890. break;
  1891. }
  1892. }
  1893. }
  1894. if (mFolderAdded)
  1895. {
  1896. LLViewerInventoryCategory* category = gInventory.getCategory(mCatID);
  1897. if (NULL == category)
  1898. {
  1899. llwarns << "gInventory.getCategory(" << mCatID
  1900. << ") was NULL" << llendl;
  1901. }
  1902. else
  1903. {
  1904. if (category->getDescendentCount() ==
  1905.     mContentsCount)
  1906. {
  1907. gInventory.removeObserver(this);
  1908. LLAppearanceManager::instance().wearInventoryCategory(category, FALSE, TRUE);
  1909. delete this;
  1910. }
  1911. }
  1912. }
  1913. }
  1914. }
  1915. void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action)
  1916. {
  1917. if ("open" == action)
  1918. {
  1919. LLFolderViewFolder *f = dynamic_cast<LLFolderViewFolder *>(folder->getItemByID(mUUID));
  1920. if (f)
  1921. {
  1922. f->setOpen(TRUE);
  1923. }
  1924. return;
  1925. }
  1926. else if ("paste" == action)
  1927. {
  1928. pasteFromClipboard();
  1929. return;
  1930. }
  1931. else if ("paste_link" == action)
  1932. {
  1933. pasteLinkFromClipboard();
  1934. return;
  1935. }
  1936. else if ("properties" == action)
  1937. {
  1938. showProperties();
  1939. return;
  1940. }
  1941. else if ("replaceoutfit" == action)
  1942. {
  1943. modifyOutfit(FALSE);
  1944. return;
  1945. }
  1946. #if SUPPORT_ENSEMBLES
  1947. else if ("wearasensemble" == action)
  1948. {
  1949. LLInventoryModel* model = getInventoryModel();
  1950. if(!model) return;
  1951. LLViewerInventoryCategory* cat = getCategory();
  1952. if(!cat) return;
  1953. LLAppearanceManager::instance().addEnsembleLink(cat,true);
  1954. return;
  1955. }
  1956. #endif
  1957. else if ("addtooutfit" == action)
  1958. {
  1959. modifyOutfit(TRUE);
  1960. return;
  1961. }
  1962. else if ("copy" == action)
  1963. {
  1964. copyToClipboard();
  1965. return;
  1966. }
  1967. else if ("removefromoutfit" == action)
  1968. {
  1969. LLInventoryModel* model = getInventoryModel();
  1970. if(!model) return;
  1971. LLViewerInventoryCategory* cat = getCategory();
  1972. if(!cat) return;
  1973. remove_inventory_category_from_avatar ( cat );
  1974. return;
  1975. }
  1976. else if ("purge" == action)
  1977. {
  1978. purgeItem(model, mUUID);
  1979. return;
  1980. }
  1981. else if ("restore" == action)
  1982. {
  1983. restoreItem();
  1984. return;
  1985. }
  1986. #ifndef LL_RELEASE_FOR_DOWNLOAD
  1987. else if ("delete_system_folder" == action)
  1988. {
  1989. removeSystemFolder();
  1990. }
  1991. #endif
  1992. }
  1993. void LLFolderBridge::openItem()
  1994. {
  1995. lldebugs << "LLFolderBridge::openItem()" << llendl;
  1996. LLInventoryModel* model = getInventoryModel();
  1997. if(!model) return;
  1998. if(mUUID.isNull()) return;
  1999. bool fetching_inventory = model->fetchDescendentsOf(mUUID);
  2000. // Only change folder type if we have the folder contents.
  2001. if (!fetching_inventory)
  2002. {
  2003. // Disabling this for now, it's causing crash when new items are added to folders
  2004. // since folder type may change before new item item has finished processing.
  2005. // determineFolderType();
  2006. }
  2007. }
  2008. void LLFolderBridge::closeItem()
  2009. {
  2010. determineFolderType();
  2011. }
  2012. void LLFolderBridge::determineFolderType()
  2013. {
  2014. if (isUpToDate())
  2015. {
  2016. LLInventoryModel* model = getInventoryModel();
  2017. LLViewerInventoryCategory* category = model->getCategory(mUUID);
  2018. if (category)
  2019. {
  2020. category->determineFolderType();
  2021. }
  2022. }
  2023. }
  2024. BOOL LLFolderBridge::isItemRenameable() const
  2025. {
  2026. LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory();
  2027. if(cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType())
  2028.    && (cat->getOwnerID() == gAgent.getID()))
  2029. {
  2030. return TRUE;
  2031. }
  2032. return FALSE;
  2033. }
  2034. void LLFolderBridge::restoreItem()
  2035. {
  2036. LLViewerInventoryCategory* cat;
  2037. cat = (LLViewerInventoryCategory*)getCategory();
  2038. if(cat)
  2039. {
  2040. LLInventoryModel* model = getInventoryModel();
  2041. const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType()));
  2042. // do not restamp children on restore
  2043. LLInvFVBridge::changeCategoryParent(model, cat, new_parent, FALSE);
  2044. }
  2045. }
  2046. LLFolderType::EType LLFolderBridge::getPreferredType() const
  2047. {
  2048. LLFolderType::EType preferred_type = LLFolderType::FT_NONE;
  2049. LLViewerInventoryCategory* cat = getCategory();
  2050. if(cat)
  2051. {
  2052. preferred_type = cat->getPreferredType();
  2053. }
  2054. return preferred_type;
  2055. }
  2056. // Icons for folders are based on the preferred type
  2057. LLUIImagePtr LLFolderBridge::getIcon() const
  2058. {
  2059. LLFolderType::EType preferred_type = LLFolderType::FT_NONE;
  2060. LLViewerInventoryCategory* cat = getCategory();
  2061. if(cat)
  2062. {
  2063. preferred_type = cat->getPreferredType();
  2064. }
  2065. return getIcon(preferred_type);
  2066. }
  2067. LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type)
  2068. {
  2069. // we only have one folder image now
  2070. if (preferred_type == LLFolderType::FT_OUTFIT)
  2071. {
  2072. return LLUI::getUIImage("Inv_LookFolderClosed");
  2073. }
  2074. return LLUI::getUIImage("Inv_FolderClosed");
  2075. }
  2076. LLUIImagePtr LLFolderBridge::getOpenIcon() const
  2077. {
  2078. if (getPreferredType() == LLFolderType::FT_OUTFIT)
  2079. {
  2080. return LLUI::getUIImage("Inv_LookFolderOpen");
  2081. }
  2082. return LLUI::getUIImage("Inv_FolderOpen");
  2083. }
  2084. BOOL LLFolderBridge::renameItem(const std::string& new_name)
  2085. {
  2086. if(!isItemRenameable())
  2087. return FALSE;
  2088. LLInventoryModel* model = getInventoryModel();
  2089. if(!model)
  2090. return FALSE;
  2091. LLViewerInventoryCategory* cat = getCategory();
  2092. if(cat && (cat->getName() != new_name))
  2093. {
  2094. LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
  2095. new_cat->rename(new_name);
  2096. new_cat->updateServer(FALSE);
  2097. model->updateCategory(new_cat);
  2098. model->notifyObservers();
  2099. }
  2100. // return FALSE because we either notified observers (& therefore
  2101. // rebuilt) or we didn't update.
  2102. return FALSE;
  2103. }
  2104. BOOL LLFolderBridge::removeItem()
  2105. {
  2106. if(!isItemRemovable())
  2107. {
  2108. return FALSE;
  2109. }
  2110. const LLViewerInventoryCategory *cat = getCategory();
  2111. LLSD payload;
  2112. LLSD args;
  2113. args["FOLDERNAME"] = cat->getName();
  2114. LLNotification::Params params("ConfirmDeleteProtectedCategory");
  2115. params.payload(payload).substitutions(args).functor.function(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2));
  2116. LLNotifications::instance().forceResponse(params, 0);
  2117. return TRUE;
  2118. }
  2119. BOOL LLFolderBridge::removeSystemFolder()
  2120. {
  2121. const LLViewerInventoryCategory *cat = getCategory();
  2122. if (!LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
  2123. {
  2124. return FALSE;
  2125. }
  2126. LLSD payload;
  2127. LLSD args;
  2128. args["FOLDERNAME"] = cat->getName();
  2129. LLNotification::Params params("ConfirmDeleteProtectedCategory");
  2130. params.payload(payload).substitutions(args).functor.function(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2));
  2131. {
  2132. LLNotifications::instance().add(params);
  2133. }
  2134. return TRUE;
  2135. }
  2136. bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& response)
  2137. {
  2138. S32 option = LLNotification::getSelectedOption(notification, response);
  2139. // if they choose delete, do it.  Otherwise, don't do anything
  2140. if(option == 0) 
  2141. {
  2142. // move it to the trash
  2143. LLPreview::hide(mUUID);
  2144. LLInventoryModel* model = getInventoryModel();
  2145. if(!model) return FALSE;
  2146. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  2147. // Look for any gestures and deactivate them
  2148. LLInventoryModel::cat_array_t descendent_categories;
  2149. LLInventoryModel::item_array_t descendent_items;
  2150. gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE );
  2151. for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin();
  2152.  iter != descendent_items.end();
  2153.  ++iter)
  2154. {
  2155. const LLViewerInventoryItem* item = (*iter);
  2156. const LLUUID& item_id = item->getUUID();
  2157. if (item->getType() == LLAssetType::AT_GESTURE
  2158. && LLGestureManager::instance().isGestureActive(item_id))
  2159. {
  2160. LLGestureManager::instance().deactivateGesture(item_id);
  2161. }
  2162. }
  2163. // go ahead and do the normal remove if no 'last calling
  2164. // cards' are being removed.
  2165. LLViewerInventoryCategory* cat = getCategory();
  2166. if(cat)
  2167. {
  2168. LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE);
  2169. }
  2170. return TRUE;
  2171. }
  2172. return FALSE;
  2173. }
  2174. void LLFolderBridge::pasteFromClipboard()
  2175. {
  2176. LLInventoryModel* model = getInventoryModel();
  2177. if(model && isClipboardPasteable())
  2178. {
  2179. const LLUUID parent_id(mUUID);
  2180. LLDynamicArray<LLUUID> objects;
  2181. LLInventoryClipboard::instance().retrieve(objects);
  2182. for (LLDynamicArray<LLUUID>::const_iterator iter = objects.begin();
  2183.  iter != objects.end();
  2184.  ++iter)
  2185. {
  2186. const LLUUID& item_id = (*iter);
  2187. LLInventoryItem *item = model->getItem(item_id);
  2188. if (item)
  2189. {
  2190. if(LLInventoryClipboard::instance().isCutMode())
  2191. {
  2192. // move_inventory_item() is not enough,
  2193. //we have to update inventory locally too
  2194. LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item);
  2195. llassert(viitem);
  2196. if (viitem)
  2197. {
  2198. changeItemParent(model, viitem, parent_id, FALSE);
  2199. }
  2200. }
  2201. else
  2202. {
  2203. copy_inventory_item(
  2204. gAgent.getID(),
  2205. item->getPermissions().getOwner(),
  2206. item->getUUID(),
  2207. parent_id,
  2208. std::string(),
  2209. LLPointer<LLInventoryCallback>(NULL));
  2210. }
  2211. }
  2212. }
  2213. }
  2214. }
  2215. void LLFolderBridge::pasteLinkFromClipboard()
  2216. {
  2217. const LLInventoryModel* model = getInventoryModel();
  2218. if(model)
  2219. {
  2220. const LLUUID parent_id(mUUID);
  2221. LLDynamicArray<LLUUID> objects;
  2222. LLInventoryClipboard::instance().retrieve(objects);
  2223. for (LLDynamicArray<LLUUID>::const_iterator iter = objects.begin();
  2224.  iter != objects.end();
  2225.  ++iter)
  2226. {
  2227. const LLUUID &object_id = (*iter);
  2228. #if SUPPORT_ENSEMBLES
  2229. if (LLInventoryCategory *cat = model->getCategory(object_id))
  2230. {
  2231. link_inventory_item(
  2232. gAgent.getID(),
  2233. cat->getUUID(),
  2234. parent_id,
  2235. cat->getName(),
  2236. LLAssetType::AT_LINK_FOLDER,
  2237. LLPointer<LLInventoryCallback>(NULL));
  2238. }
  2239. else
  2240. #endif
  2241. if (LLInventoryItem *item = model->getItem(object_id))
  2242. {
  2243. link_inventory_item(
  2244. gAgent.getID(),
  2245. item->getLinkedUUID(),
  2246. parent_id,
  2247. item->getName(),
  2248. LLAssetType::AT_LINK,
  2249. LLPointer<LLInventoryCallback>(NULL));
  2250. }
  2251. }
  2252. }
  2253. }
  2254. void LLFolderBridge::staticFolderOptionsMenu()
  2255. {
  2256. if (!sSelf) return;
  2257. sSelf->folderOptionsMenu();
  2258. }
  2259. void LLFolderBridge::folderOptionsMenu()
  2260. {
  2261. menuentry_vec_t disabled_items;
  2262. LLInventoryModel* model = getInventoryModel();
  2263. if(!model) return;
  2264. const LLInventoryCategory* category = model->getCategory(mUUID);
  2265. if(!category) return;
  2266. LLFolderType::EType type = category->getPreferredType();
  2267. const bool is_system_folder = LLFolderType::lookupIsProtectedType(type);
  2268. // BAP change once we're no longer treating regular categories as ensembles.
  2269. const bool is_ensemble = (type == LLFolderType::FT_NONE ||
  2270.   LLFolderType::lookupIsEnsembleType(type));
  2271. // calling card related functionality for folders.
  2272. const bool is_sidepanel = isInOutfitsSidePanel();
  2273. if (is_sidepanel)
  2274. {
  2275. mItems.push_back("Rename");
  2276. addDeleteContextMenuOptions(mItems, disabled_items);
  2277. }
  2278. // Only enable calling-card related options for non-system folders.
  2279. if (!is_sidepanel && !is_system_folder)
  2280. {
  2281. LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
  2282. if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard))
  2283. {
  2284. mItems.push_back(std::string("Calling Card Separator"));
  2285. mItems.push_back(std::string("Conference Chat Folder"));
  2286. mItems.push_back(std::string("IM All Contacts In Folder"));
  2287. }
  2288. }
  2289. #ifndef LL_RELEASE_FOR_DOWNLOAD
  2290. if (LLFolderType::lookupIsProtectedType(type))
  2291. {
  2292. mItems.push_back(std::string("Delete System Folder"));
  2293. }
  2294. #endif
  2295. // wearables related functionality for folders.
  2296. //is_wearable
  2297. LLFindWearables is_wearable;
  2298. LLIsType is_object( LLAssetType::AT_OBJECT );
  2299. LLIsType is_gesture( LLAssetType::AT_GESTURE );
  2300. if (mWearables ||
  2301. checkFolderForContentsOfType(model, is_wearable)  ||
  2302. checkFolderForContentsOfType(model, is_object) ||
  2303. checkFolderForContentsOfType(model, is_gesture) )
  2304. {
  2305. if (!is_sidepanel)
  2306. {
  2307. mItems.push_back(std::string("Folder Wearables Separator"));
  2308. }
  2309. // Only enable add/replace outfit for non-system folders.
  2310. if (!is_system_folder)
  2311. {
  2312. // Adding an outfit onto another (versus replacing) doesn't make sense.
  2313. if (type != LLFolderType::FT_OUTFIT)
  2314. {
  2315. mItems.push_back(std::string("Add To Outfit"));
  2316. }
  2317. mItems.push_back(std::string("Replace Outfit"));
  2318. }
  2319. if (is_ensemble)
  2320. {
  2321. mItems.push_back(std::string("Wear As Ensemble"));
  2322. }
  2323. mItems.push_back(std::string("Remove From Outfit"));
  2324. if (!areAnyContentsWorn(model))
  2325. {
  2326. disabled_items.push_back(std::string("Remove From Outfit"));
  2327. }
  2328. mItems.push_back(std::string("Outfit Separator"));
  2329. }
  2330. hide_context_entries(*mMenu, mItems, disabled_items);
  2331. // Reposition the menu, in case we're adding items to an existing menu.
  2332. mMenu->needsArrange();
  2333. mMenu->arrangeAndClear();
  2334. }
  2335. BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type)
  2336. {
  2337. LLInventoryModel::cat_array_t cat_array;
  2338. LLInventoryModel::item_array_t item_array;
  2339. model->collectDescendentsIf(mUUID,
  2340. cat_array,
  2341. item_array,
  2342. LLInventoryModel::EXCLUDE_TRASH,
  2343. is_type);
  2344. return ((item_array.count() > 0) ? TRUE : FALSE );
  2345. }
  2346. class LLFindWorn : public LLInventoryCollectFunctor
  2347. {
  2348. public:
  2349. LLFindWorn() {}
  2350. virtual ~LLFindWorn() {}
  2351. virtual bool operator()(LLInventoryCategory* cat,
  2352. LLInventoryItem* item)
  2353. {
  2354. if (item && get_is_item_worn(item->getUUID()))
  2355. {
  2356. return TRUE;
  2357. }
  2358. return FALSE;
  2359. }
  2360. };
  2361. BOOL LLFolderBridge::areAnyContentsWorn(LLInventoryModel* model) const
  2362. {
  2363. LLInventoryModel::cat_array_t cat_array;
  2364. LLInventoryModel::item_array_t item_array;
  2365. LLFindWorn is_worn;
  2366. model->collectDescendentsIf(mUUID,
  2367. cat_array,
  2368. item_array,
  2369. LLInventoryModel::EXCLUDE_TRASH,
  2370. is_worn);
  2371. return (item_array.size() > 0);
  2372. }
  2373. // Flags unused
  2374. void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
  2375. {
  2376. mItems.clear();
  2377. mDisabledItems.clear();
  2378. lldebugs << "LLFolderBridge::buildContextMenu()" << llendl;
  2379. // menuentry_vec_t disabled_items;
  2380. LLInventoryModel* model = getInventoryModel();
  2381. if(!model) return;
  2382. const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
  2383. const LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
  2384. if (lost_and_found_id == mUUID)
  2385.   {
  2386. // This is the lost+found folder.
  2387.   mItems.push_back(std::string("Empty Lost And Found"));
  2388.   }
  2389. if(trash_id == mUUID)
  2390. {
  2391. // This is the trash.
  2392. mItems.push_back(std::string("Empty Trash"));
  2393. }
  2394. else if(isItemInTrash())
  2395. {
  2396. // This is a folder in the trash.
  2397. mItems.clear(); // clear any items that used to exist
  2398. addTrashContextMenuOptions(mItems, mDisabledItems);
  2399. }
  2400. else if(isAgentInventory()) // do not allow creating in library
  2401. {
  2402. LLViewerInventoryCategory *cat =  getCategory();
  2403. // BAP removed protected check to re-enable standard ops in untyped folders.
  2404. // Not sure what the right thing is to do here.
  2405. if (!isCOFFolder() && cat && cat->getPreferredType()!=LLFolderType::FT_OUTFIT /*&&
  2406. LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType())*/)
  2407. {
  2408. // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694.
  2409. if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat))
  2410. mItems.push_back(std::string("New Folder"));
  2411. mItems.push_back(std::string("New Script"));
  2412. mItems.push_back(std::string("New Note"));
  2413. mItems.push_back(std::string("New Gesture"));
  2414. mItems.push_back(std::string("New Clothes"));
  2415. mItems.push_back(std::string("New Body Parts"));
  2416. // Changing folder types is just a debug feature; this is fairly unsupported
  2417. // and can lead to unexpected behavior if enabled.
  2418. #if !LL_RELEASE_FOR_DOWNLOAD
  2419. mItems.push_back(std::string("Change Type"));
  2420. const LLViewerInventoryCategory *cat = getCategory();
  2421. if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
  2422. {
  2423. mDisabledItems.push_back(std::string("Change Type"));
  2424. }
  2425. #endif
  2426. getClipboardEntries(false, mItems, mDisabledItems, flags);
  2427. }
  2428. else
  2429. {
  2430. // Want some but not all of the items from getClipboardEntries for outfits.
  2431. if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
  2432. {
  2433. mItems.push_back(std::string("Rename"));
  2434. addDeleteContextMenuOptions(mItems, mDisabledItems);
  2435. // EXT-4030: disallow deletion of currently worn outfit
  2436. const LLViewerInventoryItem *base_outfit_link = LLAppearanceManager::instance().getBaseOutfitLink();
  2437. if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory()))
  2438. {
  2439. mDisabledItems.push_back(std::string("Delete"));
  2440. }
  2441. }
  2442. }
  2443. //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06
  2444. mCallingCards = mWearables = FALSE;
  2445. LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
  2446. if (checkFolderForContentsOfType(model, is_callingcard))
  2447. {
  2448. mCallingCards=TRUE;