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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llappearancemgr.cpp
  3.  * @brief Manager for initiating appearance changes on the viewer
  4.  *
  5.  * $LicenseInfo:firstyear=2004&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2004-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 "llagent.h"
  34. #include "llagentwearables.h"
  35. #include "llappearancemgr.h"
  36. #include "llcommandhandler.h"
  37. #include "llfloatercustomize.h"
  38. #include "llgesturemgr.h"
  39. #include "llinventorybridge.h"
  40. #include "llinventoryobserver.h"
  41. #include "llnotificationsutil.h"
  42. #include "llsidepanelappearance.h"
  43. #include "llsidetray.h"
  44. #include "llvoavatar.h"
  45. #include "llvoavatarself.h"
  46. #include "llviewerregion.h"
  47. #include "llwearablelist.h"
  48. LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name)
  49. {
  50. LLInventoryModel::cat_array_t cat_array;
  51. LLInventoryModel::item_array_t item_array;
  52. LLNameCategoryCollector has_name(name);
  53. gInventory.collectDescendentsIf(parent_id,
  54. cat_array,
  55. item_array,
  56. LLInventoryModel::EXCLUDE_TRASH,
  57. has_name);
  58. if (0 == cat_array.count())
  59. return LLUUID();
  60. else
  61. {
  62. LLViewerInventoryCategory *cat = cat_array.get(0);
  63. if (cat)
  64. return cat->getUUID();
  65. else
  66. {
  67. llwarns << "null cat" << llendl;
  68. return LLUUID();
  69. }
  70. }
  71. }
  72. // support for secondlife:///app/appearance SLapps
  73. class LLAppearanceHandler : public LLCommandHandler
  74. {
  75. public:
  76. // requests will be throttled from a non-trusted browser
  77. LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {}
  78. bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
  79. {
  80. // support secondlife:///app/appearance/show, but for now we just
  81. // make all secondlife:///app/appearance SLapps behave this way
  82. LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD());
  83. return true;
  84. }
  85. };
  86. LLAppearanceHandler gAppearanceHandler;
  87. class LLWearInventoryCategoryCallback : public LLInventoryCallback
  88. {
  89. public:
  90. LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append)
  91. {
  92. mCatID = cat_id;
  93. mAppend = append;
  94. }
  95. void fire(const LLUUID& item_id)
  96. {
  97. /*
  98.  * Do nothing.  We only care about the destructor
  99.  *
  100.  * The reason for this is that this callback is used in a hack where the
  101.  * same callback is given to dozens of items, and the destructor is called
  102.  * after the last item has fired the event and dereferenced it -- if all
  103.  * the events actually fire!
  104.  */
  105. }
  106. protected:
  107. ~LLWearInventoryCategoryCallback()
  108. {
  109. llinfos << "done all inventory callbacks" << llendl;
  110. // Is the destructor called by ordinary dereference, or because the app's shutting down?
  111. // If the inventory callback manager goes away, we're shutting down, no longer want the callback.
  112. if( LLInventoryCallbackManager::is_instantiated() )
  113. {
  114. LLAppearanceManager::instance().wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
  115. }
  116. else
  117. {
  118. llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl;
  119. }
  120. }
  121. private:
  122. LLUUID mCatID;
  123. bool mAppend;
  124. };
  125. class LLOutfitObserver : public LLInventoryFetchObserver
  126. {
  127. public:
  128. LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) :
  129. mCatID(cat_id),
  130. mCopyItems(copy_items),
  131. mAppend(append)
  132. {}
  133. ~LLOutfitObserver() {}
  134. virtual void done();
  135. void doWearCategory();
  136. protected:
  137. LLUUID mCatID;
  138. bool mCopyItems;
  139. bool mAppend;
  140. };
  141. void LLOutfitObserver::done()
  142. {
  143. llinfos << "done 2nd stage fetch" << llendl;
  144. gInventory.removeObserver(this);
  145. doOnIdle(boost::bind(&LLOutfitObserver::doWearCategory,this));
  146. }
  147. void LLOutfitObserver::doWearCategory()
  148. {
  149. llinfos << "starting" << llendl;
  150. // We now have an outfit ready to be copied to agent inventory. Do
  151. // it, and wear that outfit normally.
  152. if(mCopyItems)
  153. {
  154. LLInventoryCategory* cat = gInventory.getCategory(mCatID);
  155. std::string name;
  156. if(!cat)
  157. {
  158. // should never happen.
  159. name = "New Outfit";
  160. }
  161. else
  162. {
  163. name = cat->getName();
  164. }
  165. LLViewerInventoryItem* item = NULL;
  166. item_ref_t::iterator it = mComplete.begin();
  167. item_ref_t::iterator end = mComplete.end();
  168. LLUUID pid;
  169. for(; it < end; ++it)
  170. {
  171. item = (LLViewerInventoryItem*)gInventory.getItem(*it);
  172. if(item)
  173. {
  174. if(LLInventoryType::IT_GESTURE == item->getInventoryType())
  175. {
  176. pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
  177. }
  178. else
  179. {
  180. pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
  181. }
  182. break;
  183. }
  184. }
  185. if(pid.isNull())
  186. {
  187. pid = gInventory.getRootFolderID();
  188. }
  189. LLUUID cat_id = gInventory.createNewCategory(
  190. pid,
  191. LLFolderType::FT_NONE,
  192. name);
  193. mCatID = cat_id;
  194. LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(mCatID, mAppend);
  195. it = mComplete.begin();
  196. for(; it < end; ++it)
  197. {
  198. item = (LLViewerInventoryItem*)gInventory.getItem(*it);
  199. if(item)
  200. {
  201. copy_inventory_item(
  202. gAgent.getID(),
  203. item->getPermissions().getOwner(),
  204. item->getUUID(),
  205. cat_id,
  206. std::string(),
  207. cb);
  208. }
  209. }
  210. // BAP fixes a lag in display of created dir.
  211. gInventory.notifyObservers();
  212. }
  213. else
  214. {
  215. // Wear the inventory category.
  216. LLAppearanceManager::instance().wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
  217. }
  218. delete this;
  219. }
  220. class LLOutfitFetch : public LLInventoryFetchDescendentsObserver
  221. {
  222. public:
  223. LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {}
  224. ~LLOutfitFetch() {}
  225. virtual void done();
  226. protected:
  227. bool mCopyItems;
  228. bool mAppend;
  229. };
  230. void LLOutfitFetch::done()
  231. {
  232. // What we do here is get the complete information on the items in
  233. // the library, and set up an observer that will wait for that to
  234. // happen.
  235. llinfos << "done first stage fetch" << llendl;
  236. LLInventoryModel::cat_array_t cat_array;
  237. LLInventoryModel::item_array_t item_array;
  238. gInventory.collectDescendents(mCompleteFolders.front(),
  239.   cat_array,
  240.   item_array,
  241.   LLInventoryModel::EXCLUDE_TRASH);
  242. S32 count = item_array.count();
  243. if(!count)
  244. {
  245. llwarns << "Nothing fetched in category " << mCompleteFolders.front()
  246. << llendl;
  247. //dec_busy_count();
  248. gInventory.removeObserver(this);
  249. delete this;
  250. return;
  251. }
  252. LLOutfitObserver* outfit_observer = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend);
  253. LLInventoryFetchObserver::item_ref_t ids;
  254. for(S32 i = 0; i < count; ++i)
  255. {
  256. ids.push_back(item_array.get(i)->getUUID());
  257. }
  258. // clean up, and remove this as an observer since the call to the
  259. // outfit could notify observers and throw us into an infinite
  260. // loop.
  261. //dec_busy_count();
  262. gInventory.removeObserver(this);
  263. // increment busy count and either tell the inventory to check &
  264. // call done, or add this object to the inventory for observation.
  265. //inc_busy_count();
  266. // do the fetch
  267. outfit_observer->fetchItems(ids);
  268. if(outfit_observer->isEverythingComplete())
  269. {
  270. // everything is already here - call done.
  271. outfit_observer->done();
  272. }
  273. else
  274. {
  275. // it's all on it's way - add an observer, and the inventory
  276. // will call done for us when everything is here.
  277. gInventory.addObserver(outfit_observer);
  278. }
  279. delete this;
  280. }
  281. class LLUpdateAppearanceOnDestroy: public LLInventoryCallback
  282. {
  283. public:
  284. LLUpdateAppearanceOnDestroy():
  285. mFireCount(0)
  286. {
  287. }
  288. virtual ~LLUpdateAppearanceOnDestroy()
  289. {
  290. llinfos << "done update appearance on destroy" << llendl;
  291. if (!LLApp::isExiting())
  292. {
  293. LLAppearanceManager::instance().updateAppearanceFromCOF();
  294. }
  295. }
  296. /* virtual */ void fire(const LLUUID& inv_item)
  297. {
  298. llinfos << "callback fired" << llendl;
  299. mFireCount++;
  300. }
  301. private:
  302. U32 mFireCount;
  303. };
  304. struct LLFoundData
  305. {
  306. LLFoundData() : mAssetType(LLAssetType::AT_NONE), mWearable(NULL) {}
  307. LLFoundData(const LLUUID& item_id,
  308.     const LLUUID& asset_id,
  309.     const std::string& name,
  310.     LLAssetType::EType asset_type) :
  311. mItemID(item_id),
  312. mAssetID(asset_id),
  313. mName(name),
  314. mAssetType(asset_type),
  315. mWearable( NULL ) {}
  316. LLUUID mItemID;
  317. LLUUID mAssetID;
  318. std::string mName;
  319. LLAssetType::EType mAssetType;
  320. LLWearable* mWearable;
  321. };
  322. class LLWearableHoldingPattern
  323. {
  324. public:
  325. LLWearableHoldingPattern();
  326. ~LLWearableHoldingPattern();
  327. bool pollCompletion();
  328. bool isFetchCompleted();
  329. bool isTimedOut();
  330. typedef std::list<LLFoundData> found_list_t;
  331. found_list_t mFoundList;
  332. LLInventoryModel::item_array_t mObjItems;
  333. LLInventoryModel::item_array_t mGestItems;
  334. S32 mResolved;
  335. LLTimer mWaitTime;
  336. bool mFired;
  337. };
  338. LLWearableHoldingPattern::LLWearableHoldingPattern():
  339. mResolved(0),
  340. mFired(false)
  341. {
  342. }
  343. LLWearableHoldingPattern::~LLWearableHoldingPattern()
  344. {
  345. }
  346. bool LLWearableHoldingPattern::isFetchCompleted()
  347. {
  348. return (mResolved >= (S32)mFoundList.size()); // have everything we were waiting for?
  349. }
  350. bool LLWearableHoldingPattern::isTimedOut()
  351. {
  352. static F32 max_wait_time = 20.0;  // give up if wearable fetches haven't completed in max_wait_time seconds.
  353. return mWaitTime.getElapsedTimeF32() > max_wait_time; 
  354. }
  355. bool LLWearableHoldingPattern::pollCompletion()
  356. {
  357. bool completed = isFetchCompleted();
  358. bool timed_out = isTimedOut();
  359. bool done = completed || timed_out;
  360. llinfos << "polling, done status: " << completed << " timed out? " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl;
  361. if (done)
  362. {
  363. mFired = true;
  364. if (timed_out)
  365. {
  366. llwarns << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl;
  367. }
  368. // Activate all gestures in this folder
  369. if (mGestItems.count() > 0)
  370. {
  371. llinfos << "Activating " << mGestItems.count() << " gestures" << llendl;
  372. LLGestureManager::instance().activateGestures(mGestItems);
  373. // Update the inventory item labels to reflect the fact
  374. // they are active.
  375. LLViewerInventoryCategory* catp =
  376. gInventory.getCategory(LLAppearanceManager::instance().getCOF());
  377. if (catp)
  378. {
  379. gInventory.updateCategory(catp);
  380. gInventory.notifyObservers();
  381. }
  382. }
  383. // Update wearables.
  384. llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl;
  385. LLAppearanceManager::instance().updateAgentWearables(this, false);
  386. // Update attachments to match those requested.
  387. LLVOAvatar* avatar = gAgent.getAvatarObject();
  388. if( avatar )
  389. {
  390. llinfos << "Updating " << mObjItems.count() << " attachments" << llendl;
  391. LLAgentWearables::userUpdateAttachments(mObjItems);
  392. }
  393. if (completed)
  394. {
  395. // Only safe to delete if all wearable callbacks completed.
  396. delete this;
  397. }
  398. }
  399. return done;
  400. }
  401. static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
  402. {
  403. LLInventoryModel::item_array_t new_items;
  404. std::set<LLUUID> items_seen;
  405. std::deque<LLViewerInventoryItem*> tmp_list;
  406. // Traverse from the front and keep the first of each item
  407. // encountered, so we actually keep the *last* of each duplicate
  408. // item.  This is needed to give the right priority when adding
  409. // duplicate items to an existing outfit.
  410. for (S32 i=items.count()-1; i>=0; i--)
  411. {
  412. LLViewerInventoryItem *item = items.get(i);
  413. LLUUID item_id = item->getLinkedUUID();
  414. if (items_seen.find(item_id)!=items_seen.end())
  415. continue;
  416. items_seen.insert(item_id);
  417. tmp_list.push_front(item);
  418. }
  419. for (std::deque<LLViewerInventoryItem*>::iterator it = tmp_list.begin();
  420.  it != tmp_list.end();
  421.  ++it)
  422. {
  423. new_items.put(*it);
  424. }
  425. items = new_items;
  426. }
  427. static void onWearableAssetFetch(LLWearable* wearable, void* data)
  428. {
  429. LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
  430. if (holder->mFired)
  431. {
  432. llwarns << "called after holder fired" << llendl;
  433. }
  434. if(wearable)
  435. {
  436. for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
  437.  iter != holder->mFoundList.end(); ++iter)
  438. {
  439. LLFoundData& data = *iter;
  440. if(wearable->getAssetID() == data.mAssetID)
  441. {
  442. data.mWearable = wearable;
  443. break;
  444. }
  445. }
  446. }
  447. holder->mResolved += 1;
  448. }
  449. const LLUUID LLAppearanceManager::getCOF() const
  450. {
  451. return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
  452. }
  453. const LLViewerInventoryItem* LLAppearanceManager::getBaseOutfitLink()
  454. {
  455. const LLUUID& current_outfit_cat = getCOF();
  456. LLInventoryModel::cat_array_t cat_array;
  457. LLInventoryModel::item_array_t item_array;
  458. // Can't search on FT_OUTFIT since links to categories return FT_CATEGORY for type since they don't
  459. // return preferred type.
  460. LLIsType is_category( LLAssetType::AT_CATEGORY ); 
  461. gInventory.collectDescendentsIf(current_outfit_cat,
  462. cat_array,
  463. item_array,
  464. false,
  465. is_category,
  466. false);
  467. for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
  468.  iter != item_array.end();
  469.  iter++)
  470. {
  471. const LLViewerInventoryItem *item = (*iter);
  472. const LLViewerInventoryCategory *cat = item->getLinkedCategory();
  473. if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
  474. {
  475. return item;
  476. }
  477. }
  478. return NULL;
  479. }
  480. bool LLAppearanceManager::getBaseOutfitName(std::string& name)
  481. {
  482. const LLViewerInventoryItem* outfit_link = getBaseOutfitLink();
  483. if(outfit_link)
  484. {
  485. const LLViewerInventoryCategory *cat = outfit_link->getLinkedCategory();
  486. if (cat)
  487. {
  488. name = cat->getName();
  489. return true;
  490. }
  491. }
  492. return false;
  493. }
  494. // Update appearance from outfit folder.
  495. void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, bool append)
  496. {
  497. if (!proceed)
  498. return;
  499. LLAppearanceManager::instance().updateCOF(category,append);
  500. }
  501. // Create a copy of src_id + contents as a subfolder of dst_id.
  502. void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
  503.   LLPointer<LLInventoryCallback> cb)
  504. {
  505. LLInventoryCategory *src_cat = gInventory.getCategory(src_id);
  506. if (!src_cat)
  507. {
  508. llwarns << "folder not found for src " << src_id.asString() << llendl;
  509. return;
  510. }
  511. LLUUID parent_id = dst_id;
  512. if(parent_id.isNull())
  513. {
  514. parent_id = gInventory.getRootFolderID();
  515. }
  516. LLUUID subfolder_id = gInventory.createNewCategory( parent_id,
  517. LLFolderType::FT_NONE,
  518. src_cat->getName());
  519. shallowCopyCategoryContents(src_id, subfolder_id, cb);
  520. gInventory.notifyObservers();
  521. }
  522. // Copy contents of src_id to dst_id.
  523. void LLAppearanceManager::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
  524.   LLPointer<LLInventoryCallback> cb)
  525. {
  526. LLInventoryModel::cat_array_t cats;
  527. LLInventoryModel::item_array_t items;
  528. gInventory.collectDescendents(src_id, cats, items,
  529.   LLInventoryModel::EXCLUDE_TRASH);
  530. for (S32 i = 0; i < items.count(); ++i)
  531. {
  532. const LLViewerInventoryItem* item = items.get(i).get();
  533. if (item->getActualType() == LLAssetType::AT_LINK)
  534. {
  535. link_inventory_item(gAgent.getID(),
  536. item->getLinkedUUID(),
  537. dst_id,
  538. item->getName(),
  539. LLAssetType::AT_LINK, cb);
  540. }
  541. else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER)
  542. {
  543. LLViewerInventoryCategory *catp = item->getLinkedCategory();
  544. // Skip copying outfit links.
  545. if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT)
  546. {
  547. link_inventory_item(gAgent.getID(),
  548. item->getLinkedUUID(),
  549. dst_id,
  550. item->getName(),
  551. LLAssetType::AT_LINK_FOLDER, cb);
  552. }
  553. }
  554. else
  555. {
  556. copy_inventory_item(
  557. gAgent.getID(),
  558. item->getPermissions().getOwner(),
  559. item->getUUID(),
  560. dst_id,
  561. item->getName(),
  562. cb);
  563. }
  564. }
  565. }
  566. void LLAppearanceManager::purgeBaseOutfitLink(const LLUUID& category)
  567. {
  568. LLInventoryModel::cat_array_t cats;
  569. LLInventoryModel::item_array_t items;
  570. gInventory.collectDescendents(category, cats, items,
  571.   LLInventoryModel::EXCLUDE_TRASH);
  572. for (S32 i = 0; i < items.count(); ++i)
  573. {
  574. LLViewerInventoryItem *item = items.get(i);
  575. if (item->getActualType() != LLAssetType::AT_LINK_FOLDER)
  576. continue;
  577. if (item->getIsLinkType())
  578. {
  579. LLViewerInventoryCategory* catp = item->getLinkedCategory();
  580. if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
  581. {
  582. gInventory.purgeObject(item->getUUID());
  583. }
  584. }
  585. }
  586. }
  587. void LLAppearanceManager::purgeCategory(const LLUUID& category, bool keep_outfit_links)
  588. {
  589. LLInventoryModel::cat_array_t cats;
  590. LLInventoryModel::item_array_t items;
  591. gInventory.collectDescendents(category, cats, items,
  592.   LLInventoryModel::EXCLUDE_TRASH);
  593. for (S32 i = 0; i < items.count(); ++i)
  594. {
  595. LLViewerInventoryItem *item = items.get(i);
  596. if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER))
  597. continue;
  598. if (item->getIsLinkType())
  599. {
  600. gInventory.purgeObject(item->getUUID());
  601. }
  602. }
  603. }
  604. // Keep the last N wearables of each type.  For viewer 2.0, N is 1 for
  605. // both body parts and clothing items.
  606. void LLAppearanceManager::filterWearableItems(
  607. LLInventoryModel::item_array_t& items, S32 max_per_type)
  608. {
  609. // Divvy items into arrays by wearable type.
  610. std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT);
  611. for (S32 i=0; i<items.count(); i++)
  612. {
  613. LLViewerInventoryItem *item = items.get(i);
  614. // Ignore non-wearables.
  615. if (!item->isWearableType())
  616. continue;
  617. EWearableType type = item->getWearableType();
  618. if(type < 0 || type >= WT_COUNT)
  619. {
  620. LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
  621. continue;
  622. }
  623. items_by_type[type].push_back(item);
  624. }
  625. // rebuild items list, retaining the last max_per_type of each array
  626. items.clear();
  627. for (S32 i=0; i<WT_COUNT; i++)
  628. {
  629. S32 size = items_by_type[i].size();
  630. if (size <= 0)
  631. continue;
  632. S32 start_index = llmax(0,size-max_per_type);
  633. for (S32 j = start_index; j<size; j++)
  634. {
  635. items.push_back(items_by_type[i][j]);
  636. }
  637. }
  638. }
  639. // Create links to all listed items.
  640. void LLAppearanceManager::linkAll(const LLUUID& category,
  641.   LLInventoryModel::item_array_t& items,
  642.   LLPointer<LLInventoryCallback> cb)
  643. {
  644. for (S32 i=0; i<items.count(); i++)
  645. {
  646. const LLInventoryItem* item = items.get(i).get();
  647. link_inventory_item(gAgent.getID(),
  648. item->getLinkedUUID(),
  649. category,
  650. item->getName(),
  651. LLAssetType::AT_LINK,
  652. cb);
  653. }
  654. }
  655. void LLAppearanceManager::updateCOF(const LLUUID& category, bool append)
  656. {
  657. llinfos << "starting" << llendl;
  658. const LLUUID cof = getCOF();
  659. // Deactivate currently active gestures in the COF, if replacing outfit
  660. if (!append)
  661. {
  662. LLInventoryModel::item_array_t gest_items;
  663. getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false);
  664. for(S32 i = 0; i  < gest_items.count(); ++i)
  665. {
  666. LLViewerInventoryItem *gest_item = gest_items.get(i);
  667. if ( LLGestureManager::instance().isGestureActive( gest_item->getLinkedUUID()) )
  668. {
  669. LLGestureManager::instance().deactivateGesture( gest_item->getLinkedUUID() );
  670. }
  671. }
  672. }
  673. // Collect and filter descendents to determine new COF contents.
  674. // - Body parts: always include COF contents as a fallback in case any
  675. // required parts are missing.
  676. LLInventoryModel::item_array_t body_items;
  677. getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false);
  678. getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false);
  679. // Reduce body items to max of one per type.
  680. removeDuplicateItems(body_items);
  681. filterWearableItems(body_items, 1);
  682. // - Wearables: include COF contents only if appending.
  683. LLInventoryModel::item_array_t wear_items;
  684. if (append)
  685. getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false);
  686. getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);
  687. // Reduce wearables to max of one per type.
  688. removeDuplicateItems(wear_items);
  689. filterWearableItems(wear_items, 1);
  690. // - Attachments: include COF contents only if appending.
  691. LLInventoryModel::item_array_t obj_items;
  692. if (append)
  693. getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false);
  694. getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false);
  695. removeDuplicateItems(obj_items);
  696. // - Gestures: include COF contents only if appending.
  697. LLInventoryModel::item_array_t gest_items;
  698. if (append)
  699. getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false);
  700. getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false);
  701. removeDuplicateItems(gest_items);
  702. // Remove current COF contents.
  703. bool keep_outfit_links = append;
  704. purgeCategory(cof, keep_outfit_links);
  705. gInventory.notifyObservers();
  706. // Create links to new COF contents.
  707. llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl;
  708. LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
  709. linkAll(cof, body_items, link_waiter);
  710. linkAll(cof, wear_items, link_waiter);
  711. linkAll(cof, obj_items, link_waiter);
  712. linkAll(cof, gest_items, link_waiter);
  713. // Add link to outfit if category is an outfit. 
  714. if (!append)
  715. {
  716. createBaseOutfitLink(category, link_waiter);
  717. }
  718. llinfos << "waiting for LLUpdateAppearanceOnDestroy" << llendl;
  719. }
  720. void LLAppearanceManager::updatePanelOutfitName(const std::string& name)
  721. {
  722. LLSidepanelAppearance* panel_appearance =
  723. dynamic_cast<LLSidepanelAppearance *>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
  724. if (panel_appearance)
  725. {
  726. panel_appearance->refreshCurrentOutfitName(name);
  727. }
  728. }
  729. void LLAppearanceManager::createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter)
  730. {
  731. const LLUUID cof = getCOF();
  732. LLViewerInventoryCategory* catp = gInventory.getCategory(category);
  733. std::string new_outfit_name = "";
  734. purgeBaseOutfitLink(cof);
  735. if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
  736. {
  737. link_inventory_item(gAgent.getID(), category, cof, catp->getName(),
  738. LLAssetType::AT_LINK_FOLDER, link_waiter);
  739. new_outfit_name = catp->getName();
  740. }
  741. updatePanelOutfitName(new_outfit_name);
  742. }
  743. void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder, bool append)
  744. {
  745. lldebugs << "updateAgentWearables()" << llendl;
  746. LLInventoryItem::item_array_t items;
  747. LLDynamicArray< LLWearable* > wearables;
  748. // For each wearable type, find the first instance in the category
  749. // that we recursed through.
  750. for( S32 i = 0; i < WT_COUNT; i++ )
  751. {
  752. for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
  753.  iter != holder->mFoundList.end(); ++iter)
  754. {
  755. LLFoundData& data = *iter;
  756. LLWearable* wearable = data.mWearable;
  757. if( wearable && ((S32)wearable->getType() == i) )
  758. {
  759. LLViewerInventoryItem* item;
  760. item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
  761. if( item && (item->getAssetUUID() == wearable->getAssetID()) )
  762. {
  763. items.put(item);
  764. wearables.put(wearable);
  765. }
  766. break;
  767. }
  768. }
  769. }
  770. if(wearables.count() > 0)
  771. {
  772. gAgentWearables.setWearableOutfit(items, wearables, !append);
  773. }
  774. // dec_busy_count();
  775. }
  776. void LLAppearanceManager::updateAppearanceFromCOF()
  777. {
  778. // update dirty flag to see if the state of the COF matches
  779. // the saved outfit stored as a folder link
  780. llinfos << "starting" << llendl;
  781. updateIsDirty();
  782. dumpCat(getCOF(),"COF, start");
  783. bool follow_folder_links = true;
  784. LLUUID current_outfit_id = getCOF();
  785. // Find all the wearables that are in the COF's subtree.
  786. lldebugs << "LLAppearanceManager::updateFromCOF()" << llendl;
  787. LLInventoryModel::item_array_t wear_items;
  788. LLInventoryModel::item_array_t obj_items;
  789. LLInventoryModel::item_array_t gest_items;
  790. getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links);
  791. if(!wear_items.count())
  792. {
  793. LLNotificationsUtil::add("CouldNotPutOnOutfit");
  794. return;
  795. }
  796. LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
  797. holder->mObjItems = obj_items;
  798. holder->mGestItems = gest_items;
  799. // Note: can't do normal iteration, because if all the
  800. // wearables can be resolved immediately, then the
  801. // callback will be called (and this object deleted)
  802. // before the final getNextData().
  803. LLDynamicArray<LLFoundData> found_container;
  804. for(S32 i = 0; i  < wear_items.count(); ++i)
  805. {
  806. LLViewerInventoryItem *item = wear_items.get(i);
  807. LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
  808. if (item && linked_item)
  809. {
  810. LLFoundData found(linked_item->getUUID(),
  811.   linked_item->getAssetUUID(),
  812.   linked_item->getName(),
  813.   linked_item->getType());
  814. holder->mFoundList.push_front(found);
  815. found_container.put(found);
  816. }
  817. else
  818. {
  819. if (!item)
  820. {
  821. llwarns << "attempt to wear a null item " << llendl;
  822. }
  823. else if (!linked_item)
  824. {
  825. llwarns << "attempt to wear a broken link " << item->getName() << llendl;
  826. }
  827. }
  828. }
  829. for(S32 i = 0; i < found_container.count(); ++i)
  830. {
  831. LLFoundData& found = found_container.get(i);
  832. // Fetch the wearables about to be worn.
  833. LLWearableList::instance().getAsset(found.mAssetID,
  834. found.mName,
  835. found.mAssetType,
  836. onWearableAssetFetch,
  837. (void*)holder);
  838. }
  839. if (!holder->pollCompletion())
  840. {
  841. doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollCompletion,holder));
  842. }
  843. }
  844. void LLAppearanceManager::getDescendentsOfAssetType(const LLUUID& category,
  845. LLInventoryModel::item_array_t& items,
  846. LLAssetType::EType type,
  847. bool follow_folder_links)
  848. {
  849. LLInventoryModel::cat_array_t cats;
  850. LLIsType is_of_type(type);
  851. gInventory.collectDescendentsIf(category,
  852. cats,
  853. items,
  854. LLInventoryModel::EXCLUDE_TRASH,
  855. is_of_type,
  856. follow_folder_links);
  857. }
  858. void LLAppearanceManager::getUserDescendents(const LLUUID& category, 
  859.  LLInventoryModel::item_array_t& wear_items,
  860.  LLInventoryModel::item_array_t& obj_items,
  861.  LLInventoryModel::item_array_t& gest_items,
  862.  bool follow_folder_links)
  863. {
  864. LLInventoryModel::cat_array_t wear_cats;
  865. LLFindWearables is_wearable;
  866. gInventory.collectDescendentsIf(category,
  867. wear_cats,
  868. wear_items,
  869. LLInventoryModel::EXCLUDE_TRASH,
  870. is_wearable,
  871. follow_folder_links);
  872. LLInventoryModel::cat_array_t obj_cats;
  873. LLIsType is_object( LLAssetType::AT_OBJECT );
  874. gInventory.collectDescendentsIf(category,
  875. obj_cats,
  876. obj_items,
  877. LLInventoryModel::EXCLUDE_TRASH,
  878. is_object,
  879. follow_folder_links);
  880. // Find all gestures in this folder
  881. LLInventoryModel::cat_array_t gest_cats;
  882. LLIsType is_gesture( LLAssetType::AT_GESTURE );
  883. gInventory.collectDescendentsIf(category,
  884. gest_cats,
  885. gest_items,
  886. LLInventoryModel::EXCLUDE_TRASH,
  887. is_gesture,
  888. follow_folder_links);
  889. }
  890. void LLAppearanceManager::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
  891. {
  892. if(!category) return;
  893. llinfos << "wearInventoryCategory( " << category->getName()
  894.  << " )" << llendl;
  895. // What we do here is get the complete information on the items in
  896. // the inventory, and set up an observer that will wait for that to
  897. // happen.
  898. LLOutfitFetch* outfit_fetcher = new LLOutfitFetch(copy, append);
  899. LLInventoryFetchDescendentsObserver::folder_ref_t folders;
  900. folders.push_back(category->getUUID());
  901. outfit_fetcher->fetchDescendents(folders);
  902. //inc_busy_count();
  903. if(outfit_fetcher->isEverythingComplete())
  904. {
  905. // everything is already here - call done.
  906. outfit_fetcher->done();
  907. }
  908. else
  909. {
  910. // it's all on it's way - add an observer, and the inventory
  911. // will call done for us when everything is here.
  912. gInventory.addObserver(outfit_fetcher);
  913. }
  914. }
  915. // *NOTE: hack to get from avatar inventory to avatar
  916. void LLAppearanceManager::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append )
  917. {
  918. // Avoid unintentionally overwriting old wearables.  We have to do
  919. // this up front to avoid having to deal with the case of multiple
  920. // wearables being dirty.
  921. if(!category) return;
  922. llinfos << "wearInventoryCategoryOnAvatar( " << category->getName()
  923.  << " )" << llendl;
  924.  
  925. if( gFloaterCustomize )
  926. {
  927. gFloaterCustomize->askToSaveIfDirty(boost::bind(&LLAppearanceManager::changeOutfit,
  928. &LLAppearanceManager::instance(),
  929. _1, category->getUUID(), append));
  930. }
  931. else
  932. {
  933. LLAppearanceManager::changeOutfit(TRUE, category->getUUID(), append);
  934. }
  935. }
  936. void LLAppearanceManager::wearOutfitByName(const std::string& name)
  937. {
  938. llinfos << "Wearing category " << name << llendl;
  939. //inc_busy_count();
  940. LLInventoryModel::cat_array_t cat_array;
  941. LLInventoryModel::item_array_t item_array;
  942. LLNameCategoryCollector has_name(name);
  943. gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
  944. cat_array,
  945. item_array,
  946. LLInventoryModel::EXCLUDE_TRASH,
  947. has_name);
  948. bool copy_items = false;
  949. LLInventoryCategory* cat = NULL;
  950. if (cat_array.count() > 0)
  951. {
  952. // Just wear the first one that matches
  953. cat = cat_array.get(0);
  954. }
  955. else
  956. {
  957. gInventory.collectDescendentsIf(LLUUID::null,
  958. cat_array,
  959. item_array,
  960. LLInventoryModel::EXCLUDE_TRASH,
  961. has_name);
  962. if(cat_array.count() > 0)
  963. {
  964. cat = cat_array.get(0);
  965. copy_items = true;
  966. }
  967. }
  968. if(cat)
  969. {
  970. LLAppearanceManager::wearInventoryCategory(cat, copy_items, false);
  971. }
  972. else
  973. {
  974. llwarns << "Couldn't find outfit " <<name<< " in wearOutfitByName()"
  975. << llendl;
  976. }
  977. //dec_busy_count();
  978. }
  979. bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventoryItem *b)
  980. {
  981. return (a->isWearableType() && b->isWearableType() &&
  982. (a->getWearableType() == b->getWearableType()));
  983. }
  984. class LLDeferredCOFLinkObserver: public LLInventoryObserver
  985. {
  986. public:
  987. LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update):
  988. mItemID(item_id),
  989. mDoUpdate(do_update)
  990. {
  991. }
  992. ~LLDeferredCOFLinkObserver()
  993. {
  994. }
  995. /* virtual */ void changed(U32 mask)
  996. {
  997. const LLInventoryItem *item = gInventory.getItem(mItemID);
  998. if (item)
  999. {
  1000. gInventory.removeObserver(this);
  1001. LLAppearanceManager::instance().addCOFItemLink(item,mDoUpdate);
  1002. delete this;
  1003. }
  1004. }
  1005. private:
  1006. const LLUUID mItemID;
  1007. bool mDoUpdate;
  1008. };
  1009. void LLAppearanceManager::addCOFItemLink(const LLUUID &item_id, bool do_update )
  1010. {
  1011. const LLInventoryItem *item = gInventory.getItem(item_id);
  1012. if (!item)
  1013. {
  1014. LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update);
  1015. gInventory.addObserver(observer);
  1016. }
  1017. else
  1018. {
  1019. addCOFItemLink(item, do_update);
  1020. }
  1021. }
  1022. void LLAppearanceManager::addCOFItemLink(const LLInventoryItem *item, bool do_update )
  1023. {
  1024. const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);
  1025. if (!vitem)
  1026. {
  1027. llwarns << "not an llviewerinventoryitem, failed" << llendl;
  1028. return;
  1029. }
  1030. gInventory.addChangedMask(LLInventoryObserver::LABEL, vitem->getLinkedUUID());
  1031. LLInventoryModel::cat_array_t cat_array;
  1032. LLInventoryModel::item_array_t item_array;
  1033. gInventory.collectDescendents(LLAppearanceManager::getCOF(),
  1034.   cat_array,
  1035.   item_array,
  1036.   LLInventoryModel::EXCLUDE_TRASH);
  1037. bool linked_already = false;
  1038. for (S32 i=0; i<item_array.count(); i++)
  1039. {
  1040. // Are these links to the same object?
  1041. const LLViewerInventoryItem* inv_item = item_array.get(i).get();
  1042. if (inv_item->getLinkedUUID() == vitem->getLinkedUUID())
  1043. {
  1044. linked_already = true;
  1045. }
  1046. // Are these links to different items of the same wearable
  1047. // type? If so, new item will replace old.
  1048. // MULTI-WEARABLES: revisit if more than one per type is allowed.
  1049. else if (areMatchingWearables(vitem,inv_item))
  1050. {
  1051. if (inv_item->getIsLinkType())
  1052. {
  1053. gInventory.purgeObject(inv_item->getUUID());
  1054. }
  1055. }
  1056. }
  1057. if (linked_already)
  1058. {
  1059. if (do_update)
  1060. {
  1061. LLAppearanceManager::updateAppearanceFromCOF();
  1062. }
  1063. return;
  1064. }
  1065. else
  1066. {
  1067. LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
  1068. link_inventory_item( gAgent.getID(),
  1069.  vitem->getLinkedUUID(),
  1070.  getCOF(),
  1071.  vitem->getName(),
  1072.  LLAssetType::AT_LINK,
  1073.  cb);
  1074. }
  1075. return;
  1076. }
  1077. void LLAppearanceManager::addEnsembleLink( LLInventoryCategory* cat, bool do_update )
  1078. {
  1079. #if SUPPORT_ENSEMBLES
  1080. // BAP add check for already in COF.
  1081. LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
  1082. link_inventory_item( gAgent.getID(),
  1083.  cat->getLinkedUUID(),
  1084.  getCOF(),
  1085.  cat->getName(),
  1086.  LLAssetType::AT_LINK_FOLDER,
  1087.  cb);
  1088. #endif
  1089. }
  1090. void LLAppearanceManager::removeCOFItemLinks(const LLUUID& item_id, bool do_update)
  1091. {
  1092. gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
  1093. LLInventoryModel::cat_array_t cat_array;
  1094. LLInventoryModel::item_array_t item_array;
  1095. gInventory.collectDescendents(LLAppearanceManager::getCOF(),
  1096.   cat_array,
  1097.   item_array,
  1098.   LLInventoryModel::EXCLUDE_TRASH);
  1099. for (S32 i=0; i<item_array.count(); i++)
  1100. {
  1101. const LLInventoryItem* item = item_array.get(i).get();
  1102. if (item->getIsLinkType() && item->getLinkedUUID() == item_id)
  1103. {
  1104. gInventory.purgeObject(item->getUUID());
  1105. }
  1106. }
  1107. if (do_update)
  1108. {
  1109. LLAppearanceManager::updateAppearanceFromCOF();
  1110. }
  1111. }
  1112. void LLAppearanceManager::updateIsDirty()
  1113. {
  1114. LLUUID cof = getCOF();
  1115. LLUUID base_outfit;
  1116. // find base outfit link 
  1117. const LLViewerInventoryItem* base_outfit_item = getBaseOutfitLink();
  1118. LLViewerInventoryCategory* catp = NULL;
  1119. if (base_outfit_item && base_outfit_item->getIsLinkType())
  1120. {
  1121. catp = base_outfit_item->getLinkedCategory();
  1122. }
  1123. if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
  1124. {
  1125. base_outfit = catp->getUUID();
  1126. }
  1127. if(base_outfit.isNull())
  1128. {
  1129. // no outfit link found, display "unsaved outfit"
  1130. mOutfitIsDirty = true;
  1131. }
  1132. else
  1133. {
  1134. LLInventoryModel::cat_array_t cof_cats;
  1135. LLInventoryModel::item_array_t cof_items;
  1136. gInventory.collectDescendents(cof, cof_cats, cof_items,
  1137.   LLInventoryModel::EXCLUDE_TRASH);
  1138. LLInventoryModel::cat_array_t outfit_cats;
  1139. LLInventoryModel::item_array_t outfit_items;
  1140. gInventory.collectDescendents(base_outfit, outfit_cats, outfit_items,
  1141.   LLInventoryModel::EXCLUDE_TRASH);
  1142. if(outfit_items.count() != cof_items.count() -1)
  1143. {
  1144. // Current outfit folder should have one more item than the outfit folder.
  1145. // this one item is the link back to the outfit folder itself.
  1146. mOutfitIsDirty = true;
  1147. }
  1148. else
  1149. {
  1150. typedef std::set<LLUUID> item_set_t;
  1151. item_set_t cof_set;
  1152. item_set_t outfit_set;
  1153. // sort COF items by UUID
  1154. for (S32 i = 0; i < cof_items.count(); ++i)
  1155. {
  1156. LLViewerInventoryItem *item = cof_items.get(i);
  1157. // don't add the base outfit link to the list of objects we're comparing
  1158. if(item != base_outfit_item)
  1159. {
  1160. cof_set.insert(item->getLinkedUUID());
  1161. }
  1162. }
  1163. // sort outfit folder by UUID
  1164. for (S32 i = 0; i < outfit_items.count(); ++i)
  1165. {
  1166. LLViewerInventoryItem *item = outfit_items.get(i);
  1167. outfit_set.insert(item->getLinkedUUID());
  1168. }
  1169. mOutfitIsDirty = (outfit_set != cof_set);
  1170. }
  1171. }
  1172. }
  1173. void LLAppearanceManager::onFirstFullyVisible()
  1174. {
  1175. // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account)
  1176. // then auto-populate outfits from the library into the My Outfits folder.
  1177. llinfos << "avatar fully visible" << llendl;
  1178. static bool check_populate_my_outfits = true;
  1179. if (check_populate_my_outfits && 
  1180. (LLInventoryModel::getIsFirstTimeInViewer2() 
  1181.  || gSavedSettings.getBOOL("MyOutfitsAutofill")))
  1182. {
  1183. gAgentWearables.populateMyOutfitsFolder();
  1184. }
  1185. check_populate_my_outfits = false;
  1186. }
  1187. //#define DUMP_CAT_VERBOSE
  1188. void LLAppearanceManager::dumpCat(const LLUUID& cat_id, const std::string& msg)
  1189. {
  1190. LLInventoryModel::cat_array_t cats;
  1191. LLInventoryModel::item_array_t items;
  1192. gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
  1193. #ifdef DUMP_CAT_VERBOSE
  1194. llinfos << llendl;
  1195. llinfos << str << llendl;
  1196. S32 hitcount = 0;
  1197. for(S32 i=0; i<items.count(); i++)
  1198. {
  1199. LLViewerInventoryItem *item = items.get(i);
  1200. if (item)
  1201. hitcount++;
  1202. llinfos << i <<" "<< item->getName() <<llendl;
  1203. }
  1204. #endif
  1205. llinfos << msg << " count " << items.count() << llendl;
  1206. }
  1207. void LLAppearanceManager::dumpItemArray(const LLInventoryModel::item_array_t& items,
  1208. const std::string& msg)
  1209. {
  1210. llinfos << msg << llendl;
  1211. for (S32 i=0; i<items.count(); i++)
  1212. {
  1213. LLViewerInventoryItem *item = items.get(i);
  1214. llinfos << i <<" " << item->getName() << llendl;
  1215. }
  1216. llinfos << llendl;
  1217. }
  1218. LLAppearanceManager::LLAppearanceManager():
  1219. mAttachmentInvLinkEnabled(false),
  1220. mOutfitIsDirty(false)
  1221. {
  1222. }
  1223. LLAppearanceManager::~LLAppearanceManager()
  1224. {
  1225. }
  1226. void LLAppearanceManager::setAttachmentInvLinkEnable(bool val)
  1227. {
  1228. llinfos << "setAttachmentInvLinkEnable => " << (int) val << llendl;
  1229. mAttachmentInvLinkEnabled = val;
  1230. }
  1231. void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
  1232. {
  1233.        llinfos << msg << llendl;
  1234.        for (std::set<LLUUID>::const_iterator it = atts.begin();
  1235.                it != atts.end();
  1236.                ++it)
  1237.        {
  1238.                LLUUID item_id = *it;
  1239.                LLViewerInventoryItem *item = gInventory.getItem(item_id);
  1240.                if (item)
  1241.                        llinfos << "atts " << item->getName() << llendl;
  1242.                else
  1243.                        llinfos << "atts " << "UNKNOWN[" << item_id.asString() << "]" << llendl;
  1244.        }
  1245.        llinfos << llendl;
  1246. }
  1247. void LLAppearanceManager::registerAttachment(const LLUUID& item_id)
  1248. {
  1249.        mRegisteredAttachments.insert(item_id);
  1250.    gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
  1251.        //dumpAttachmentSet(mRegisteredAttachments,"after register:");
  1252.    if (mAttachmentInvLinkEnabled)
  1253.    {
  1254.    LLAppearanceManager::addCOFItemLink(item_id, false);  // Add COF link for item.
  1255.    }
  1256.    else
  1257.    {
  1258.    //llinfos << "no link changes, inv link not enabled" << llendl;
  1259.    }
  1260. }
  1261. void LLAppearanceManager::unregisterAttachment(const LLUUID& item_id)
  1262. {
  1263.        mRegisteredAttachments.erase(item_id);
  1264.    gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
  1265.        //dumpAttachmentSet(mRegisteredAttachments,"after unregister:");
  1266.    if (mAttachmentInvLinkEnabled)
  1267.    {
  1268.    //LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Removing attachment link:");
  1269.    LLAppearanceManager::removeCOFItemLinks(item_id, false);
  1270.    }
  1271.    else
  1272.    {
  1273.    //llinfos << "no link changes, inv link not enabled" << llendl;
  1274.    }
  1275. }
  1276. void LLAppearanceManager::linkRegisteredAttachments()
  1277. {
  1278. for (std::set<LLUUID>::iterator it = mRegisteredAttachments.begin();
  1279.  it != mRegisteredAttachments.end();
  1280.  ++it)
  1281. {
  1282. LLUUID item_id = *it;
  1283. addCOFItemLink(item_id, false);
  1284. }
  1285. mRegisteredAttachments.clear();
  1286. }
  1287. BOOL LLAppearanceManager::getIsInCOF(const LLUUID& obj_id) const
  1288. {
  1289. return gInventory.isObjectDescendentOf(obj_id, getCOF());
  1290. }
  1291. BOOL LLAppearanceManager::getIsProtectedCOFItem(const LLUUID& obj_id) const
  1292. {
  1293. if (!getIsInCOF(obj_id)) return FALSE;
  1294. // For now, don't allow direct deletion from the COF.  Instead, force users
  1295. // to choose "Detach" or "Take Off".
  1296. return TRUE;
  1297. /*
  1298. const LLInventoryObject *obj = gInventory.getObject(obj_id);
  1299. if (!obj) return FALSE;
  1300. // Can't delete bodyparts, since this would be equivalent to removing the item.
  1301. if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE;
  1302. // Can't delete the folder link, since this is saved for bookkeeping.
  1303. if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE;
  1304. return FALSE;
  1305. */
  1306. }