/indra/newview/llfloaterfriends.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 807 lines · 613 code · 111 blank · 83 comment · 95 complexity · 41cfc4f332c2507dabec6140e5882c5a MD5 · raw file

  1. /**
  2. * @file llfloaterfriends.cpp
  3. * @author Phoenix
  4. * @date 2005-01-13
  5. * @brief Implementation of the friends floater
  6. *
  7. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #include "llviewerprecompiledheaders.h"
  29. #include "llfloaterfriends.h"
  30. #include <sstream>
  31. #include "lldir.h"
  32. #include "llagent.h"
  33. #include "llappviewer.h" // for gLastVersionChannel
  34. #include "llfloateravatarpicker.h"
  35. #include "llviewerwindow.h"
  36. #include "llbutton.h"
  37. #include "llavataractions.h"
  38. #include "llinventorymodel.h"
  39. #include "llnamelistctrl.h"
  40. #include "llnotificationsutil.h"
  41. #include "llresmgr.h"
  42. #include "llscrolllistctrl.h"
  43. #include "llscrolllistitem.h"
  44. #include "llscrolllistcell.h"
  45. #include "lluictrlfactory.h"
  46. #include "llmenucommands.h"
  47. #include "llviewercontrol.h"
  48. #include "llviewermessage.h"
  49. #include "lleventtimer.h"
  50. #include "lltextbox.h"
  51. #include "llvoiceclient.h"
  52. // *TODO: Move more common stuff to LLAvatarActions?
  53. //Maximum number of people you can select to do an operation on at once.
  54. #define MAX_FRIEND_SELECT 20
  55. #define DEFAULT_PERIOD 5.0
  56. #define RIGHTS_CHANGE_TIMEOUT 5.0
  57. #define OBSERVER_TIMEOUT 0.5
  58. #define ONLINE_SIP_ICON_NAME "slim_icon_16_viewer.tga"
  59. // simple class to observe the calling cards.
  60. class LLLocalFriendsObserver : public LLFriendObserver, public LLEventTimer
  61. {
  62. public:
  63. LLLocalFriendsObserver(LLPanelFriends* floater) : mFloater(floater), LLEventTimer(OBSERVER_TIMEOUT)
  64. {
  65. mEventTimer.stop();
  66. }
  67. virtual ~LLLocalFriendsObserver()
  68. {
  69. mFloater = NULL;
  70. }
  71. virtual void changed(U32 mask)
  72. {
  73. // events can arrive quickly in bulk - we need not process EVERY one of them -
  74. // so we wait a short while to let others pile-in, and process them in aggregate.
  75. mEventTimer.start();
  76. // save-up all the mask-bits which have come-in
  77. mMask |= mask;
  78. }
  79. virtual BOOL tick()
  80. {
  81. mFloater->updateFriends(mMask);
  82. mEventTimer.stop();
  83. mMask = 0;
  84. return FALSE;
  85. }
  86. protected:
  87. LLPanelFriends* mFloater;
  88. U32 mMask;
  89. };
  90. LLPanelFriends::LLPanelFriends() :
  91. LLPanel(),
  92. LLEventTimer(DEFAULT_PERIOD),
  93. mObserver(NULL),
  94. mShowMaxSelectWarning(TRUE),
  95. mAllowRightsChange(TRUE),
  96. mNumRightsChanged(0)
  97. {
  98. mEventTimer.stop();
  99. mObserver = new LLLocalFriendsObserver(this);
  100. LLAvatarTracker::instance().addObserver(mObserver);
  101. // For notification when SIP online status changes.
  102. LLVoiceClient::getInstance()->addObserver(mObserver);
  103. }
  104. LLPanelFriends::~LLPanelFriends()
  105. {
  106. // For notification when SIP online status changes.
  107. LLVoiceClient::getInstance()->removeObserver(mObserver);
  108. LLAvatarTracker::instance().removeObserver(mObserver);
  109. delete mObserver;
  110. }
  111. BOOL LLPanelFriends::tick()
  112. {
  113. mEventTimer.stop();
  114. mPeriod = DEFAULT_PERIOD;
  115. mAllowRightsChange = TRUE;
  116. updateFriends(LLFriendObserver::ADD);
  117. return FALSE;
  118. }
  119. void LLPanelFriends::updateFriends(U32 changed_mask)
  120. {
  121. LLUUID selected_id;
  122. LLCtrlListInterface *friends_list = childGetListInterface("friend_list");
  123. if (!friends_list) return;
  124. LLCtrlScrollInterface *friends_scroll = childGetScrollInterface("friend_list");
  125. if (!friends_scroll) return;
  126. // We kill the selection warning, otherwise we'll spam with warning popups
  127. // if the maximum amount of friends are selected
  128. mShowMaxSelectWarning = false;
  129. std::vector<LLUUID> selected_friends = getSelectedIDs();
  130. if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
  131. {
  132. refreshNames(changed_mask);
  133. }
  134. else if(changed_mask & LLFriendObserver::POWERS)
  135. {
  136. --mNumRightsChanged;
  137. if(mNumRightsChanged > 0)
  138. {
  139. mPeriod = RIGHTS_CHANGE_TIMEOUT;
  140. mEventTimer.start();
  141. mAllowRightsChange = FALSE;
  142. }
  143. else
  144. {
  145. tick();
  146. }
  147. }
  148. if(selected_friends.size() > 0)
  149. {
  150. // only non-null if friends was already found. This may fail,
  151. // but we don't really care here, because refreshUI() will
  152. // clean up the interface.
  153. friends_list->setCurrentByID(selected_id);
  154. for(std::vector<LLUUID>::iterator itr = selected_friends.begin(); itr != selected_friends.end(); ++itr)
  155. {
  156. friends_list->setSelectedByValue(*itr, true);
  157. }
  158. }
  159. refreshUI();
  160. mShowMaxSelectWarning = true;
  161. }
  162. // virtual
  163. BOOL LLPanelFriends::postBuild()
  164. {
  165. mFriendsList = getChild<LLScrollListCtrl>("friend_list");
  166. mFriendsList->setMaxSelectable(MAX_FRIEND_SELECT);
  167. mFriendsList->setMaximumSelectCallback(boost::bind(&LLPanelFriends::onMaximumSelect));
  168. mFriendsList->setCommitOnSelectionChange(TRUE);
  169. mFriendsList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
  170. childSetCommitCallback("friend_list", onSelectName, this);
  171. getChild<LLScrollListCtrl>("friend_list")->setDoubleClickCallback(onClickIM, this);
  172. U32 changed_mask = LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE;
  173. refreshNames(changed_mask);
  174. childSetAction("im_btn", onClickIM, this);
  175. childSetAction("profile_btn", onClickProfile, this);
  176. childSetAction("offer_teleport_btn", onClickOfferTeleport, this);
  177. childSetAction("pay_btn", onClickPay, this);
  178. childSetAction("add_btn", onClickAddFriend, this);
  179. childSetAction("remove_btn", onClickRemove, this);
  180. setDefaultBtn("im_btn");
  181. updateFriends(LLFriendObserver::ADD);
  182. refreshUI();
  183. // primary sort = online status, secondary sort = name
  184. mFriendsList->sortByColumn(std::string("friend_name"), TRUE);
  185. mFriendsList->sortByColumn(std::string("icon_online_status"), FALSE);
  186. return TRUE;
  187. }
  188. BOOL LLPanelFriends::addFriend(const LLUUID& agent_id)
  189. {
  190. LLAvatarTracker& at = LLAvatarTracker::instance();
  191. const LLRelationship* relationInfo = at.getBuddyInfo(agent_id);
  192. if(!relationInfo) return FALSE;
  193. bool isOnlineSIP = LLVoiceClient::getInstance()->isOnlineSIP(agent_id);
  194. bool isOnline = relationInfo->isOnline();
  195. std::string fullname;
  196. BOOL have_name = gCacheName->getFullName(agent_id, fullname);
  197. LLSD element;
  198. element["id"] = agent_id;
  199. LLSD& friend_column = element["columns"][LIST_FRIEND_NAME];
  200. friend_column["column"] = "friend_name";
  201. friend_column["value"] = fullname;
  202. friend_column["font"]["name"] = "SANSSERIF";
  203. friend_column["font"]["style"] = "NORMAL";
  204. LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS];
  205. online_status_column["column"] = "icon_online_status";
  206. online_status_column["type"] = "icon";
  207. if (isOnline)
  208. {
  209. friend_column["font"]["style"] = "BOLD";
  210. online_status_column["value"] = "icon_avatar_online.tga";
  211. }
  212. else if(isOnlineSIP)
  213. {
  214. friend_column["font"]["style"] = "BOLD";
  215. online_status_column["value"] = ONLINE_SIP_ICON_NAME;
  216. }
  217. LLSD& online_column = element["columns"][LIST_VISIBLE_ONLINE];
  218. online_column["column"] = "icon_visible_online";
  219. online_column["type"] = "checkbox";
  220. online_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS);
  221. LLSD& visible_map_column = element["columns"][LIST_VISIBLE_MAP];
  222. visible_map_column["column"] = "icon_visible_map";
  223. visible_map_column["type"] = "checkbox";
  224. visible_map_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION);
  225. LLSD& edit_my_object_column = element["columns"][LIST_EDIT_MINE];
  226. edit_my_object_column["column"] = "icon_edit_mine";
  227. edit_my_object_column["type"] = "checkbox";
  228. edit_my_object_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS);
  229. LLSD& edit_their_object_column = element["columns"][LIST_EDIT_THEIRS];
  230. edit_their_object_column["column"] = "icon_edit_theirs";
  231. edit_their_object_column["type"] = "checkbox";
  232. edit_their_object_column["enabled"] = "";
  233. edit_their_object_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS);
  234. LLSD& update_gen_column = element["columns"][LIST_FRIEND_UPDATE_GEN];
  235. update_gen_column["column"] = "friend_last_update_generation";
  236. update_gen_column["value"] = have_name ? relationInfo->getChangeSerialNum() : -1;
  237. mFriendsList->addElement(element, ADD_BOTTOM);
  238. return have_name;
  239. }
  240. // propagate actual relationship to UI.
  241. // Does not resort the UI list because it can be called frequently. JC
  242. BOOL LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationship* info)
  243. {
  244. if (!info) return FALSE;
  245. LLScrollListItem* itemp = mFriendsList->getItem(agent_id);
  246. if (!itemp) return FALSE;
  247. bool isOnlineSIP = LLVoiceClient::getInstance()->isOnlineSIP(itemp->getUUID());
  248. bool isOnline = info->isOnline();
  249. std::string fullname;
  250. BOOL have_name = gCacheName->getFullName(agent_id, fullname);
  251. // Name of the status icon to use
  252. std::string statusIcon;
  253. if(isOnline)
  254. {
  255. statusIcon = "icon_avatar_online.tga";
  256. }
  257. else if(isOnlineSIP)
  258. {
  259. statusIcon = ONLINE_SIP_ICON_NAME;
  260. }
  261. itemp->getColumn(LIST_ONLINE_STATUS)->setValue(statusIcon);
  262. itemp->getColumn(LIST_FRIEND_NAME)->setValue(fullname);
  263. // render name of online friends in bold text
  264. ((LLScrollListText*)itemp->getColumn(LIST_FRIEND_NAME))->setFontStyle((isOnline || isOnlineSIP) ? LLFontGL::BOLD : LLFontGL::NORMAL);
  265. itemp->getColumn(LIST_VISIBLE_ONLINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS));
  266. itemp->getColumn(LIST_VISIBLE_MAP)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION));
  267. itemp->getColumn(LIST_EDIT_MINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS));
  268. S32 change_generation = have_name ? info->getChangeSerialNum() : -1;
  269. itemp->getColumn(LIST_FRIEND_UPDATE_GEN)->setValue(change_generation);
  270. // enable this item, in case it was disabled after user input
  271. itemp->setEnabled(TRUE);
  272. // Do not resort, this function can be called frequently.
  273. return have_name;
  274. }
  275. void LLPanelFriends::refreshRightsChangeList()
  276. {
  277. std::vector<LLUUID> friends = getSelectedIDs();
  278. S32 num_selected = friends.size();
  279. bool can_offer_teleport = num_selected >= 1;
  280. bool selected_friends_online = true;
  281. const LLRelationship* friend_status = NULL;
  282. for(std::vector<LLUUID>::iterator itr = friends.begin(); itr != friends.end(); ++itr)
  283. {
  284. friend_status = LLAvatarTracker::instance().getBuddyInfo(*itr);
  285. if (friend_status)
  286. {
  287. if(!friend_status->isOnline())
  288. {
  289. can_offer_teleport = false;
  290. selected_friends_online = false;
  291. }
  292. }
  293. else // missing buddy info, don't allow any operations
  294. {
  295. can_offer_teleport = false;
  296. }
  297. }
  298. if (num_selected == 0) // nothing selected
  299. {
  300. childSetEnabled("im_btn", FALSE);
  301. childSetEnabled("offer_teleport_btn", FALSE);
  302. }
  303. else // we have at least one friend selected...
  304. {
  305. // only allow IMs to groups when everyone in the group is online
  306. // to be consistent with context menus in inventory and because otherwise
  307. // offline friends would be silently dropped from the session
  308. childSetEnabled("im_btn", selected_friends_online || num_selected == 1);
  309. childSetEnabled("offer_teleport_btn", can_offer_teleport);
  310. }
  311. }
  312. struct SortFriendsByID
  313. {
  314. bool operator() (const LLScrollListItem* const a, const LLScrollListItem* const b) const
  315. {
  316. return a->getValue().asUUID() < b->getValue().asUUID();
  317. }
  318. };
  319. void LLPanelFriends::refreshNames(U32 changed_mask)
  320. {
  321. std::vector<LLUUID> selected_ids = getSelectedIDs();
  322. S32 pos = mFriendsList->getScrollPos();
  323. // get all buddies we know about
  324. LLAvatarTracker::buddy_map_t all_buddies;
  325. LLAvatarTracker::instance().copyBuddyList(all_buddies);
  326. BOOL have_names = TRUE;
  327. if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE))
  328. {
  329. have_names &= refreshNamesSync(all_buddies);
  330. }
  331. if(changed_mask & LLFriendObserver::ONLINE)
  332. {
  333. have_names &= refreshNamesPresence(all_buddies);
  334. }
  335. if (!have_names)
  336. {
  337. mEventTimer.start();
  338. }
  339. // Changed item in place, need to request sort and update columns
  340. // because we might have changed data in a column on which the user
  341. // has already sorted. JC
  342. mFriendsList->updateSort();
  343. // re-select items
  344. mFriendsList->selectMultiple(selected_ids);
  345. mFriendsList->setScrollPos(pos);
  346. }
  347. BOOL LLPanelFriends::refreshNamesSync(const LLAvatarTracker::buddy_map_t & all_buddies)
  348. {
  349. mFriendsList->deleteAllItems();
  350. BOOL have_names = TRUE;
  351. LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin();
  352. for(; buddy_it != all_buddies.end(); ++buddy_it)
  353. {
  354. have_names &= addFriend(buddy_it->first);
  355. }
  356. return have_names;
  357. }
  358. BOOL LLPanelFriends::refreshNamesPresence(const LLAvatarTracker::buddy_map_t & all_buddies)
  359. {
  360. std::vector<LLScrollListItem*> items = mFriendsList->getAllData();
  361. std::sort(items.begin(), items.end(), SortFriendsByID());
  362. LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin();
  363. std::vector<LLScrollListItem*>::const_iterator item_it = items.begin();
  364. BOOL have_names = TRUE;
  365. while(true)
  366. {
  367. if(item_it == items.end() || buddy_it == all_buddies.end())
  368. {
  369. break;
  370. }
  371. const LLUUID & buddy_uuid = buddy_it->first;
  372. const LLUUID & item_uuid = (*item_it)->getValue().asUUID();
  373. if(item_uuid == buddy_uuid)
  374. {
  375. const LLRelationship* info = buddy_it->second;
  376. if (!info)
  377. {
  378. ++item_it;
  379. continue;
  380. }
  381. S32 last_change_generation = (*item_it)->getColumn(LIST_FRIEND_UPDATE_GEN)->getValue().asInteger();
  382. if (last_change_generation < info->getChangeSerialNum())
  383. {
  384. // update existing item in UI
  385. have_names &= updateFriendItem(buddy_it->first, info);
  386. }
  387. ++buddy_it;
  388. ++item_it;
  389. }
  390. else if(item_uuid < buddy_uuid)
  391. {
  392. ++item_it;
  393. }
  394. else //if(item_uuid > buddy_uuid)
  395. {
  396. ++buddy_it;
  397. }
  398. }
  399. return have_names;
  400. }
  401. void LLPanelFriends::refreshUI()
  402. {
  403. BOOL single_selected = FALSE;
  404. BOOL multiple_selected = FALSE;
  405. int num_selected = mFriendsList->getAllSelected().size();
  406. if(num_selected > 0)
  407. {
  408. single_selected = TRUE;
  409. if(num_selected > 1)
  410. {
  411. multiple_selected = TRUE;
  412. }
  413. }
  414. //Options that can only be performed with one friend selected
  415. childSetEnabled("profile_btn", single_selected && !multiple_selected);
  416. childSetEnabled("pay_btn", single_selected && !multiple_selected);
  417. //Options that can be performed with up to MAX_FRIEND_SELECT friends selected
  418. //(single_selected will always be true in this situations)
  419. childSetEnabled("remove_btn", single_selected);
  420. childSetEnabled("im_btn", single_selected);
  421. // childSetEnabled("friend_rights", single_selected);
  422. refreshRightsChangeList();
  423. }
  424. std::vector<LLUUID> LLPanelFriends::getSelectedIDs()
  425. {
  426. LLUUID selected_id;
  427. std::vector<LLUUID> friend_ids;
  428. std::vector<LLScrollListItem*> selected = mFriendsList->getAllSelected();
  429. for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
  430. {
  431. friend_ids.push_back((*itr)->getUUID());
  432. }
  433. return friend_ids;
  434. }
  435. // static
  436. void LLPanelFriends::onSelectName(LLUICtrl* ctrl, void* user_data)
  437. {
  438. LLPanelFriends* panelp = (LLPanelFriends*)user_data;
  439. if(panelp)
  440. {
  441. panelp->refreshUI();
  442. // check to see if rights have changed
  443. panelp->applyRightsToFriends();
  444. }
  445. }
  446. //static
  447. void LLPanelFriends::onMaximumSelect()
  448. {
  449. LLSD args;
  450. args["MAX_SELECT"] = llformat("%d", MAX_FRIEND_SELECT);
  451. LLNotificationsUtil::add("MaxListSelectMessage", args);
  452. };
  453. // static
  454. void LLPanelFriends::onClickProfile(void* user_data)
  455. {
  456. LLPanelFriends* panelp = (LLPanelFriends*)user_data;
  457. std::vector<LLUUID> ids = panelp->getSelectedIDs();
  458. if(ids.size() > 0)
  459. {
  460. LLUUID agent_id = ids[0];
  461. LLAvatarActions::showProfile(agent_id);
  462. }
  463. }
  464. // static
  465. void LLPanelFriends::onClickIM(void* user_data)
  466. {
  467. LLPanelFriends* panelp = (LLPanelFriends*)user_data;
  468. std::vector<LLUUID> ids = panelp->getSelectedIDs();
  469. if(ids.size() > 0)
  470. {
  471. if(ids.size() == 1)
  472. {
  473. LLAvatarActions::startIM(ids[0]);
  474. }
  475. else
  476. {
  477. LLAvatarActions::startConference(ids);
  478. }
  479. }
  480. }
  481. // static
  482. void LLPanelFriends::onPickAvatar(const std::vector<std::string>& names,
  483. const std::vector<LLUUID>& ids)
  484. {
  485. if (names.empty()) return;
  486. if (ids.empty()) return;
  487. LLAvatarActions::requestFriendshipDialog(ids[0], names[0]);
  488. }
  489. // static
  490. void LLPanelFriends::onClickAddFriend(void* user_data)
  491. {
  492. LLPanelFriends* panelp = (LLPanelFriends*)user_data;
  493. LLFloater* root_floater = gFloaterView->getParentFloater(panelp);
  494. LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelFriends::onPickAvatar, _1,_2), FALSE, TRUE);
  495. if (root_floater)
  496. {
  497. root_floater->addDependentFloater(picker);
  498. }
  499. }
  500. // static
  501. void LLPanelFriends::onClickRemove(void* user_data)
  502. {
  503. LLPanelFriends* panelp = (LLPanelFriends*)user_data;
  504. LLAvatarActions::removeFriendsDialog(panelp->getSelectedIDs());
  505. }
  506. // static
  507. void LLPanelFriends::onClickOfferTeleport(void* user_data)
  508. {
  509. LLPanelFriends* panelp = (LLPanelFriends*)user_data;
  510. LLAvatarActions::offerTeleport(panelp->getSelectedIDs());
  511. }
  512. // static
  513. void LLPanelFriends::onClickPay(void* user_data)
  514. {
  515. LLPanelFriends* panelp = (LLPanelFriends*)user_data;
  516. std::vector<LLUUID> ids = panelp->getSelectedIDs();
  517. if(ids.size() == 1)
  518. {
  519. LLAvatarActions::pay(ids[0]);
  520. }
  521. }
  522. void LLPanelFriends::confirmModifyRights(rights_map_t& ids, EGrantRevoke command)
  523. {
  524. if (ids.empty()) return;
  525. LLSD args;
  526. if(ids.size() > 0)
  527. {
  528. rights_map_t* rights = new rights_map_t(ids);
  529. // for single friend, show their name
  530. if(ids.size() == 1)
  531. {
  532. LLUUID agent_id = ids.begin()->first;
  533. std::string first, last;
  534. if(gCacheName->getName(agent_id, first, last))
  535. {
  536. args["FIRST_NAME"] = first;
  537. args["LAST_NAME"] = last;
  538. }
  539. if (command == GRANT)
  540. {
  541. LLNotificationsUtil::add("GrantModifyRights",
  542. args,
  543. LLSD(),
  544. boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
  545. }
  546. else
  547. {
  548. LLNotificationsUtil::add("RevokeModifyRights",
  549. args,
  550. LLSD(),
  551. boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
  552. }
  553. }
  554. else
  555. {
  556. if (command == GRANT)
  557. {
  558. LLNotificationsUtil::add("GrantModifyRightsMultiple",
  559. args,
  560. LLSD(),
  561. boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
  562. }
  563. else
  564. {
  565. LLNotificationsUtil::add("RevokeModifyRightsMultiple",
  566. args,
  567. LLSD(),
  568. boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
  569. }
  570. }
  571. }
  572. }
  573. bool LLPanelFriends::modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t* rights)
  574. {
  575. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  576. if(0 == option)
  577. {
  578. sendRightsGrant(*rights);
  579. }
  580. else
  581. {
  582. // need to resync view with model, since user cancelled operation
  583. rights_map_t::iterator rights_it;
  584. for (rights_it = rights->begin(); rights_it != rights->end(); ++rights_it)
  585. {
  586. const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(rights_it->first);
  587. updateFriendItem(rights_it->first, info);
  588. }
  589. }
  590. refreshUI();
  591. delete rights;
  592. return false;
  593. }
  594. void LLPanelFriends::applyRightsToFriends()
  595. {
  596. BOOL rights_changed = FALSE;
  597. // store modify rights separately for confirmation
  598. rights_map_t rights_updates;
  599. BOOL need_confirmation = FALSE;
  600. EGrantRevoke confirmation_type = GRANT;
  601. // this assumes that changes only happened to selected items
  602. std::vector<LLScrollListItem*> selected = mFriendsList->getAllSelected();
  603. for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
  604. {
  605. LLUUID id = (*itr)->getValue();
  606. const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(id);
  607. if (buddy_relationship == NULL) continue;
  608. bool show_online_staus = (*itr)->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean();
  609. bool show_map_location = (*itr)->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean();
  610. bool allow_modify_objects = (*itr)->getColumn(LIST_EDIT_MINE)->getValue().asBoolean();
  611. S32 rights = buddy_relationship->getRightsGrantedTo();
  612. if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS) != show_online_staus)
  613. {
  614. rights_changed = TRUE;
  615. if(show_online_staus)
  616. {
  617. rights |= LLRelationship::GRANT_ONLINE_STATUS;
  618. }
  619. else
  620. {
  621. // ONLINE_STATUS necessary for MAP_LOCATION
  622. rights &= ~LLRelationship::GRANT_ONLINE_STATUS;
  623. rights &= ~LLRelationship::GRANT_MAP_LOCATION;
  624. // propagate rights constraint to UI
  625. (*itr)->getColumn(LIST_VISIBLE_MAP)->setValue(FALSE);
  626. }
  627. }
  628. if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION) != show_map_location)
  629. {
  630. rights_changed = TRUE;
  631. if(show_map_location)
  632. {
  633. // ONLINE_STATUS necessary for MAP_LOCATION
  634. rights |= LLRelationship::GRANT_MAP_LOCATION;
  635. rights |= LLRelationship::GRANT_ONLINE_STATUS;
  636. (*itr)->getColumn(LIST_VISIBLE_ONLINE)->setValue(TRUE);
  637. }
  638. else
  639. {
  640. rights &= ~LLRelationship::GRANT_MAP_LOCATION;
  641. }
  642. }
  643. // now check for change in modify object rights, which requires confirmation
  644. if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects)
  645. {
  646. rights_changed = TRUE;
  647. need_confirmation = TRUE;
  648. if(allow_modify_objects)
  649. {
  650. rights |= LLRelationship::GRANT_MODIFY_OBJECTS;
  651. confirmation_type = GRANT;
  652. }
  653. else
  654. {
  655. rights &= ~LLRelationship::GRANT_MODIFY_OBJECTS;
  656. confirmation_type = REVOKE;
  657. }
  658. }
  659. if (rights_changed)
  660. {
  661. rights_updates.insert(std::make_pair(id, rights));
  662. // disable these ui elements until response from server
  663. // to avoid race conditions
  664. (*itr)->setEnabled(FALSE);
  665. }
  666. }
  667. // separately confirm grant and revoke of modify rights
  668. if (need_confirmation)
  669. {
  670. confirmModifyRights(rights_updates, confirmation_type);
  671. }
  672. else
  673. {
  674. sendRightsGrant(rights_updates);
  675. }
  676. }
  677. void LLPanelFriends::sendRightsGrant(rights_map_t& ids)
  678. {
  679. if (ids.empty()) return;
  680. LLMessageSystem* msg = gMessageSystem;
  681. // setup message header
  682. msg->newMessageFast(_PREHASH_GrantUserRights);
  683. msg->nextBlockFast(_PREHASH_AgentData);
  684. msg->addUUID(_PREHASH_AgentID, gAgent.getID());
  685. msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
  686. rights_map_t::iterator id_it;
  687. rights_map_t::iterator end_it = ids.end();
  688. for(id_it = ids.begin(); id_it != end_it; ++id_it)
  689. {
  690. msg->nextBlockFast(_PREHASH_Rights);
  691. msg->addUUID(_PREHASH_AgentRelated, id_it->first);
  692. msg->addS32(_PREHASH_RelatedRights, id_it->second);
  693. }
  694. mNumRightsChanged = ids.size();
  695. gAgent.sendReliableMessage();
  696. }