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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llviewerinventory.cpp
  3.  * @brief Implementation of the viewer side inventory objects.
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-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 "llviewerinventory.h"
  34. #include "llnotificationsutil.h"
  35. #include "llsdserialize.h"
  36. #include "message.h"
  37. #include "indra_constants.h"
  38. #include "llagent.h"
  39. #include "llviewerfoldertype.h"
  40. #include "llfolderview.h"
  41. #include "llviewercontrol.h"
  42. #include "llconsole.h"
  43. #include "llinventorymodel.h"
  44. #include "llgesturemgr.h"
  45. #include "llsidetray.h"
  46. #include "llinventorybridge.h"
  47. #include "llfloaterinventory.h"
  48. #include "llviewerassettype.h"
  49. #include "llviewerregion.h"
  50. #include "llviewerobjectlist.h"
  51. #include "llpreviewgesture.h"
  52. #include "llviewerwindow.h"
  53. #include "lltrans.h"
  54. #include "llappearancemgr.h"
  55. #include "llfloatercustomize.h"
  56. #include "llcommandhandler.h"
  57. #include "llviewermessage.h"
  58. ///----------------------------------------------------------------------------
  59. /// Local function declarations, constants, enums, and typedefs
  60. ///----------------------------------------------------------------------------
  61. class LLInventoryHandler : public LLCommandHandler
  62. {
  63. public:
  64. // requires trusted browser to trigger
  65. LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { }
  66. bool handle(const LLSD& params, const LLSD& query_map,
  67. LLMediaCtrl* web)
  68. {
  69. if (params.size() < 1)
  70. {
  71. return false;
  72. }
  73. // support secondlife:///app/inventory/show
  74. if (params[0].asString() == "show")
  75. {
  76. LLSideTray::getInstance()->showPanel("sidepanel_inventory", LLSD());
  77. return true;
  78. }
  79. // otherwise, we need a UUID and a verb...
  80. if (params.size() < 2) 
  81. {
  82. return false;
  83. }
  84. LLUUID inventory_id;
  85. if (!inventory_id.set(params[0], FALSE))
  86. {
  87. return false;
  88. }
  89. const std::string verb = params[1].asString();
  90. if (verb == "select")
  91. {
  92. std::vector<LLUUID> items_to_open;
  93. items_to_open.push_back(inventory_id);
  94. //inventory_handler is just a stub, because we don't know from who this offer
  95. open_inventory_offer(items_to_open, "inventory_handler");
  96. return true;
  97. }
  98. return false;
  99. }
  100. };
  101. LLInventoryHandler gInventoryHandler;
  102. ///----------------------------------------------------------------------------
  103. /// Class LLViewerInventoryItem
  104. ///----------------------------------------------------------------------------
  105. LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& uuid,
  106.  const LLUUID& parent_uuid,
  107.  const LLPermissions& perm,
  108.  const LLUUID& asset_uuid,
  109.  LLAssetType::EType type,
  110.  LLInventoryType::EType inv_type,
  111.  const std::string& name,
  112.  const std::string& desc,
  113.  const LLSaleInfo& sale_info,
  114.  U32 flags,
  115.  time_t creation_date_utc) :
  116. LLInventoryItem(uuid, parent_uuid, perm, asset_uuid, type, inv_type,
  117. name, desc, sale_info, flags, creation_date_utc),
  118. mIsComplete(TRUE)
  119. {
  120. }
  121. LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
  122.  const LLUUID& parent_id,
  123.  const std::string& name,
  124.  LLInventoryType::EType inv_type) :
  125. LLInventoryItem(),
  126. mIsComplete(FALSE)
  127. {
  128. mUUID = item_id;
  129. mParentUUID = parent_id;
  130. mInventoryType = inv_type;
  131. mName = name;
  132. }
  133. LLViewerInventoryItem::LLViewerInventoryItem() :
  134. LLInventoryItem(),
  135. mIsComplete(FALSE)
  136. {
  137. }
  138. LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other) :
  139. LLInventoryItem()
  140. {
  141. copyViewerItem(other);
  142. if (!mIsComplete)
  143. {
  144. llwarns << "LLViewerInventoryItem copy constructor for incomplete item"
  145. << mUUID << llendl;
  146. }
  147. }
  148. LLViewerInventoryItem::LLViewerInventoryItem(const LLInventoryItem *other) :
  149. LLInventoryItem(other),
  150. mIsComplete(TRUE)
  151. {
  152. }
  153. LLViewerInventoryItem::~LLViewerInventoryItem()
  154. {
  155. }
  156. void LLViewerInventoryItem::copyViewerItem(const LLViewerInventoryItem* other)
  157. {
  158. LLInventoryItem::copyItem(other);
  159. mIsComplete = other->mIsComplete;
  160. mTransactionID = other->mTransactionID;
  161. }
  162. // virtual
  163. void LLViewerInventoryItem::copyItem(const LLInventoryItem *other)
  164. {
  165. LLInventoryItem::copyItem(other);
  166. mIsComplete = true;
  167. mTransactionID.setNull();
  168. }
  169. void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const
  170. {
  171. newitem = new LLViewerInventoryItem(this);
  172. if(newitem.notNull())
  173. {
  174. LLUUID item_id;
  175. item_id.generate();
  176. newitem->setUUID(item_id);
  177. }
  178. }
  179. void LLViewerInventoryItem::removeFromServer()
  180. {
  181. llinfos << "Removing inventory item " << mUUID << " from server."
  182. << llendl;
  183. LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1);
  184. gInventory.accountForUpdate(up);
  185. LLMessageSystem* msg = gMessageSystem;
  186. msg->newMessageFast(_PREHASH_RemoveInventoryItem);
  187. msg->nextBlockFast(_PREHASH_AgentData);
  188. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  189. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); 
  190. msg->nextBlockFast(_PREHASH_InventoryData);
  191. msg->addUUIDFast(_PREHASH_ItemID, mUUID);
  192. gAgent.sendReliableMessage();
  193. }
  194. void LLViewerInventoryItem::updateServer(BOOL is_new) const
  195. {
  196. if(!mIsComplete)
  197. {
  198. // *FIX: deal with this better.
  199. // If we're crashing here then the UI is incorrectly enabled.
  200. llerrs << "LLViewerInventoryItem::updateServer() - for incomplete item"
  201.    << llendl;
  202. return;
  203. }
  204. if(gAgent.getID() != mPermissions.getOwner())
  205. {
  206. // *FIX: deal with this better.
  207. llwarns << "LLViewerInventoryItem::updateServer() - for unowned item"
  208. << llendl;
  209. return;
  210. }
  211. LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
  212. gInventory.accountForUpdate(up);
  213. LLMessageSystem* msg = gMessageSystem;
  214. msg->newMessageFast(_PREHASH_UpdateInventoryItem);
  215. msg->nextBlockFast(_PREHASH_AgentData);
  216. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  217. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  218. msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
  219. msg->nextBlockFast(_PREHASH_InventoryData);
  220. msg->addU32Fast(_PREHASH_CallbackID, 0);
  221. packMessage(msg);
  222. gAgent.sendReliableMessage();
  223. }
  224. void LLViewerInventoryItem::fetchFromServer(void) const
  225. {
  226. if(!mIsComplete)
  227. {
  228. std::string url; 
  229. LLViewerRegion* region = gAgent.getRegion();
  230. // we have to check region. It can be null after region was destroyed. See EXT-245
  231. if (region)
  232. {
  233. if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString())
  234. url = region->getCapability("FetchLib");
  235. else
  236. url = region->getCapability("FetchInventory");
  237. }
  238. else
  239. {
  240. llwarns << "Agent Region is absent" << llendl;
  241. }
  242. if (!url.empty())
  243. {
  244. LLSD body;
  245. body["agent_id"] = gAgent.getID();
  246. body["items"][0]["owner_id"] = mPermissions.getOwner();
  247. body["items"][0]["item_id"] = mUUID;
  248. LLHTTPClient::post(url, body, new LLInventoryModel::fetchInventoryResponder(body));
  249. }
  250. else
  251. {
  252. LLMessageSystem* msg = gMessageSystem;
  253. msg->newMessage("FetchInventory");
  254. msg->nextBlock("AgentData");
  255. msg->addUUID("AgentID", gAgent.getID());
  256. msg->addUUID("SessionID", gAgent.getSessionID());
  257. msg->nextBlock("InventoryData");
  258. msg->addUUID("OwnerID", mPermissions.getOwner());
  259. msg->addUUID("ItemID", mUUID);
  260. gAgent.sendReliableMessage();
  261. }
  262. }
  263. else
  264. {
  265. // *FIX: this can be removed after a bit.
  266. llwarns << "request to fetch complete item" << llendl;
  267. }
  268. }
  269. // virtual
  270. BOOL LLViewerInventoryItem::unpackMessage(LLSD item)
  271. {
  272. BOOL rv = LLInventoryItem::fromLLSD(item);
  273. mIsComplete = TRUE;
  274. return rv;
  275. }
  276. // virtual
  277. BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
  278. {
  279. BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num);
  280. mIsComplete = TRUE;
  281. return rv;
  282. }
  283. void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_id)
  284. {
  285. mTransactionID = transaction_id;
  286. }
  287. // virtual
  288. void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
  289. {
  290. msg->addUUIDFast(_PREHASH_ItemID, mUUID);
  291. msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
  292. mPermissions.packMessage(msg);
  293. msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
  294. S8 type = static_cast<S8>(mType);
  295. msg->addS8Fast(_PREHASH_Type, type);
  296. type = static_cast<S8>(mInventoryType);
  297. msg->addS8Fast(_PREHASH_InvType, type);
  298. msg->addU32Fast(_PREHASH_Flags, mFlags);
  299. mSaleInfo.packMessage(msg);
  300. msg->addStringFast(_PREHASH_Name, mName);
  301. msg->addStringFast(_PREHASH_Description, mDescription);
  302. msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
  303. U32 crc = getCRC32();
  304. msg->addU32Fast(_PREHASH_CRC, crc);
  305. }
  306. // virtual
  307. BOOL LLViewerInventoryItem::importFile(LLFILE* fp)
  308. {
  309. BOOL rv = LLInventoryItem::importFile(fp);
  310. mIsComplete = TRUE;
  311. return rv;
  312. }
  313. // virtual
  314. BOOL LLViewerInventoryItem::importLegacyStream(std::istream& input_stream)
  315. {
  316. BOOL rv = LLInventoryItem::importLegacyStream(input_stream);
  317. mIsComplete = TRUE;
  318. return rv;
  319. }
  320. bool LLViewerInventoryItem::importFileLocal(LLFILE* fp)
  321. {
  322. // TODO: convert all functions that return BOOL to return bool
  323. bool rv = (LLInventoryItem::importFile(fp) ? true : false);
  324. mIsComplete = false;
  325. return rv;
  326. }
  327. bool LLViewerInventoryItem::exportFileLocal(LLFILE* fp) const
  328. {
  329. std::string uuid_str;
  330. fprintf(fp, "tinv_itemt0nt{n");
  331. mUUID.toString(uuid_str);
  332. fprintf(fp, "ttitem_idt%sn", uuid_str.c_str());
  333. mParentUUID.toString(uuid_str);
  334. fprintf(fp, "ttparent_idt%sn", uuid_str.c_str());
  335. mPermissions.exportFile(fp);
  336. fprintf(fp, "tttypet%sn", LLAssetType::lookup(mType));
  337. const std::string inv_type_str = LLInventoryType::lookup(mInventoryType);
  338. if(!inv_type_str.empty()) fprintf(fp, "ttinv_typet%sn", inv_type_str.c_str());
  339. fprintf(fp, "ttnamet%s|n", mName.c_str());
  340. fprintf(fp, "ttcreation_datet%dn", (S32) mCreationDate);
  341. fprintf(fp,"t}n");
  342. return true;
  343. }
  344. void LLViewerInventoryItem::updateParentOnServer(BOOL restamp) const
  345. {
  346. LLMessageSystem* msg = gMessageSystem;
  347. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  348. msg->nextBlockFast(_PREHASH_AgentData);
  349. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  350. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  351. msg->addBOOLFast(_PREHASH_Stamp, restamp);
  352. msg->nextBlockFast(_PREHASH_InventoryData);
  353. msg->addUUIDFast(_PREHASH_ItemID, mUUID);
  354. msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
  355. msg->addString("NewName", NULL);
  356. gAgent.sendReliableMessage();
  357. }
  358. //void LLViewerInventoryItem::setCloneCount(S32 clones)
  359. //{
  360. // mClones = clones;
  361. //}
  362. //S32 LLViewerInventoryItem::getCloneCount() const
  363. //{
  364. // return mClones;
  365. //}
  366. ///----------------------------------------------------------------------------
  367. /// Class LLViewerInventoryCategory
  368. ///----------------------------------------------------------------------------
  369. LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
  370.  const LLUUID& parent_uuid,
  371.  LLFolderType::EType pref,
  372.  const std::string& name,
  373.  const LLUUID& owner_id) :
  374. LLInventoryCategory(uuid, parent_uuid, pref, name),
  375. mOwnerID(owner_id),
  376. mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
  377. mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
  378. {
  379. mDescendentsRequested.reset();
  380. }
  381. LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& owner_id) :
  382. mOwnerID(owner_id),
  383. mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
  384. mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
  385. {
  386. mDescendentsRequested.reset();
  387. }
  388. LLViewerInventoryCategory::LLViewerInventoryCategory(const LLViewerInventoryCategory* other)
  389. {
  390. copyViewerCategory(other);
  391. }
  392. LLViewerInventoryCategory::~LLViewerInventoryCategory()
  393. {
  394. }
  395. void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCategory* other)
  396. {
  397. copyCategory(other);
  398. mOwnerID = other->mOwnerID;
  399. mVersion = other->mVersion;
  400. mDescendentCount = other->mDescendentCount;
  401. mDescendentsRequested = other->mDescendentsRequested;
  402. }
  403. void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const
  404. {
  405. LLMessageSystem* msg = gMessageSystem;
  406. msg->newMessageFast(_PREHASH_MoveInventoryFolder);
  407. msg->nextBlockFast(_PREHASH_AgentData);
  408. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  409. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  410. msg->addBOOL("Stamp", restamp);
  411. msg->nextBlockFast(_PREHASH_InventoryData);
  412. msg->addUUIDFast(_PREHASH_FolderID, mUUID);
  413. msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
  414. gAgent.sendReliableMessage();
  415. }
  416. void LLViewerInventoryCategory::updateServer(BOOL is_new) const
  417. {
  418. // communicate that change with the server.
  419. if (LLFolderType::lookupIsProtectedType(mPreferredType))
  420. {
  421. LLNotificationsUtil::add("CannotModifyProtectedCategories");
  422. return;
  423. }
  424. LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
  425. gInventory.accountForUpdate(up);
  426. LLMessageSystem* msg = gMessageSystem;
  427. msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
  428. msg->nextBlockFast(_PREHASH_AgentData);
  429. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  430. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  431. msg->nextBlockFast(_PREHASH_FolderData);
  432. packMessage(msg);
  433. gAgent.sendReliableMessage();
  434. }
  435. void LLViewerInventoryCategory::removeFromServer( void )
  436. {
  437. llinfos << "Removing inventory category " << mUUID << " from server."
  438. << llendl;
  439. // communicate that change with the server.
  440. if(LLFolderType::lookupIsProtectedType(mPreferredType))
  441. {
  442. LLNotificationsUtil::add("CannotRemoveProtectedCategories");
  443. return;
  444. }
  445. LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1);
  446. gInventory.accountForUpdate(up);
  447. LLMessageSystem* msg = gMessageSystem;
  448. msg->newMessageFast(_PREHASH_RemoveInventoryFolder);
  449. msg->nextBlockFast(_PREHASH_AgentData);
  450. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  451. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  452. msg->nextBlockFast(_PREHASH_FolderData);
  453. msg->addUUIDFast(_PREHASH_FolderID, mUUID);
  454. gAgent.sendReliableMessage();
  455. }
  456. bool LLViewerInventoryCategory::fetchDescendents()
  457. {
  458. if((VERSION_UNKNOWN == mVersion)
  459.    && mDescendentsRequested.hasExpired()) //Expired check prevents multiple downloads.
  460. {
  461. const F32 FETCH_TIMER_EXPIRY = 10.0f;
  462. mDescendentsRequested.reset();
  463. mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
  464. // bitfield
  465. // 1 = by date
  466. // 2 = folders by date
  467. // Need to mask off anything but the first bit.
  468. // This comes from LLInventoryFilter from llfolderview.h
  469. U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1;
  470. // *NOTE: For bug EXT-2879, originally commented out
  471. // gAgent.getRegion()->getCapability in order to use the old
  472. // message-based system.  This has been uncommented now that
  473. // AIS folks are aware of the issue and have a fix in process.
  474. // see ticket for details.
  475. std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");
  476. if (!url.empty()) //Capability found.  Build up LLSD and use it.
  477. {
  478. gInventory.startBackgroundFetch(mUUID);
  479. }
  480. else
  481. { //Deprecated, but if we don't have a capability, use the old system.
  482. llinfos << "WebFetchInventoryDescendents capability not found.  Using deprecated UDP message." << llendl;
  483. LLMessageSystem* msg = gMessageSystem;
  484. msg->newMessage("FetchInventoryDescendents");
  485. msg->nextBlock("AgentData");
  486. msg->addUUID("AgentID", gAgent.getID());
  487. msg->addUUID("SessionID", gAgent.getSessionID());
  488. msg->nextBlock("InventoryData");
  489. msg->addUUID("FolderID", mUUID);
  490. msg->addUUID("OwnerID", mOwnerID);
  491. msg->addS32("SortOrder", sort_order);
  492. msg->addBOOL("FetchFolders", FALSE);
  493. msg->addBOOL("FetchItems", TRUE);
  494. gAgent.sendReliableMessage();
  495. }
  496. return true;
  497. }
  498. return false;
  499. }
  500. bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp)
  501. {
  502. // *NOTE: This buffer size is hard coded into scanf() below.
  503. char buffer[MAX_STRING]; /* Flawfinder: ignore */
  504. char keyword[MAX_STRING]; /* Flawfinder: ignore */
  505. char valuestr[MAX_STRING]; /* Flawfinder: ignore */
  506. keyword[0] = '';
  507. valuestr[0] = '';
  508. while(!feof(fp))
  509. {
  510. if (fgets(buffer, MAX_STRING, fp) == NULL)
  511. {
  512. buffer[0] = '';
  513. }
  514. sscanf( /* Flawfinder: ignore */
  515. buffer, " %254s %254s", keyword, valuestr); 
  516. if(0 == strcmp("{",keyword))
  517. {
  518. continue;
  519. }
  520. if(0 == strcmp("}", keyword))
  521. {
  522. break;
  523. }
  524. else if(0 == strcmp("cat_id", keyword))
  525. {
  526. mUUID.set(valuestr);
  527. }
  528. else if(0 == strcmp("parent_id", keyword))
  529. {
  530. mParentUUID.set(valuestr);
  531. }
  532. else if(0 == strcmp("type", keyword))
  533. {
  534. mType = LLAssetType::lookup(valuestr);
  535. }
  536. else if(0 == strcmp("pref_type", keyword))
  537. {
  538. mPreferredType = LLFolderType::lookup(valuestr);
  539. }
  540. else if(0 == strcmp("name", keyword))
  541. {
  542. //strcpy(valuestr, buffer + strlen(keyword) + 3);
  543. // *NOTE: Not ANSI C, but widely supported.
  544. sscanf( /* Flawfinder: ignore */
  545. buffer, " %254s %254[^|]", keyword, valuestr);
  546. mName.assign(valuestr);
  547. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  548. LLStringUtil::replaceChar(mName, '|', ' ');
  549. }
  550. else if(0 == strcmp("owner_id", keyword))
  551. {
  552. mOwnerID.set(valuestr);
  553. }
  554. else if(0 == strcmp("version", keyword))
  555. {
  556. sscanf(valuestr, "%d", &mVersion);
  557. }
  558. else
  559. {
  560. llwarns << "unknown keyword '" << keyword
  561. << "' in inventory import category "  << mUUID << llendl;
  562. }
  563. }
  564. return true;
  565. }
  566. bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const
  567. {
  568. std::string uuid_str;
  569. fprintf(fp, "tinv_categoryt0nt{n");
  570. mUUID.toString(uuid_str);
  571. fprintf(fp, "ttcat_idt%sn", uuid_str.c_str());
  572. mParentUUID.toString(uuid_str);
  573. fprintf(fp, "ttparent_idt%sn", uuid_str.c_str());
  574. fprintf(fp, "tttypet%sn", LLAssetType::lookup(mType));
  575. fprintf(fp, "ttpref_typet%sn", LLFolderType::lookup(mPreferredType).c_str());
  576. fprintf(fp, "ttnamet%s|n", mName.c_str());
  577. mOwnerID.toString(uuid_str);
  578. fprintf(fp, "ttowner_idt%sn", uuid_str.c_str());
  579. fprintf(fp, "ttversiont%dn", mVersion);
  580. fprintf(fp,"t}n");
  581. return true;
  582. }
  583. void LLViewerInventoryCategory::determineFolderType()
  584. {
  585. /* Do NOT uncomment this code.  This is for future 2.1 support of ensembles.
  586. llassert(FALSE);
  587. LLFolderType::EType original_type = getPreferredType();
  588. if (LLFolderType::lookupIsProtectedType(original_type))
  589. return;
  590. U64 folder_valid = 0;
  591. U64 folder_invalid = 0;
  592. LLInventoryModel::cat_array_t category_array;
  593. LLInventoryModel::item_array_t item_array;
  594. gInventory.collectDescendents(getUUID(),category_array,item_array,FALSE);
  595. // For ensembles
  596. if (category_array.empty())
  597. {
  598. for (LLInventoryModel::item_array_t::iterator item_iter = item_array.begin();
  599.  item_iter != item_array.end();
  600.  item_iter++)
  601. {
  602. const LLViewerInventoryItem *item = (*item_iter);
  603. if (item->getIsLinkType())
  604. return;
  605. if (item->isWearableType())
  606. {
  607. const EWearableType wearable_type = item->getWearableType();
  608. const std::string& wearable_name = LLWearableDictionary::getTypeName(wearable_type);
  609. U64 valid_folder_types = LLViewerFolderType::lookupValidFolderTypes(wearable_name);
  610. folder_valid |= valid_folder_types;
  611. folder_invalid |= ~valid_folder_types;
  612. }
  613. }
  614. for (U8 i = LLFolderType::FT_ENSEMBLE_START; i <= LLFolderType::FT_ENSEMBLE_END; i++)
  615. {
  616. if ((folder_valid & (1LL << i)) &&
  617. !(folder_invalid & (1LL << i)))
  618. {
  619. changeType((LLFolderType::EType)i);
  620. return;
  621. }
  622. }
  623. }
  624. if (LLFolderType::lookupIsEnsembleType(original_type))
  625. {
  626. changeType(LLFolderType::FT_NONE);
  627. }
  628. llassert(FALSE);
  629. */
  630. }
  631. void LLViewerInventoryCategory::changeType(LLFolderType::EType new_folder_type)
  632. {
  633. const LLUUID &folder_id = getUUID();
  634. const LLUUID &parent_id = getParentUUID();
  635. const std::string &name = getName();
  636. LLMessageSystem* msg = gMessageSystem;
  637. msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
  638. msg->nextBlockFast(_PREHASH_AgentData);
  639. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  640. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  641. msg->nextBlockFast(_PREHASH_FolderData);
  642. msg->addUUIDFast(_PREHASH_FolderID, folder_id);
  643. msg->addUUIDFast(_PREHASH_ParentID, parent_id);
  644. msg->addS8Fast(_PREHASH_Type, new_folder_type);
  645. msg->addStringFast(_PREHASH_Name, name);
  646. gAgent.sendReliableMessage();
  647. setPreferredType(new_folder_type);
  648. gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id);
  649. }
  650. ///----------------------------------------------------------------------------
  651. /// Local function definitions
  652. ///----------------------------------------------------------------------------
  653. LLInventoryCallbackManager *LLInventoryCallbackManager::sInstance = NULL;
  654. LLInventoryCallbackManager::LLInventoryCallbackManager() :
  655. mLastCallback(0)
  656. {
  657. if( sInstance != NULL )
  658. {
  659. llwarns << "LLInventoryCallbackManager::LLInventoryCallbackManager: unexpected multiple instances" << llendl;
  660. return;
  661. }
  662. sInstance = this;
  663. }
  664. LLInventoryCallbackManager::~LLInventoryCallbackManager()
  665. {
  666. if( sInstance != this )
  667. {
  668. llwarns << "LLInventoryCallbackManager::~LLInventoryCallbackManager: unexpected multiple instances" << llendl;
  669. return;
  670. }
  671. sInstance = NULL;
  672. }
  673. U32 LLInventoryCallbackManager::registerCB(LLPointer<LLInventoryCallback> cb)
  674. {
  675. if (cb.isNull())
  676. return 0;
  677. mLastCallback++;
  678. if (!mLastCallback)
  679. mLastCallback++;
  680. mMap[mLastCallback] = cb;
  681. return mLastCallback;
  682. }
  683. void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id)
  684. {
  685. if (!callback_id || item_id.isNull())
  686. return;
  687. std::map<U32, LLPointer<LLInventoryCallback> >::iterator i;
  688. i = mMap.find(callback_id);
  689. if (i != mMap.end())
  690. {
  691. (*i).second->fire(item_id);
  692. mMap.erase(i);
  693. }
  694. }
  695. void WearOnAvatarCallback::fire(const LLUUID& inv_item)
  696. {
  697. if (inv_item.isNull())
  698. return;
  699. LLViewerInventoryItem *item = gInventory.getItem(inv_item);
  700. if (item)
  701. {
  702. wear_inventory_item_on_avatar(item);
  703. }
  704. }
  705. void ModifiedCOFCallback::fire(const LLUUID& inv_item)
  706. {
  707. LLAppearanceManager::instance().updateAppearanceFromCOF();
  708. if( CAMERA_MODE_CUSTOMIZE_AVATAR == gAgent.getCameraMode() )
  709. {
  710. // If we're in appearance editing mode, the current tab may need to be refreshed
  711. if (gFloaterCustomize)
  712. {
  713. gFloaterCustomize->switchToDefaultSubpart();
  714. }
  715. }
  716. }
  717. RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp)
  718. {
  719. mAttach = attachmentp;
  720. }
  721. RezAttachmentCallback::~RezAttachmentCallback()
  722. {
  723. }
  724. void RezAttachmentCallback::fire(const LLUUID& inv_item)
  725. {
  726. if (inv_item.isNull())
  727. return;
  728. LLViewerInventoryItem *item = gInventory.getItem(inv_item);
  729. if (item)
  730. {
  731. rez_attachment(item, mAttach);
  732. }
  733. }
  734. void ActivateGestureCallback::fire(const LLUUID& inv_item)
  735. {
  736. if (inv_item.isNull())
  737. return;
  738. LLGestureManager::instance().activateGesture(inv_item);
  739. }
  740. void CreateGestureCallback::fire(const LLUUID& inv_item)
  741. {
  742. if (inv_item.isNull())
  743. return;
  744. LLGestureManager::instance().activateGesture(inv_item);
  745. LLViewerInventoryItem* item = gInventory.getItem(inv_item);
  746. if (!item) return;
  747.     gInventory.updateItem(item);
  748.     gInventory.notifyObservers();
  749. LLPreviewGesture* preview = LLPreviewGesture::show(inv_item,  LLUUID::null);
  750. // Force to be entirely onscreen.
  751. gFloaterView->adjustToFitScreen(preview, FALSE);
  752. }
  753. void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id)
  754. {
  755. if (mTargetLandmarkId.isNull()) return;
  756. gInventory.rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId);
  757. }
  758. LLInventoryCallbackManager gInventoryCallbacks;
  759. void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
  760.    const LLUUID& parent, const LLTransactionID& transaction_id,
  761.    const std::string& name,
  762.    const std::string& desc, LLAssetType::EType asset_type,
  763.    LLInventoryType::EType inv_type, EWearableType wtype,
  764.    U32 next_owner_perm,
  765.    LLPointer<LLInventoryCallback> cb)
  766. {
  767. LLMessageSystem* msg = gMessageSystem;
  768. msg->newMessageFast(_PREHASH_CreateInventoryItem);
  769. msg->nextBlock(_PREHASH_AgentData);
  770. msg->addUUIDFast(_PREHASH_AgentID, agent_id);
  771. msg->addUUIDFast(_PREHASH_SessionID, session_id);
  772. msg->nextBlock(_PREHASH_InventoryBlock);
  773. msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
  774. msg->addUUIDFast(_PREHASH_FolderID, parent);
  775. msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
  776. msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm);
  777. msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
  778. msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
  779. msg->addU8Fast(_PREHASH_WearableType, (U8)wtype);
  780. msg->addStringFast(_PREHASH_Name, name);
  781. msg->addStringFast(_PREHASH_Description, desc);
  782. gAgent.sendReliableMessage();
  783. }
  784. void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer<LLInventoryCallback> cb/*=NULL*/)
  785. {
  786. std::string item_desc = avatar_id.asString();
  787. std::string item_name;
  788. gCacheName->getFullName(avatar_id, item_name);
  789. create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
  790.   parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD,
  791.   LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb);
  792. }
  793. void copy_inventory_item(
  794. const LLUUID& agent_id,
  795. const LLUUID& current_owner,
  796. const LLUUID& item_id,
  797. const LLUUID& parent_id,
  798. const std::string& new_name,
  799. LLPointer<LLInventoryCallback> cb)
  800. {
  801. LLMessageSystem* msg = gMessageSystem;
  802. msg->newMessageFast(_PREHASH_CopyInventoryItem);
  803. msg->nextBlockFast(_PREHASH_AgentData);
  804. msg->addUUIDFast(_PREHASH_AgentID, agent_id);
  805. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  806. msg->nextBlockFast(_PREHASH_InventoryData);
  807. msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
  808. msg->addUUIDFast(_PREHASH_OldAgentID, current_owner);
  809. msg->addUUIDFast(_PREHASH_OldItemID, item_id);
  810. msg->addUUIDFast(_PREHASH_NewFolderID, parent_id);
  811. msg->addStringFast(_PREHASH_NewName, new_name);
  812. gAgent.sendReliableMessage();
  813. }
  814. void link_inventory_item(
  815. const LLUUID& agent_id,
  816. const LLUUID& item_id,
  817. const LLUUID& parent_id,
  818. const std::string& new_name,
  819. const LLAssetType::EType asset_type,
  820. LLPointer<LLInventoryCallback> cb)
  821. {
  822. const LLInventoryObject *baseobj = gInventory.getObject(item_id);
  823. if (!baseobj)
  824. {
  825. llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl;
  826. return;
  827. }
  828. if (baseobj && baseobj->getIsLinkType())
  829. {
  830. llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl;
  831. return;
  832. }
  833. if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType()))
  834. {
  835. // Fail if item can be found but is of a type that can't be linked.
  836. // Arguably should fail if the item can't be found too, but that could
  837. // be a larger behavioral change.
  838. llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl;
  839. return;
  840. }
  841. LLUUID transaction_id;
  842. std::string desc = "Broken link"; // This should only show if the object can't find its baseobj.
  843. LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
  844. if (dynamic_cast<const LLInventoryCategory *>(baseobj))
  845. {
  846. inv_type = LLInventoryType::IT_CATEGORY;
  847. }
  848. else
  849. {
  850. const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj);
  851. if (baseitem)
  852. {
  853. inv_type = baseitem->getInventoryType();
  854. }
  855. }
  856. LLMessageSystem* msg = gMessageSystem;
  857. msg->newMessageFast(_PREHASH_LinkInventoryItem);
  858. msg->nextBlock(_PREHASH_AgentData);
  859. {
  860. msg->addUUIDFast(_PREHASH_AgentID, agent_id);
  861. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  862. }
  863. msg->nextBlock(_PREHASH_InventoryBlock);
  864. {
  865. msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
  866. msg->addUUIDFast(_PREHASH_FolderID, parent_id);
  867. msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
  868. msg->addUUIDFast(_PREHASH_OldItemID, item_id);
  869. msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
  870. msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
  871. msg->addStringFast(_PREHASH_Name, new_name);
  872. msg->addStringFast(_PREHASH_Description, desc);
  873. }
  874. gAgent.sendReliableMessage();
  875. }
  876. void move_inventory_item(
  877. const LLUUID& agent_id,
  878. const LLUUID& session_id,
  879. const LLUUID& item_id,
  880. const LLUUID& parent_id,
  881. const std::string& new_name,
  882. LLPointer<LLInventoryCallback> cb)
  883. {
  884. LLMessageSystem* msg = gMessageSystem;
  885. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  886. msg->nextBlockFast(_PREHASH_AgentData);
  887. msg->addUUIDFast(_PREHASH_AgentID, agent_id);
  888. msg->addUUIDFast(_PREHASH_SessionID, session_id);
  889. msg->addBOOLFast(_PREHASH_Stamp, FALSE);
  890. msg->nextBlockFast(_PREHASH_InventoryData);
  891. msg->addUUIDFast(_PREHASH_ItemID, item_id);
  892. msg->addUUIDFast(_PREHASH_FolderID, parent_id);
  893. msg->addStringFast(_PREHASH_NewName, new_name);
  894. gAgent.sendReliableMessage();
  895. }
  896. void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecard_inv_id, const LLInventoryItem *src, U32 callback_id)
  897. {
  898. LLViewerRegion* viewer_region = NULL;
  899.     LLViewerObject* vo = NULL;
  900. if (object_id.notNull() && (vo = gObjectList.findObject(object_id)) != NULL)
  901.     {
  902.         viewer_region = vo->getRegion();
  903. }
  904. // Fallback to the agents region if for some reason the 
  905. // object isn't found in the viewer.
  906. if (! viewer_region)
  907. {
  908. viewer_region = gAgent.getRegion();
  909. }
  910. if (! viewer_region)
  911. {
  912.         LL_WARNS("copy_inventory_from_notecard") << "Can't find region from object_id "
  913.                                                  << object_id << " or gAgent"
  914.                                                  << LL_ENDL;
  915.         return;
  916.     }
  917.     LLSD request, body;
  918.     body["notecard-id"] = notecard_inv_id;
  919.     body["object-id"] = object_id;
  920.     body["item-id"] = src->getUUID();
  921. body["folder-id"] = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(src->getType()));
  922.     body["callback-id"] = (LLSD::Integer)callback_id;
  923.     request["message"] = "CopyInventoryFromNotecard";
  924.     request["payload"] = body;
  925.     viewer_region->getCapAPI().post(request);
  926. }
  927. void create_new_item(const std::string& name,
  928.    const LLUUID& parent_id,
  929.    LLAssetType::EType asset_type,
  930.    LLInventoryType::EType inv_type,
  931.    U32 next_owner_perm)
  932. {
  933. std::string desc;
  934. LLViewerAssetType::generateDescriptionFor(asset_type, desc);
  935. next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER;
  936. if (inv_type == LLInventoryType::IT_GESTURE)
  937. {
  938. LLPointer<LLInventoryCallback> cb = new CreateGestureCallback();
  939. create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
  940.   parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type,
  941.   NOT_WEARABLE, next_owner_perm, cb);
  942. }
  943. else
  944. {
  945. LLPointer<LLInventoryCallback> cb = NULL;
  946. create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
  947.   parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type,
  948.   NOT_WEARABLE, next_owner_perm, cb);
  949. }
  950. }
  951. const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)
  952. const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)
  953. const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not)
  954. // ! REFACTOR ! Really need to refactor this so that it's not a bunch of if-then statements...
  955. void menu_create_inventory_item(LLFolderView* folder, LLFolderBridge *bridge, const LLSD& userdata, const LLUUID& default_parent_uuid)
  956. {
  957. std::string type_name = userdata.asString();
  958. if (("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name))
  959. {
  960. LLFolderType::EType preferred_type = LLFolderType::lookup(type_name);
  961. LLUUID parent_id;
  962. if (bridge)
  963. {
  964. parent_id = bridge->getUUID();
  965. }
  966. else if (default_parent_uuid.notNull())
  967. {
  968. parent_id = default_parent_uuid;
  969. }
  970. else
  971. {
  972. parent_id = gInventory.getRootFolderID();
  973. }
  974. LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null);
  975. gInventory.notifyObservers();
  976. folder->setSelectionByID(category, TRUE);
  977. }
  978. else if ("lsl" == type_name)
  979. {
  980. const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
  981. create_new_item(NEW_LSL_NAME,
  982.   parent_id,
  983.   LLAssetType::AT_LSL_TEXT,
  984.   LLInventoryType::IT_LSL,
  985.   PERM_MOVE | PERM_TRANSFER);
  986. }
  987. else if ("notecard" == type_name)
  988. {
  989. const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
  990. create_new_item(NEW_NOTECARD_NAME,
  991.   parent_id,
  992.   LLAssetType::AT_NOTECARD,
  993.   LLInventoryType::IT_NOTECARD,
  994.   PERM_ALL);
  995. }
  996. else if ("gesture" == type_name)
  997. {
  998. const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
  999. create_new_item(NEW_GESTURE_NAME,
  1000.   parent_id,
  1001.   LLAssetType::AT_GESTURE,
  1002.   LLInventoryType::IT_GESTURE,
  1003.   PERM_ALL);
  1004. }
  1005. else
  1006. {
  1007. // Use for all clothing and body parts.  Adding new wearable types requires updating LLWearableDictionary.
  1008. EWearableType wearable_type = LLWearableDictionary::typeNameToType(type_name);
  1009. if (wearable_type >= WT_SHAPE && wearable_type < WT_COUNT)
  1010. {
  1011. LLAssetType::EType asset_type = LLWearableDictionary::getAssetType(wearable_type);
  1012. LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type);
  1013. const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(folder_type);
  1014. LLFolderBridge::createWearable(parent_id, wearable_type);
  1015. }
  1016. else
  1017. {
  1018. llwarns << "Can't create unrecognized type " << type_name << llendl;
  1019. }
  1020. }
  1021. folder->setNeedsAutoRename(TRUE);
  1022. }
  1023. LLAssetType::EType LLViewerInventoryItem::getType() const
  1024. {
  1025. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1026. {
  1027. return linked_item->getType();
  1028. }
  1029. if (const LLViewerInventoryCategory *linked_category = getLinkedCategory())
  1030. {
  1031. return linked_category->getType();
  1032. }
  1033. return LLInventoryItem::getType();
  1034. }
  1035. const LLUUID& LLViewerInventoryItem::getAssetUUID() const
  1036. {
  1037. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1038. {
  1039. return linked_item->getAssetUUID();
  1040. }
  1041. return LLInventoryItem::getAssetUUID();
  1042. }
  1043. const std::string& LLViewerInventoryItem::getName() const
  1044. {
  1045. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1046. {
  1047. return linked_item->getName();
  1048. }
  1049. if (const LLViewerInventoryCategory *linked_category = getLinkedCategory())
  1050. {
  1051. return linked_category->getName();
  1052. }
  1053. return  LLInventoryItem::getName();
  1054. }
  1055. /**
  1056.  * Class to store sorting order of favorites landmarks in a local file. EXT-3985.
  1057.  * It replaced previously implemented solution to store sort index in landmark's name as a "<N>@" prefix.
  1058.  * Data are stored in user home directory.
  1059.  */
  1060. class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage>
  1061. , public LLDestroyClass<LLFavoritesOrderStorage>
  1062. {
  1063. public:
  1064. /**
  1065.  * Sets sort index for specified with LLUUID favorite landmark
  1066.  */
  1067. void setSortIndex(const LLUUID& inv_item_id, S32 sort_index);
  1068. /**
  1069.  * Gets sort index for specified with LLUUID favorite landmark
  1070.  */
  1071. S32 getSortIndex(const LLUUID& inv_item_id);
  1072. void removeSortIndex(const LLUUID& inv_item_id);
  1073. /**
  1074.  * Implementation of LLDestroyClass. Calls cleanup() instance method.
  1075.  *
  1076.  * It is important this callback is called before gInventory is cleaned.
  1077.  * For now it is called from LLAppViewer::cleanup() -> LLAppViewer::disconnectViewer(),
  1078.  * Inventory is cleaned later from LLAppViewer::cleanup() after LLAppViewer::disconnectViewer() is called.
  1079.  * @see cleanup()
  1080.  */
  1081. static void destroyClass();
  1082. const static S32 NO_INDEX;
  1083. private:
  1084. friend class LLSingleton<LLFavoritesOrderStorage>;
  1085. LLFavoritesOrderStorage() : mIsDirty(false) { load(); }
  1086. ~LLFavoritesOrderStorage() { save(); }
  1087. /**
  1088.  * Removes sort indexes for items which are not in Favorites bar for now.
  1089.  */
  1090. void cleanup();
  1091. const static std::string SORTING_DATA_FILE_NAME;
  1092. void load();
  1093. void save();
  1094. typedef std::map<LLUUID, S32> sort_index_map_t;
  1095. sort_index_map_t mSortIndexes;
  1096. bool mIsDirty;
  1097. struct IsNotInFavorites
  1098. {
  1099. IsNotInFavorites(const LLInventoryModel::item_array_t& items)
  1100. : mFavoriteItems(items)
  1101. {
  1102. }
  1103. /**
  1104.  * Returns true if specified item is not found among inventory items
  1105.  */
  1106. bool operator()(const sort_index_map_t::value_type& id_index_pair) const
  1107. {
  1108. LLPointer<LLViewerInventoryItem> item = gInventory.getItem(id_index_pair.first);
  1109. if (item.isNull()) return true;
  1110. LLInventoryModel::item_array_t::const_iterator found_it =
  1111. std::find(mFavoriteItems.begin(), mFavoriteItems.end(), item);
  1112. return found_it == mFavoriteItems.end();
  1113. }
  1114. private:
  1115. LLInventoryModel::item_array_t mFavoriteItems;
  1116. };
  1117. };
  1118. const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml";
  1119. const S32 LLFavoritesOrderStorage::NO_INDEX = -1;
  1120. void LLFavoritesOrderStorage::setSortIndex(const LLUUID& inv_item_id, S32 sort_index)
  1121. {
  1122. mSortIndexes[inv_item_id] = sort_index;
  1123. mIsDirty = true;
  1124. }
  1125. S32 LLFavoritesOrderStorage::getSortIndex(const LLUUID& inv_item_id)
  1126. {
  1127. sort_index_map_t::const_iterator it = mSortIndexes.find(inv_item_id);
  1128. if (it != mSortIndexes.end())
  1129. {
  1130. return it->second;
  1131. }
  1132. return NO_INDEX;
  1133. }
  1134. void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id)
  1135. {
  1136. mSortIndexes.erase(inv_item_id);
  1137. mIsDirty = true;
  1138. }
  1139. // static
  1140. void LLFavoritesOrderStorage::destroyClass()
  1141. {
  1142. LLFavoritesOrderStorage::instance().cleanup();
  1143. }
  1144. void LLFavoritesOrderStorage::load()
  1145. {
  1146. // load per-resident sorting information
  1147. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME);
  1148. LLSD settings_llsd;
  1149. llifstream file;
  1150. file.open(filename);
  1151. if (file.is_open())
  1152. {
  1153. LLSDSerialize::fromXML(settings_llsd, file);
  1154. }
  1155. for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
  1156. iter != settings_llsd.endMap(); ++iter)
  1157. {
  1158. mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger()));
  1159. }
  1160. }
  1161. void LLFavoritesOrderStorage::save()
  1162. {
  1163. // nothing to save if clean
  1164. if (!mIsDirty) return;
  1165. // If we quit from the login screen we will not have an SL account
  1166. // name.  Don't try to save, otherwise we'll dump a file in
  1167. // C:Program FilesSecondLife or similar. JC
  1168. std::string user_dir = gDirUtilp->getLindenUserDir();
  1169. if (!user_dir.empty())
  1170. {
  1171. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME);
  1172. LLSD settings_llsd;
  1173. for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter)
  1174. {
  1175. settings_llsd[iter->first.asString()] = iter->second;
  1176. }
  1177. llofstream file;
  1178. file.open(filename);
  1179. LLSDSerialize::toPrettyXML(settings_llsd, file);
  1180. }
  1181. }
  1182. void LLFavoritesOrderStorage::cleanup()
  1183. {
  1184. // nothing to clean
  1185. if (!mIsDirty) return;
  1186. const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
  1187. LLInventoryModel::cat_array_t cats;
  1188. LLInventoryModel::item_array_t items;
  1189. gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
  1190. IsNotInFavorites is_not_in_fav(items);
  1191. sort_index_map_t  aTempMap;
  1192. //copy unremoved values from mSortIndexes to aTempMap
  1193. std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), 
  1194. inserter(aTempMap, aTempMap.begin()),
  1195. is_not_in_fav);
  1196. //Swap the contents of mSortIndexes and aTempMap
  1197. mSortIndexes.swap(aTempMap);
  1198. }
  1199. S32 LLViewerInventoryItem::getSortField() const
  1200. {
  1201. return LLFavoritesOrderStorage::instance().getSortIndex(mUUID);
  1202. }
  1203. void LLViewerInventoryItem::setSortField(S32 sortField)
  1204. {
  1205. LLFavoritesOrderStorage::instance().setSortIndex(mUUID, sortField);
  1206. }
  1207. const LLPermissions& LLViewerInventoryItem::getPermissions() const
  1208. {
  1209. // Use the actual permissions of the symlink, not its parent.
  1210. return LLInventoryItem::getPermissions();
  1211. }
  1212. const LLUUID& LLViewerInventoryItem::getCreatorUUID() const
  1213. {
  1214. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1215. {
  1216. return linked_item->getCreatorUUID();
  1217. }
  1218. return LLInventoryItem::getCreatorUUID();
  1219. }
  1220. const std::string& LLViewerInventoryItem::getDescription() const
  1221. {
  1222. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1223. {
  1224. return linked_item->getDescription();
  1225. }
  1226. return LLInventoryItem::getDescription();
  1227. }
  1228. const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const
  1229. {
  1230. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1231. {
  1232. return linked_item->getSaleInfo();
  1233. }
  1234. return LLInventoryItem::getSaleInfo();
  1235. }
  1236. LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
  1237. {
  1238. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1239. {
  1240. return linked_item->getInventoryType();
  1241. }
  1242. // Categories don't have types.  If this item is an AT_FOLDER_LINK,
  1243. // treat it as a category.
  1244. if (getLinkedCategory())
  1245. {
  1246. return LLInventoryType::IT_CATEGORY;
  1247. }
  1248. return LLInventoryItem::getInventoryType();
  1249. }
  1250. U32 LLViewerInventoryItem::getFlags() const
  1251. {
  1252. if (const LLViewerInventoryItem *linked_item = getLinkedItem())
  1253. {
  1254. return linked_item->getFlags();
  1255. }
  1256. return LLInventoryItem::getFlags();
  1257. }
  1258. bool LLViewerInventoryItem::isWearableType() const
  1259. {
  1260. return (getInventoryType() == LLInventoryType::IT_WEARABLE);
  1261. }
  1262. EWearableType LLViewerInventoryItem::getWearableType() const
  1263. {
  1264. if (!isWearableType())
  1265. {
  1266. llwarns << "item is not a wearable" << llendl;
  1267. return WT_INVALID;
  1268. }
  1269. return EWearableType(getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK);
  1270. }
  1271. time_t LLViewerInventoryItem::getCreationDate() const
  1272. {
  1273. return LLInventoryItem::getCreationDate();
  1274. }
  1275. U32 LLViewerInventoryItem::getCRC32() const
  1276. {
  1277. return LLInventoryItem::getCRC32();
  1278. }
  1279. // *TODO: mantipov: should be removed with LMSortPrefix patch in llinventorymodel.cpp, EXT-3985
  1280. static char getSeparator() { return '@'; }
  1281. BOOL LLViewerInventoryItem::extractSortFieldAndDisplayName(const std::string& name, S32* sortField, std::string* displayName)
  1282. {
  1283. using std::string;
  1284. using std::stringstream;
  1285. const char separator = getSeparator();
  1286. const string::size_type separatorPos = name.find(separator, 0);
  1287. BOOL result = FALSE;
  1288. if (separatorPos < string::npos)
  1289. {
  1290. if (sortField)
  1291. {
  1292. /*
  1293.  * The conversion from string to S32 is made this way instead of old plain
  1294.  * atoi() to ensure portability. If on some other platform S32 will not be
  1295.  * defined to be signed int, this conversion will still work because of
  1296.  * operators overloading, but atoi() may fail.
  1297.  */
  1298. stringstream ss(name.substr(0, separatorPos));
  1299. ss >> *sortField;
  1300. }
  1301. if (displayName)
  1302. {
  1303. *displayName = name.substr(separatorPos + 1, string::npos);
  1304. }
  1305. result = TRUE;
  1306. }
  1307. return result;
  1308. }
  1309. // This returns true if the item that this item points to 
  1310. // doesn't exist in memory (i.e. LLInventoryModel).  The baseitem
  1311. // might still be in the database but just not loaded yet.
  1312. bool LLViewerInventoryItem::getIsBrokenLink() const
  1313. {
  1314. // If the item's type resolves to be a link, that means either:
  1315. // A. It wasn't able to perform indirection, i.e. the baseobj doesn't exist in memory.
  1316. // B. It's pointing to another link, which is illegal.
  1317. return LLAssetType::lookupIsLinkType(getType());
  1318. }
  1319. LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const
  1320. {
  1321. if (mType == LLAssetType::AT_LINK)
  1322. {
  1323. LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
  1324. if (linked_item && linked_item->getIsLinkType())
  1325. {
  1326. llwarns << "Warning: Accessing link to link" << llendl;
  1327. return NULL;
  1328. }
  1329. return linked_item;
  1330. }
  1331. return NULL;
  1332. }
  1333. LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const
  1334. {
  1335. if (mType == LLAssetType::AT_LINK_FOLDER)
  1336. {
  1337. LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID);
  1338. return linked_category;
  1339. }
  1340. return NULL;
  1341. }
  1342. bool LLViewerInventoryItem::checkPermissionsSet(PermissionMask mask) const
  1343. {
  1344. const LLPermissions& perm = getPermissions();
  1345. PermissionMask curr_mask = PERM_NONE;
  1346. if(perm.getOwner() == gAgent.getID())
  1347. {
  1348. curr_mask = perm.getMaskBase();
  1349. }
  1350. else if(gAgent.isInGroup(perm.getGroup()))
  1351. {
  1352. curr_mask = perm.getMaskGroup();
  1353. }
  1354. else
  1355. {
  1356. curr_mask = perm.getMaskEveryone();
  1357. }
  1358. return ((curr_mask & mask) == mask);
  1359. }
  1360. //----------
  1361. void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name)
  1362. {
  1363. rename(first_name + " " + last_name);
  1364. gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID());
  1365. gInventory.notifyObservers();
  1366. }
  1367. class LLRegenerateLinkCollector : public LLInventoryCollectFunctor
  1368. {
  1369. public:
  1370. LLRegenerateLinkCollector(const LLViewerInventoryItem *target_item) : mTargetItem(target_item) {}
  1371. virtual ~LLRegenerateLinkCollector() {}
  1372. virtual bool operator()(LLInventoryCategory* cat,
  1373. LLInventoryItem* item)
  1374. {
  1375. if (item)
  1376. {
  1377. if ((item->getName() == mTargetItem->getName()) &&
  1378. (item->getInventoryType() == mTargetItem->getInventoryType()) &&
  1379. (!item->getIsLinkType()))
  1380. {
  1381. return true;
  1382. }
  1383. }
  1384. return false;
  1385. }
  1386. protected:
  1387. const LLViewerInventoryItem* mTargetItem;
  1388. };
  1389. LLUUID find_possible_item_for_regeneration(const LLViewerInventoryItem *target_item)
  1390. {
  1391. LLViewerInventoryCategory::cat_array_t cats;
  1392. LLViewerInventoryItem::item_array_t items;
  1393. LLRegenerateLinkCollector candidate_matches(target_item);
  1394. gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
  1395. cats,
  1396. items,
  1397. LLInventoryModel::EXCLUDE_TRASH,
  1398. candidate_matches);
  1399. for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items.begin();
  1400.  item_iter != items.end();
  1401.  ++item_iter)
  1402. {
  1403.     const LLViewerInventoryItem *item = (*item_iter);
  1404. if (true) return item->getUUID();
  1405. }
  1406. return LLUUID::null;
  1407. }
  1408. // This currently dosen't work, because the sim does not allow us 
  1409. // to change an item's assetID.
  1410. BOOL LLViewerInventoryItem::regenerateLink()
  1411. {
  1412. const LLUUID target_item_id = find_possible_item_for_regeneration(this);
  1413. if (target_item_id.isNull())
  1414. return FALSE;
  1415. LLViewerInventoryCategory::cat_array_t cats;
  1416. LLViewerInventoryItem::item_array_t items;
  1417. LLAssetIDMatches asset_id_matches(getAssetUUID());
  1418. gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
  1419. cats,
  1420. items,
  1421. LLInventoryModel::EXCLUDE_TRASH,
  1422. asset_id_matches);
  1423. for (LLViewerInventoryItem::item_array_t::iterator item_iter = items.begin();
  1424.  item_iter != items.end();
  1425.  item_iter++)
  1426. {
  1427.     LLViewerInventoryItem *item = (*item_iter);
  1428. item->setAssetUUID(target_item_id);
  1429. item->updateServer(FALSE);
  1430. gInventory.addChangedMask(LLInventoryObserver::REBUILD, item->getUUID());
  1431. }
  1432. gInventory.notifyObservers();
  1433. return TRUE;
  1434. }