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