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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llfriendcard.cpp
  3.  * @brief Implementation of classes to process Friends Cards
  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 "llinventory.h"
  34. #include "llinventoryobserver.h"
  35. #include "lltrans.h"
  36. #include "llfriendcard.h"
  37. #include "llcallingcard.h" // for LLAvatarTracker
  38. #include "llviewerinventory.h"
  39. #include "llinventorymodel.h"
  40. // Constants;
  41. static const std::string INVENTORY_STRING_FRIENDS_SUBFOLDER = "InvFolder Friends";
  42. static const std::string INVENTORY_STRING_FRIENDS_ALL_SUBFOLDER = "InvFolder All";
  43. // helper functions
  44. // NOTE: Usage of LLTrans::getString(); in next two functions to set localized
  45. // folders' names is caused by a hack in the LLFolderViewItem::refreshFromListener()
  46. // method for protected asset types.
  47. // So, localized names will be got from the strings with "InvFolder LABEL_NAME"
  48. // in the strings.xml
  49. inline const std::string get_friend_folder_name()
  50. {
  51. return LLTrans::getString(INVENTORY_STRING_FRIENDS_SUBFOLDER);
  52. }
  53. inline const std::string get_friend_all_subfolder_name()
  54. {
  55. return LLTrans::getString(INVENTORY_STRING_FRIENDS_ALL_SUBFOLDER);
  56. }
  57. void move_from_to_arrays(LLInventoryModel::cat_array_t& from, LLInventoryModel::cat_array_t& to)
  58. {
  59. while (from.count() > 0)
  60. {
  61. to.put(from.get(0));
  62. from.remove(0);
  63. }
  64. }
  65. const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollectFunctor& matchFunctor)
  66. {
  67. LLInventoryModel::cat_array_t cats;
  68. LLInventoryModel::item_array_t items;
  69. gInventory.collectDescendentsIf(parentFolderUUID, cats, items,
  70. LLInventoryModel::EXCLUDE_TRASH, matchFunctor);
  71. S32 cats_count = cats.count();
  72. if (cats_count > 1)
  73. {
  74. LL_WARNS("LLFriendCardsManager")
  75. << "There is more than one Friend card folder."
  76. << "The first folder will be used."
  77. << LL_ENDL;
  78. }
  79. return (cats_count >= 1) ? cats.get(0)->getUUID() : LLUUID::null;
  80. }
  81. /**
  82.  * Class for fetching initial friend cards data
  83.  *
  84.  * Implemented to fix an issue when Inventory folders are in incomplete state.
  85.  * See EXT-2320, EXT-2061, EXT-1935, EXT-813.
  86.  * Uses a callback to sync Inventory Friends/All folder with agent's Friends List.
  87.  */
  88. class LLInitialFriendCardsFetch : public LLInventoryFetchDescendentsObserver
  89. {
  90. public:
  91. typedef boost::function<void()> callback_t;
  92. LLInitialFriendCardsFetch(callback_t cb)
  93. : mCheckFolderCallback(cb) {}
  94. /* virtual */ void done();
  95. private:
  96. callback_t mCheckFolderCallback;
  97. };
  98. void LLInitialFriendCardsFetch::done()
  99. {
  100. // This observer is no longer needed.
  101. gInventory.removeObserver(this);
  102. mCheckFolderCallback();
  103. delete this;
  104. }
  105. // LLFriendCardsManager Constructor / Destructor
  106. LLFriendCardsManager::LLFriendCardsManager()
  107. {
  108. LLAvatarTracker::instance().addObserver(this);
  109. }
  110. LLFriendCardsManager::~LLFriendCardsManager()
  111. {
  112. LLAvatarTracker::instance().removeObserver(this);
  113. }
  114. void LLFriendCardsManager::putAvatarData(const LLUUID& avatarID)
  115. {
  116. llinfos << "Store avatar data, avatarID: " << avatarID << llendl;
  117. std::pair< avatar_uuid_set_t::iterator, bool > pr;
  118. pr = mBuddyIDSet.insert(avatarID);
  119. if (pr.second == false)
  120. {
  121. llwarns << "Trying to add avatar UUID for the stored avatar: " 
  122. << avatarID
  123. << llendl;
  124. }
  125. }
  126. const LLUUID LLFriendCardsManager::extractAvatarID(const LLUUID& avatarID)
  127. {
  128. LLUUID rv;
  129. avatar_uuid_set_t::iterator it = mBuddyIDSet.find(avatarID);
  130. if (mBuddyIDSet.end() == it)
  131. {
  132. llwarns << "Call method for non-existent avatar name in the map: " << avatarID << llendl;
  133. }
  134. else
  135. {
  136. rv = (*it);
  137. mBuddyIDSet.erase(it);
  138. }
  139. return rv;
  140. }
  141. bool LLFriendCardsManager::isItemInAnyFriendsList(const LLViewerInventoryItem* item)
  142. {
  143. if (item->getType() != LLAssetType::AT_CALLINGCARD)
  144. return false;
  145. LLInventoryModel::item_array_t items;
  146. findMatchedFriendCards(item->getCreatorUUID(), items);
  147. return items.count() > 0;
  148. }
  149. bool LLFriendCardsManager::isObjDirectDescendentOfCategory(const LLInventoryObject* obj, 
  150. const LLViewerInventoryCategory* cat) const
  151. {
  152. // we need both params to proceed.
  153. if ( !obj || !cat )
  154. return false;
  155. // Need to check that target category is in the Calling Card/Friends folder. 
  156. // In other case function returns unpredictable result.
  157. if ( !isCategoryInFriendFolder(cat) )
  158. return false;
  159. bool result = false;
  160. LLInventoryModel::item_array_t* items;
  161. LLInventoryModel::cat_array_t* cats;
  162. gInventory.lockDirectDescendentArrays(cat->getUUID(), cats, items);
  163. if ( items )
  164. {
  165. if ( obj->getType() == LLAssetType::AT_CALLINGCARD )
  166. {
  167. // For CALLINGCARD compare items by creator's id, if they are equal assume
  168. // that it is same card and return true. Note: UUID's of compared items
  169. // may be not equal. Also, we already know that obj should be type of LLInventoryItem,
  170. // but in case inventory database is broken check what dynamic_cast returns.
  171. const LLInventoryItem* item = dynamic_cast < const LLInventoryItem* > (obj);
  172. if ( item )
  173. {
  174. LLUUID creator_id = item->getCreatorUUID();
  175. LLViewerInventoryItem* cur_item = NULL;
  176. for ( S32 i = items->count() - 1; i >= 0; --i )
  177. {
  178. cur_item = items->get(i);
  179. if ( creator_id == cur_item->getCreatorUUID() )
  180. {
  181. result = true;
  182. break;
  183. }
  184. }
  185. }
  186. }
  187. else
  188. {
  189. // Else check that items have same type and name.
  190. // Note: UUID's of compared items also may be not equal.
  191. std::string obj_name = obj->getName();
  192. LLViewerInventoryItem* cur_item = NULL;
  193. for ( S32 i = items->count() - 1; i >= 0; --i )
  194. {
  195. cur_item = items->get(i);
  196. if ( obj->getType() != cur_item->getType() )
  197. continue;
  198. if ( obj_name == cur_item->getName() )
  199. {
  200. result = true;
  201. break;
  202. }
  203. }
  204. }
  205. }
  206. if ( !result && cats )
  207. {
  208. // There is no direct descendent in items, so check categories.
  209. // If target obj and descendent category have same type and name
  210. // then return true. Note: UUID's of compared items also may be not equal.
  211. std::string obj_name = obj->getName();
  212. LLViewerInventoryCategory* cur_cat = NULL;
  213. for ( S32 i = cats->count() - 1; i >= 0; --i )
  214. {
  215. cur_cat = cats->get(i);
  216. if ( obj->getType() != cur_cat->getType() )
  217. continue;
  218. if ( obj_name == cur_cat->getName() )
  219. {
  220. result = true;
  221. break;
  222. }
  223. }
  224. }
  225. gInventory.unlockDirectDescendentArrays(cat->getUUID());
  226. return result;
  227. }
  228. bool LLFriendCardsManager::isCategoryInFriendFolder(const LLViewerInventoryCategory* cat) const
  229. {
  230. if (NULL == cat)
  231. return false;
  232. return TRUE == gInventory.isObjectDescendentOf(cat->getUUID(), findFriendFolderUUIDImpl());
  233. }
  234. bool LLFriendCardsManager::isAnyFriendCategory(const LLUUID& catID) const
  235. {
  236. const LLUUID& friendFolderID = findFriendFolderUUIDImpl();
  237. if (catID == friendFolderID)
  238. return true;
  239. return TRUE == gInventory.isObjectDescendentOf(catID, friendFolderID);
  240. }
  241. void LLFriendCardsManager::syncFriendCardsFolders()
  242. {
  243. const LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  244. fetchAndCheckFolderDescendents(callingCardsFolderID,
  245. boost::bind(&LLFriendCardsManager::ensureFriendsFolderExists, this));
  246. }
  247. void LLFriendCardsManager::collectFriendsLists(folderid_buddies_map_t& folderBuddiesMap) const
  248. {
  249. folderBuddiesMap.clear();
  250. LLInventoryModel::cat_array_t* listFolders;
  251. LLInventoryModel::item_array_t* items;
  252. // get folders in the Friend folder. Items should be NULL due to Cards should be in lists.
  253. gInventory.getDirectDescendentsOf(findFriendFolderUUIDImpl(), listFolders, items);
  254. if (NULL == listFolders)
  255. return;
  256. LLInventoryModel::cat_array_t::const_iterator itCats; // to iterate Friend Lists (categories)
  257. LLInventoryModel::item_array_t::const_iterator itBuddy; // to iterate Buddies in each List
  258. LLInventoryModel::cat_array_t* fakeCatsArg;
  259. for (itCats = listFolders->begin(); itCats != listFolders->end(); ++itCats)
  260. {
  261. if (items)
  262. items->clear();
  263. // *HACK: Only Friends/All content will be shown for now
  264. // *TODO: Remove this hack, implement sorting if it will be needded by spec.
  265. if ((*itCats)->getUUID() != findFriendAllSubfolderUUIDImpl())
  266. continue;
  267. gInventory.getDirectDescendentsOf((*itCats)->getUUID(), fakeCatsArg, items);
  268. if (NULL == items)
  269. continue;
  270. std::vector<LLUUID> buddyUUIDs;
  271. for (itBuddy = items->begin(); itBuddy != items->end(); ++itBuddy)
  272. {
  273. buddyUUIDs.push_back((*itBuddy)->getCreatorUUID());
  274. }
  275. folderBuddiesMap.insert(make_pair((*itCats)->getUUID(), buddyUUIDs));
  276. }
  277. }
  278. /************************************************************************/
  279. /* Private Methods                                                 */
  280. /************************************************************************/
  281. const LLUUID& LLFriendCardsManager::findFriendFolderUUIDImpl() const
  282. {
  283. const LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  284. std::string friendFolderName = get_friend_folder_name();
  285. return findChildFolderUUID(callingCardsFolderID, friendFolderName);
  286. }
  287. const LLUUID& LLFriendCardsManager::findFriendAllSubfolderUUIDImpl() const
  288. {
  289. LLUUID friendFolderUUID = findFriendFolderUUIDImpl();
  290. std::string friendAllSubfolderName = get_friend_all_subfolder_name();
  291. return findChildFolderUUID(friendFolderUUID, friendAllSubfolderName);
  292. }
  293. const LLUUID& LLFriendCardsManager::findChildFolderUUID(const LLUUID& parentFolderUUID, const std::string& localizedName) const
  294. {
  295. LLNameCategoryCollector matchFolderFunctor(localizedName);
  296. return get_folder_uuid(parentFolderUUID, matchFolderFunctor);
  297. }
  298. const LLUUID& LLFriendCardsManager::findFriendCardInventoryUUIDImpl(const LLUUID& avatarID)
  299. {
  300. LLUUID friendAllSubfolderUUID = findFriendAllSubfolderUUIDImpl();
  301. LLInventoryModel::cat_array_t cats;
  302. LLInventoryModel::item_array_t items;
  303. LLInventoryModel::item_array_t::const_iterator it;
  304. // it is not necessary to check friendAllSubfolderUUID against NULL. It will be processed by collectDescendents
  305. gInventory.collectDescendents(friendAllSubfolderUUID, cats, items, LLInventoryModel::EXCLUDE_TRASH);
  306. for (it = items.begin(); it != items.end(); ++it)
  307. {
  308. if ((*it)->getCreatorUUID() == avatarID)
  309. return (*it)->getUUID();
  310. }
  311. return LLUUID::null;
  312. }
  313. void LLFriendCardsManager::findMatchedFriendCards(const LLUUID& avatarID, LLInventoryModel::item_array_t& items) const
  314. {
  315. LLInventoryModel::cat_array_t cats;
  316. LLUUID friendFolderUUID = findFriendFolderUUIDImpl();
  317. LLViewerInventoryCategory* friendFolder = gInventory.getCategory(friendFolderUUID);
  318. if (NULL == friendFolder)
  319. return;
  320. LLParticularBuddyCollector matchFunctor(avatarID);
  321. LLInventoryModel::cat_array_t subFolders;
  322. subFolders.push_back(friendFolder);
  323. while (subFolders.count() > 0)
  324. {
  325. LLViewerInventoryCategory* cat = subFolders.get(0);
  326. subFolders.remove(0);
  327. gInventory.collectDescendentsIf(cat->getUUID(), cats, items, 
  328. LLInventoryModel::EXCLUDE_TRASH, matchFunctor);
  329. move_from_to_arrays(cats, subFolders);
  330. }
  331. }
  332. void LLFriendCardsManager::fetchAndCheckFolderDescendents(const LLUUID& folder_id,  callback_t cb)
  333. {
  334. // This instance will be deleted in LLInitialFriendCardsFetch::done().
  335. LLInitialFriendCardsFetch* fetch = new LLInitialFriendCardsFetch(cb);
  336. LLInventoryFetchDescendentsObserver::folder_ref_t folders;
  337. folders.push_back(folder_id);
  338. fetch->fetchDescendents(folders);
  339. if(fetch->isEverythingComplete())
  340. {
  341. // everything is already here - call done.
  342. fetch->done();
  343. }
  344. else
  345. {
  346. // it's all on it's way - add an observer, and the inventory
  347. // will call done for us when everything is here.
  348. gInventory.addObserver(fetch);
  349. }
  350. }
  351. // Make sure LLInventoryModel::buildParentChildMap() has been called before it.
  352. // This method must be called before any actions with friends list.
  353. void LLFriendCardsManager::ensureFriendsFolderExists()
  354. {
  355. const LLUUID calling_cards_folder_ID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  356. // If "Friends" folder exists in "Calling Cards" we should check if "All" sub-folder
  357. // exists in "Friends", otherwise we create it.
  358. LLUUID friends_folder_ID = findFriendFolderUUIDImpl();
  359. if (friends_folder_ID.notNull())
  360. {
  361. fetchAndCheckFolderDescendents(friends_folder_ID,
  362. boost::bind(&LLFriendCardsManager::ensureFriendsAllFolderExists, this));
  363. }
  364. else
  365. {
  366. if (!gInventory.isCategoryComplete(calling_cards_folder_ID))
  367. {
  368. LLViewerInventoryCategory* cat = gInventory.getCategory(calling_cards_folder_ID);
  369. std::string cat_name = cat ? cat->getName() : "unknown";
  370. llwarns << "Failed to find "" << cat_name << "" category descendents in Category Tree." << llendl;
  371. }
  372. friends_folder_ID = gInventory.createNewCategory(calling_cards_folder_ID,
  373. LLFolderType::FT_CALLINGCARD, get_friend_folder_name());
  374. gInventory.createNewCategory(friends_folder_ID,
  375. LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
  376. // Now when we have all needed folders we can sync their contents with buddies list.
  377. syncFriendsFolder();
  378. }
  379. }
  380. // Make sure LLFriendCardsManager::ensureFriendsFolderExists() has been called before it.
  381. void LLFriendCardsManager::ensureFriendsAllFolderExists()
  382. {
  383. LLUUID friends_all_folder_ID = findFriendAllSubfolderUUIDImpl();
  384. if (friends_all_folder_ID.notNull())
  385. {
  386. fetchAndCheckFolderDescendents(friends_all_folder_ID,
  387. boost::bind(&LLFriendCardsManager::syncFriendsFolder, this));
  388. }
  389. else
  390. {
  391. LLUUID friends_folder_ID = findFriendFolderUUIDImpl();
  392. if (!gInventory.isCategoryComplete(friends_folder_ID))
  393. {
  394. LLViewerInventoryCategory* cat = gInventory.getCategory(friends_folder_ID);
  395. std::string cat_name = cat ? cat->getName() : "unknown";
  396. llwarns << "Failed to find "" << cat_name << "" category descendents in Category Tree." << llendl;
  397. }
  398. friends_all_folder_ID = gInventory.createNewCategory(friends_folder_ID,
  399. LLFolderType::FT_CALLINGCARD, get_friend_all_subfolder_name());
  400. // Now when we have all needed folders we can sync their contents with buddies list.
  401. syncFriendsFolder();
  402. }
  403. }
  404. void LLFriendCardsManager::syncFriendsFolder()
  405. {
  406. LLAvatarTracker::buddy_map_t all_buddies;
  407. LLAvatarTracker::instance().copyBuddyList(all_buddies);
  408. // 1. Remove Friend Cards for non-friends
  409. LLInventoryModel::cat_array_t cats;
  410. LLInventoryModel::item_array_t items;
  411. gInventory.collectDescendents(findFriendAllSubfolderUUIDImpl(), cats, items, LLInventoryModel::EXCLUDE_TRASH);
  412. LLInventoryModel::item_array_t::const_iterator it;
  413. for (it = items.begin(); it != items.end(); ++it)
  414. {
  415. lldebugs << "Check if buddy is in list: " << (*it)->getName() << " " << (*it)->getCreatorUUID() << llendl;
  416. if (NULL == get_ptr_in_map(all_buddies, (*it)->getCreatorUUID()))
  417. {
  418. lldebugs << "NONEXISTS, so remove it" << llendl;
  419. removeFriendCardFromInventory((*it)->getCreatorUUID());
  420. }
  421. }
  422. // 2. Add missing Friend Cards for friends
  423. LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin();
  424. llinfos << "try to build friends, count: " << all_buddies.size() << llendl;
  425. for(; buddy_it != all_buddies.end(); ++buddy_it)
  426. {
  427. const LLUUID& buddy_id = (*buddy_it).first;
  428. addFriendCardToInventory(buddy_id);
  429. }
  430. }
  431. class CreateFriendCardCallback : public LLInventoryCallback
  432. {
  433. public:
  434. void fire(const LLUUID& inv_item_id)
  435. {
  436. LLViewerInventoryItem* item = gInventory.getItem(inv_item_id);
  437. if (item)
  438. LLFriendCardsManager::instance().extractAvatarID(item->getCreatorUUID());
  439. }
  440. };
  441. void LLFriendCardsManager::addFriendCardToInventory(const LLUUID& avatarID)
  442. {
  443. bool shouldBeAdded = true;
  444. std::string name;
  445. gCacheName->getFullName(avatarID, name);
  446. lldebugs << "Processing buddy name: " << name 
  447. << ", id: " << avatarID
  448. << llendl; 
  449. if (shouldBeAdded && findFriendCardInventoryUUIDImpl(avatarID).notNull())
  450. {
  451. shouldBeAdded = false;
  452. lldebugs << "is found in Inventory: " << name << llendl; 
  453. }
  454. if (shouldBeAdded && isAvatarDataStored(avatarID))
  455. {
  456. shouldBeAdded = false;
  457. lldebugs << "is found in sentRequests: " << name << llendl; 
  458. }
  459. if (shouldBeAdded)
  460. {
  461. putAvatarData(avatarID);
  462. lldebugs << "Sent create_inventory_item for " << avatarID << ", " << name << llendl;
  463. // TODO: mantipov: Is CreateFriendCardCallback really needed? Probably not
  464. LLPointer<LLInventoryCallback> cb = new CreateFriendCardCallback();
  465. create_inventory_callingcard(avatarID, findFriendAllSubfolderUUIDImpl(), cb);
  466. }
  467. }
  468. void LLFriendCardsManager::removeFriendCardFromInventory(const LLUUID& avatarID)
  469. {
  470. LLInventoryModel::item_array_t items;
  471. findMatchedFriendCards(avatarID, items);
  472. LLInventoryModel::item_array_t::const_iterator it;
  473. for (it = items.begin(); it != items.end(); ++ it)
  474. {
  475. gInventory.removeItem((*it)->getUUID());
  476. }
  477. }
  478. void LLFriendCardsManager::onFriendListUpdate(U32 changed_mask)
  479. {
  480. LLAvatarTracker& at = LLAvatarTracker::instance();
  481. switch(changed_mask) {
  482. case LLFriendObserver::ADD:
  483. {
  484. const std::set<LLUUID>& changed_items = at.getChangedIDs();
  485. std::set<LLUUID>::const_iterator id_it = changed_items.begin();
  486. std::set<LLUUID>::const_iterator id_end = changed_items.end();
  487. for (;id_it != id_end; ++id_it)
  488. {
  489. LLFriendCardsManager::instance().addFriendCardToInventory(*id_it);
  490. }
  491. }
  492. break;
  493. case LLFriendObserver::REMOVE:
  494. {
  495. const std::set<LLUUID>& changed_items = at.getChangedIDs();
  496. std::set<LLUUID>::const_iterator id_it = changed_items.begin();
  497. std::set<LLUUID>::const_iterator id_end = changed_items.end();
  498. for (;id_it != id_end; ++id_it)
  499. {
  500. LLFriendCardsManager::instance().removeFriendCardFromInventory(*id_it);
  501. }
  502. }
  503. default:;
  504. }
  505. }
  506. // EOF