/indra/newview/llavataractions.cpp
C++ | 1033 lines | 770 code | 136 blank | 127 comment | 121 complexity | d270770c431d19f9510d590f7711dd6f MD5 | raw file
Possible License(s): LGPL-2.1
1/** 2 * @file llavataractions.cpp 3 * @brief Friend-related actions (add, remove, offer teleport, etc) 4 * 5 * $LicenseInfo:firstyear=2009&license=viewerlgpl$ 6 * Second Life Viewer Source Code 7 * Copyright (C) 2010, Linden Research, Inc. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; 12 * version 2.1 of the License only. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA 24 * $/LicenseInfo$ 25 */ 26 27 28#include "llviewerprecompiledheaders.h" 29 30#include "llavataractions.h" 31 32#include "boost/lambda/lambda.hpp" // for lambda::constant 33 34#include "llavatarnamecache.h" // IDEVO 35#include "llsd.h" 36#include "lldarray.h" 37#include "llnotifications.h" 38#include "llnotificationsutil.h" 39#include "roles_constants.h" // for GP_MEMBER_INVITE 40 41#include "llagent.h" 42#include "llappviewer.h" // for gLastVersionChannel 43#include "llcachename.h" 44#include "llcallingcard.h" // for LLAvatarTracker 45#include "llfloateravatarpicker.h" // for LLFloaterAvatarPicker 46#include "llfloatergroupinvite.h" 47#include "llfloatergroups.h" 48#include "llfloaterreg.h" 49#include "llfloaterpay.h" 50#include "llfloatersidepanelcontainer.h" 51#include "llfloaterwebcontent.h" 52#include "llfloaterworldmap.h" 53#include "llfolderview.h" 54#include "llgiveinventory.h" 55#include "llinventorybridge.h" 56#include "llinventorymodel.h" // for gInventory.findCategoryUUIDForType 57#include "llinventorypanel.h" 58#include "llimview.h" // for gIMMgr 59#include "llmutelist.h" 60#include "llnotificationsutil.h" // for LLNotificationsUtil 61#include "llpaneloutfitedit.h" 62#include "llpanelprofile.h" 63#include "llrecentpeople.h" 64#include "lltrans.h" 65#include "llviewercontrol.h" 66#include "llviewerobjectlist.h" 67#include "llviewermessage.h" // for handle_lure 68#include "llviewerregion.h" 69#include "llimfloater.h" 70#include "lltrans.h" 71#include "llcallingcard.h" 72#include "llslurl.h" // IDEVO 73#include "llsidepanelinventory.h" 74 75// static 76void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name) 77{ 78 if(id == gAgentID) 79 { 80 LLNotificationsUtil::add("AddSelfFriend"); 81 return; 82 } 83 84 LLSD args; 85 args["NAME"] = LLSLURL("agent", id, "completename").getSLURLString(); 86 LLSD payload; 87 payload["id"] = id; 88 payload["name"] = name; 89 90 LLNotificationsUtil::add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage); 91 92 // add friend to recent people list 93 LLRecentPeople::instance().add(id); 94} 95 96void on_avatar_name_friendship(const LLUUID& id, const LLAvatarName av_name) 97{ 98 LLAvatarActions::requestFriendshipDialog(id, av_name.getCompleteName()); 99} 100 101// static 102void LLAvatarActions::requestFriendshipDialog(const LLUUID& id) 103{ 104 if(id.isNull()) 105 { 106 return; 107 } 108 109 LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_friendship, _1, _2)); 110} 111 112// static 113void LLAvatarActions::removeFriendDialog(const LLUUID& id) 114{ 115 if (id.isNull()) 116 return; 117 118 uuid_vec_t ids; 119 ids.push_back(id); 120 removeFriendsDialog(ids); 121} 122 123// static 124void LLAvatarActions::removeFriendsDialog(const uuid_vec_t& ids) 125{ 126 if(ids.size() == 0) 127 return; 128 129 LLSD args; 130 std::string msgType; 131 if(ids.size() == 1) 132 { 133 LLUUID agent_id = ids[0]; 134 LLAvatarName av_name; 135 if(LLAvatarNameCache::get(agent_id, &av_name)) 136 { 137 args["NAME"] = av_name.mDisplayName; 138 } 139 140 msgType = "RemoveFromFriends"; 141 } 142 else 143 { 144 msgType = "RemoveMultipleFromFriends"; 145 } 146 147 LLSD payload; 148 for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) 149 { 150 payload["ids"].append(*it); 151 } 152 153 LLNotificationsUtil::add(msgType, 154 args, 155 payload, 156 &handleRemove); 157} 158 159// static 160void LLAvatarActions::offerTeleport(const LLUUID& invitee) 161{ 162 if (invitee.isNull()) 163 return; 164 165 LLDynamicArray<LLUUID> ids; 166 ids.push_back(invitee); 167 offerTeleport(ids); 168} 169 170// static 171void LLAvatarActions::offerTeleport(const uuid_vec_t& ids) 172{ 173 if (ids.size() == 0) 174 return; 175 176 handle_lure(ids); 177} 178 179static void on_avatar_name_cache_start_im(const LLUUID& agent_id, 180 const LLAvatarName& av_name) 181{ 182 std::string name = av_name.getCompleteName(); 183 LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, agent_id); 184 if (session_id != LLUUID::null) 185 { 186 LLIMFloater::show(session_id); 187 } 188 make_ui_sound("UISndStartIM"); 189} 190 191// static 192void LLAvatarActions::startIM(const LLUUID& id) 193{ 194 if (id.isNull()) 195 return; 196 197 LLAvatarNameCache::get(id, 198 boost::bind(&on_avatar_name_cache_start_im, _1, _2)); 199} 200 201// static 202void LLAvatarActions::endIM(const LLUUID& id) 203{ 204 if (id.isNull()) 205 return; 206 207 LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id); 208 if (session_id != LLUUID::null) 209 { 210 gIMMgr->leaveSession(session_id); 211 } 212} 213 214static void on_avatar_name_cache_start_call(const LLUUID& agent_id, 215 const LLAvatarName& av_name) 216{ 217 std::string name = av_name.getCompleteName(); 218 LLUUID session_id = gIMMgr->addSession(name, IM_NOTHING_SPECIAL, agent_id, true); 219 if (session_id != LLUUID::null) 220 { 221 gIMMgr->startCall(session_id); 222 } 223 make_ui_sound("UISndStartIM"); 224} 225 226// static 227void LLAvatarActions::startCall(const LLUUID& id) 228{ 229 if (id.isNull()) 230 { 231 return; 232 } 233 LLAvatarNameCache::get(id, 234 boost::bind(&on_avatar_name_cache_start_call, _1, _2)); 235} 236 237// static 238void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids) 239{ 240 if (ids.size() == 0) 241 { 242 return; 243 } 244 245 // convert vector into LLDynamicArray for addSession 246 LLDynamicArray<LLUUID> id_array; 247 for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) 248 { 249 id_array.push_back(*it); 250 } 251 252 // create the new ad hoc voice session 253 const std::string title = LLTrans::getString("conference-title"); 254 LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, 255 ids[0], id_array, true); 256 if (session_id == LLUUID::null) 257 { 258 return; 259 } 260 261 gIMMgr->autoStartCallOnStartup(session_id); 262 263 make_ui_sound("UISndStartIM"); 264} 265 266/* AD *TODO: Is this function needed any more? 267 I fixed it a bit(added check for canCall), but it appears that it is not used 268 anywhere. Maybe it should be removed? 269// static 270bool LLAvatarActions::isCalling(const LLUUID &id) 271{ 272 if (id.isNull() || !canCall()) 273 { 274 return false; 275 } 276 277 LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id); 278 return (LLIMModel::getInstance()->findIMSession(session_id) != NULL); 279}*/ 280 281//static 282bool LLAvatarActions::canCall() 283{ 284 return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); 285} 286 287// static 288void LLAvatarActions::startConference(const uuid_vec_t& ids) 289{ 290 // *HACK: Copy into dynamic array 291 LLDynamicArray<LLUUID> id_array; 292 for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) 293 { 294 id_array.push_back(*it); 295 } 296 const std::string title = LLTrans::getString("conference-title"); 297 LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, ids[0], id_array); 298 if (session_id != LLUUID::null) 299 { 300 LLIMFloater::show(session_id); 301 } 302 make_ui_sound("UISndStartIM"); 303} 304 305static const char* get_profile_floater_name(const LLUUID& avatar_id) 306{ 307 // Use different floater XML for our profile to be able to save its rect. 308 return avatar_id == gAgentID ? "my_profile" : "profile"; 309} 310 311static void on_avatar_name_show_profile(const LLUUID& agent_id, const LLAvatarName& av_name) 312{ 313 std::string username = av_name.mUsername; 314 if (username.empty()) 315 { 316 username = LLCacheName::buildUsername(av_name.mDisplayName); 317 } 318 319 llinfos << "opening web profile for " << username << llendl; 320 std::string url = getProfileURL(username); 321 322 // PROFILES: open in webkit window 323 LLFloaterWebContent::Params p; 324 p.url(url). 325 id(agent_id.asString()); 326 LLFloaterReg::showInstance(get_profile_floater_name(agent_id), p); 327} 328 329// static 330void LLAvatarActions::showProfile(const LLUUID& id) 331{ 332 if (id.notNull()) 333 { 334 LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_show_profile, _1, _2)); 335 } 336} 337 338//static 339bool LLAvatarActions::profileVisible(const LLUUID& id) 340{ 341 LLSD sd; 342 sd["id"] = id; 343 LLFloater* browser = getProfileFloater(id); 344 return browser && browser->isShown(); 345} 346 347//static 348LLFloater* LLAvatarActions::getProfileFloater(const LLUUID& id) 349{ 350 LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> 351 (LLFloaterReg::findInstance(get_profile_floater_name(id), LLSD().with("id", id))); 352 return browser; 353} 354 355//static 356void LLAvatarActions::hideProfile(const LLUUID& id) 357{ 358 LLSD sd; 359 sd["id"] = id; 360 LLFloater* browser = getProfileFloater(id); 361 if (browser) 362 { 363 browser->closeFloater(); 364 } 365} 366 367// static 368void LLAvatarActions::showOnMap(const LLUUID& id) 369{ 370 LLAvatarName av_name; 371 if (!LLAvatarNameCache::get(id, &av_name)) 372 { 373 LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::showOnMap, id)); 374 return; 375 } 376 377 gFloaterWorldMap->trackAvatar(id, av_name.mDisplayName); 378 LLFloaterReg::showInstance("world_map"); 379} 380 381// static 382void LLAvatarActions::pay(const LLUUID& id) 383{ 384 LLNotification::Params params("BusyModePay"); 385 params.functor.function(boost::bind(&LLAvatarActions::handlePay, _1, _2, id)); 386 387 if (gAgent.getBusy()) 388 { 389 // warn users of being in busy mode during a transaction 390 LLNotifications::instance().add(params); 391 } 392 else 393 { 394 LLNotifications::instance().forceResponse(params, 1); 395 } 396} 397 398// static 399void LLAvatarActions::kick(const LLUUID& id) 400{ 401 LLSD payload; 402 payload["avatar_id"] = id; 403 LLNotifications::instance().add("KickUser", LLSD(), payload, handleKick); 404} 405 406// static 407void LLAvatarActions::freeze(const LLUUID& id) 408{ 409 LLSD payload; 410 payload["avatar_id"] = id; 411 LLNotifications::instance().add("FreezeUser", LLSD(), payload, handleFreeze); 412} 413 414// static 415void LLAvatarActions::unfreeze(const LLUUID& id) 416{ 417 LLSD payload; 418 payload["avatar_id"] = id; 419 LLNotifications::instance().add("UnFreezeUser", LLSD(), payload, handleUnfreeze); 420} 421 422//static 423void LLAvatarActions::csr(const LLUUID& id, std::string name) 424{ 425 if (name.empty()) return; 426 427 std::string url = "http://csr.lindenlab.com/agent/"; 428 429 // slow and stupid, but it's late 430 S32 len = name.length(); 431 for (S32 i = 0; i < len; i++) 432 { 433 if (name[i] == ' ') 434 { 435 url += "%20"; 436 } 437 else 438 { 439 url += name[i]; 440 } 441 } 442 443 LLWeb::loadURL(url); 444} 445 446//static 447void LLAvatarActions::share(const LLUUID& id) 448{ 449 LLSD key; 450 LLFloaterSidePanelContainer::showPanel("inventory", key); 451 452 LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL,id); 453 454 if (!gIMMgr->hasSession(session_id)) 455 { 456 startIM(id); 457 } 458 459 if (gIMMgr->hasSession(session_id)) 460 { 461 // we should always get here, but check to verify anyways 462 LLIMModel::getInstance()->addMessage(session_id, SYSTEM_FROM, LLUUID::null, LLTrans::getString("share_alert"), false); 463 } 464} 465 466namespace action_give_inventory 467{ 468 /** 469 * Returns a pointer to 'Add More' inventory panel of Edit Outfit SP. 470 */ 471 static LLInventoryPanel* get_outfit_editor_inventory_panel() 472 { 473 LLPanelOutfitEdit* panel_outfit_edit = dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit")); 474 if (NULL == panel_outfit_edit) return NULL; 475 476 LLInventoryPanel* inventory_panel = panel_outfit_edit->findChild<LLInventoryPanel>("folder_view"); 477 return inventory_panel; 478 } 479 480 /** 481 * @return active inventory panel, or NULL if there's no such panel 482 */ 483 static LLInventoryPanel* get_active_inventory_panel() 484 { 485 LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); 486 if (!active_panel) 487 { 488 active_panel = get_outfit_editor_inventory_panel(); 489 } 490 491 return active_panel; 492 } 493 494 /** 495 * Checks My Inventory visibility. 496 */ 497 498 static bool is_give_inventory_acceptable() 499 { 500 // check selection in the panel 501 const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); 502 if (inventory_selected_uuids.empty()) return false; // nothing selected 503 504 bool acceptable = false; 505 std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin(); 506 const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end(); 507 for (; it != it_end; ++it) 508 { 509 LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); 510 // any category can be offered. 511 if (inv_cat) 512 { 513 acceptable = true; 514 continue; 515 } 516 517 LLViewerInventoryItem* inv_item = gInventory.getItem(*it); 518 // check if inventory item can be given 519 if (LLGiveInventory::isInventoryGiveAcceptable(inv_item)) 520 { 521 acceptable = true; 522 continue; 523 } 524 525 // there are neither item nor category in inventory 526 acceptable = false; 527 break; 528 } 529 return acceptable; 530 } 531 532 static void build_residents_string(const std::vector<LLAvatarName> avatar_names, std::string& residents_string) 533 { 534 llassert(avatar_names.size() > 0); 535 536 const std::string& separator = LLTrans::getString("words_separator"); 537 for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; ) 538 { 539 LLAvatarName av_name = *it; 540 residents_string.append(av_name.mDisplayName); 541 if (++it == avatar_names.end()) 542 { 543 break; 544 } 545 residents_string.append(separator); 546 } 547 } 548 549 static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string) 550 { 551 llassert(inventory_selected_uuids.size() > 0); 552 553 const std::string& separator = LLTrans::getString("words_separator"); 554 for (std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin(); ; ) 555 { 556 LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); 557 if (NULL != inv_cat) 558 { 559 items_string = inv_cat->getName(); 560 break; 561 } 562 LLViewerInventoryItem* inv_item = gInventory.getItem(*it); 563 if (NULL != inv_item) 564 { 565 items_string.append(inv_item->getName()); 566 } 567 if(++it == inventory_selected_uuids.end()) 568 { 569 break; 570 } 571 items_string.append(separator); 572 } 573 } 574 575 struct LLShareInfo : public LLSingleton<LLShareInfo> 576 { 577 std::vector<LLAvatarName> mAvatarNames; 578 uuid_vec_t mAvatarUuids; 579 }; 580 581 static void give_inventory_cb(const LLSD& notification, const LLSD& response) 582 { 583 S32 option = LLNotificationsUtil::getSelectedOption(notification, response); 584 // if Cancel pressed 585 if (option == 1) 586 { 587 return; 588 } 589 590 const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); 591 if (inventory_selected_uuids.empty()) 592 { 593 return; 594 } 595 596 S32 count = LLShareInfo::instance().mAvatarNames.size(); 597 bool shared = false; 598 599 // iterate through avatars 600 for(S32 i = 0; i < count; ++i) 601 { 602 const LLUUID& avatar_uuid = LLShareInfo::instance().mAvatarUuids[i]; 603 604 // We souldn't open IM session, just calculate session ID for logging purpose. See EXT-6710 605 const LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, avatar_uuid); 606 607 std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin(); 608 const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end(); 609 610 const std::string& separator = LLTrans::getString("words_separator"); 611 std::string noncopy_item_names; 612 LLSD noncopy_items = LLSD::emptyArray(); 613 // iterate through selected inventory objects 614 for (; it != it_end; ++it) 615 { 616 LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); 617 if (inv_cat) 618 { 619 LLGiveInventory::doGiveInventoryCategory(avatar_uuid, inv_cat, session_id); 620 shared = true; 621 break; 622 } 623 LLViewerInventoryItem* inv_item = gInventory.getItem(*it); 624 if (!inv_item->getPermissions().allowCopyBy(gAgentID)) 625 { 626 if (!noncopy_item_names.empty()) 627 { 628 noncopy_item_names.append(separator); 629 } 630 noncopy_item_names.append(inv_item->getName()); 631 noncopy_items.append(*it); 632 } 633 else 634 { 635 LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id); 636 shared = true; 637 } 638 } 639 if (noncopy_items.beginArray() != noncopy_items.endArray()) 640 { 641 LLSD substitutions; 642 substitutions["ITEMS"] = noncopy_item_names; 643 LLSD payload; 644 payload["agent_id"] = avatar_uuid; 645 payload["items"] = noncopy_items; 646 LLNotificationsUtil::add("CannotCopyWarning", substitutions, payload, 647 &LLGiveInventory::handleCopyProtectedItem); 648 break; 649 } 650 } 651 if (shared) 652 { 653 LLFloaterReg::hideInstance("avatar_picker"); 654 LLNotificationsUtil::add("ItemsShared"); 655 } 656 } 657 658 /** 659 * Performs "give inventory" operations for provided avatars. 660 * 661 * Sends one requests to give all selected inventory items for each passed avatar. 662 * Avatars are represent by two vectors: names and UUIDs which must be sychronized with each other. 663 * 664 * @param avatar_names - avatar names request to be sent. 665 * @param avatar_uuids - avatar names request to be sent. 666 */ 667 static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names) 668 { 669 llassert(avatar_names.size() == avatar_uuids.size()); 670 671 const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); 672 if (inventory_selected_uuids.empty()) 673 { 674 return; 675 } 676 677 std::string residents; 678 build_residents_string(avatar_names, residents); 679 680 std::string items; 681 build_items_string(inventory_selected_uuids, items); 682 683 int folders_count = 0; 684 std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin(); 685 686 //traverse through selected inventory items and count folders among them 687 for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it) 688 { 689 LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); 690 if (NULL != inv_cat) 691 { 692 folders_count++; 693 } 694 } 695 696 // EXP-1599 697 // In case of sharing multiple folders, make the confirmation 698 // dialog contain a warning that only one folder can be shared at a time. 699 std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation"; 700 LLSD substitutions; 701 substitutions["RESIDENTS"] = residents; 702 substitutions["ITEMS"] = items; 703 LLShareInfo::instance().mAvatarNames = avatar_names; 704 LLShareInfo::instance().mAvatarUuids = avatar_uuids; 705 LLNotificationsUtil::add(notification, substitutions, LLSD(), &give_inventory_cb); 706 } 707} 708 709 710 711//static 712std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs() 713{ 714 std::set<LLUUID> inventory_selected_uuids; 715 716 LLInventoryPanel* active_panel = action_give_inventory::get_active_inventory_panel(); 717 if (active_panel) 718 { 719 inventory_selected_uuids = active_panel->getRootFolder()->getSelectionList(); 720 } 721 722 if (inventory_selected_uuids.empty()) 723 { 724 LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); 725 if (sidepanel_inventory) 726 { 727 inventory_selected_uuids = sidepanel_inventory->getInboxSelectionList(); 728 } 729 } 730 731 return inventory_selected_uuids; 732} 733 734//static 735void LLAvatarActions::shareWithAvatars() 736{ 737 using namespace action_give_inventory; 738 739 LLFloaterAvatarPicker* picker = 740 LLFloaterAvatarPicker::show(boost::bind(give_inventory, _1, _2), TRUE, FALSE); 741 picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable)); 742 picker->openFriendsTab(); 743 LLNotificationsUtil::add("ShareNotification"); 744} 745 746 747// static 748bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NULL*/) 749{ 750 using namespace action_give_inventory; 751 752 if (!inv_panel) 753 { 754 LLInventoryPanel* active_panel = get_active_inventory_panel(); 755 if (!active_panel) return false; 756 inv_panel = active_panel; 757 } 758 759 // check selection in the panel 760 LLFolderView* root_folder = inv_panel->getRootFolder(); 761 const std::set<LLUUID> inventory_selected_uuids = root_folder->getSelectionList(); 762 if (inventory_selected_uuids.empty()) return false; // nothing selected 763 764 bool can_share = true; 765 std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin(); 766 const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end(); 767 for (; it != it_end; ++it) 768 { 769 LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); 770 // any category can be offered. 771 if (inv_cat) 772 { 773 continue; 774 } 775 776 // check if inventory item can be given 777 LLFolderViewItem* item = root_folder->getItemByID(*it); 778 if (!item) return false; 779 LLInvFVBridge* bridge = dynamic_cast<LLInvFVBridge*>(item->getListener()); 780 if (bridge && bridge->canShare()) 781 { 782 continue; 783 } 784 785 // there are neither item nor category in inventory 786 can_share = false; 787 break; 788 } 789 790 return can_share; 791} 792 793// static 794void LLAvatarActions::toggleBlock(const LLUUID& id) 795{ 796 std::string name; 797 798 gCacheName->getFullName(id, name); // needed for mute 799 LLMute mute(id, name, LLMute::AGENT); 800 801 if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName)) 802 { 803 LLMuteList::getInstance()->remove(mute); 804 } 805 else 806 { 807 LLMuteList::getInstance()->add(mute); 808 } 809} 810 811// static 812bool LLAvatarActions::canOfferTeleport(const LLUUID& id) 813{ 814 // First use LLAvatarTracker::isBuddy() 815 // If LLAvatarTracker::instance().isBuddyOnline function only is used 816 // then for avatars that are online and not a friend it will return false. 817 // But we should give an ability to offer a teleport for such avatars. 818 if(LLAvatarTracker::instance().isBuddy(id)) 819 { 820 return LLAvatarTracker::instance().isBuddyOnline(id); 821 } 822 823 return true; 824} 825 826// static 827bool LLAvatarActions::canOfferTeleport(const uuid_vec_t& ids) 828{ 829 // We can't send more than 250 lures in a single message, so disable this 830 // button when there are too many id's selected. 831 if(ids.size() > 250) return false; 832 833 bool result = true; 834 for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) 835 { 836 if(!canOfferTeleport(*it)) 837 { 838 result = false; 839 break; 840 } 841 } 842 return result; 843} 844 845void LLAvatarActions::inviteToGroup(const LLUUID& id) 846{ 847 LLFloaterGroupPicker* widget = LLFloaterReg::showTypedInstance<LLFloaterGroupPicker>("group_picker", LLSD(id)); 848 if (widget) 849 { 850 widget->center(); 851 widget->setPowersMask(GP_MEMBER_INVITE); 852 widget->removeNoneOption(); 853 widget->setSelectGroupCallback(boost::bind(callback_invite_to_group, _1, id)); 854 } 855} 856 857//== private methods ======================================================================================== 858 859// static 860bool LLAvatarActions::handleRemove(const LLSD& notification, const LLSD& response) 861{ 862 S32 option = LLNotificationsUtil::getSelectedOption(notification, response); 863 864 const LLSD& ids = notification["payload"]["ids"]; 865 for (LLSD::array_const_iterator itr = ids.beginArray(); itr != ids.endArray(); ++itr) 866 { 867 LLUUID id = itr->asUUID(); 868 const LLRelationship* ip = LLAvatarTracker::instance().getBuddyInfo(id); 869 if (ip) 870 { 871 switch (option) 872 { 873 case 0: // YES 874 if( ip->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS)) 875 { 876 LLAvatarTracker::instance().empower(id, FALSE); 877 LLAvatarTracker::instance().notifyObservers(); 878 } 879 LLAvatarTracker::instance().terminateBuddy(id); 880 LLAvatarTracker::instance().notifyObservers(); 881 break; 882 883 case 1: // NO 884 default: 885 llinfos << "No removal performed." << llendl; 886 break; 887 } 888 } 889 } 890 return false; 891} 892 893// static 894bool LLAvatarActions::handlePay(const LLSD& notification, const LLSD& response, LLUUID avatar_id) 895{ 896 S32 option = LLNotificationsUtil::getSelectedOption(notification, response); 897 if (option == 0) 898 { 899 gAgent.clearBusy(); 900 } 901 902 LLFloaterPayUtil::payDirectly(&give_money, avatar_id, /*is_group=*/false); 903 return false; 904} 905 906// static 907void LLAvatarActions::callback_invite_to_group(LLUUID group_id, LLUUID id) 908{ 909 uuid_vec_t agent_ids; 910 agent_ids.push_back(id); 911 912 LLFloaterGroupInvite::showForGroup(group_id, &agent_ids); 913} 914 915 916// static 917bool LLAvatarActions::callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response) 918{ 919 S32 option = LLNotificationsUtil::getSelectedOption(notification, response); 920 if (option == 0) 921 { 922 requestFriendship(notification["payload"]["id"].asUUID(), 923 notification["payload"]["name"].asString(), 924 response["message"].asString()); 925 } 926 return false; 927} 928 929// static 930bool LLAvatarActions::handleKick(const LLSD& notification, const LLSD& response) 931{ 932 S32 option = LLNotification::getSelectedOption(notification, response); 933 934 if (option == 0) 935 { 936 LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); 937 LLMessageSystem* msg = gMessageSystem; 938 939 msg->newMessageFast(_PREHASH_GodKickUser); 940 msg->nextBlockFast(_PREHASH_UserInfo); 941 msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); 942 msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); 943 msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); 944 msg->addU32("KickFlags", KICK_FLAGS_DEFAULT ); 945 msg->addStringFast(_PREHASH_Reason, response["message"].asString() ); 946 gAgent.sendReliableMessage(); 947 } 948 return false; 949} 950bool LLAvatarActions::handleFreeze(const LLSD& notification, const LLSD& response) 951{ 952 S32 option = LLNotification::getSelectedOption(notification, response); 953 954 if (option == 0) 955 { 956 LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); 957 LLMessageSystem* msg = gMessageSystem; 958 959 msg->newMessageFast(_PREHASH_GodKickUser); 960 msg->nextBlockFast(_PREHASH_UserInfo); 961 msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); 962 msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); 963 msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); 964 msg->addU32("KickFlags", KICK_FLAGS_FREEZE ); 965 msg->addStringFast(_PREHASH_Reason, response["message"].asString() ); 966 gAgent.sendReliableMessage(); 967 } 968 return false; 969} 970bool LLAvatarActions::handleUnfreeze(const LLSD& notification, const LLSD& response) 971{ 972 S32 option = LLNotification::getSelectedOption(notification, response); 973 std::string text = response["message"].asString(); 974 if (option == 0) 975 { 976 LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); 977 LLMessageSystem* msg = gMessageSystem; 978 979 msg->newMessageFast(_PREHASH_GodKickUser); 980 msg->nextBlockFast(_PREHASH_UserInfo); 981 msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); 982 msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); 983 msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); 984 msg->addU32("KickFlags", KICK_FLAGS_UNFREEZE ); 985 msg->addStringFast(_PREHASH_Reason, text ); 986 gAgent.sendReliableMessage(); 987 } 988 return false; 989} 990 991// static 992void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message) 993{ 994 const LLUUID calling_card_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); 995 send_improved_im(target_id, 996 target_name, 997 message, 998 IM_ONLINE, 999 IM_FRIENDSHIP_OFFERED, 1000 calling_card_folder_id); 1001 1002 LLSD args; 1003 args["TO_NAME"] = target_name; 1004 1005 LLSD payload; 1006 payload["from_id"] = target_id; 1007 payload["SUPPRESS_TOAST"] = true; 1008 LLNotificationsUtil::add("FriendshipOffered", args, payload); 1009} 1010 1011//static 1012bool LLAvatarActions::isFriend(const LLUUID& id) 1013{ 1014 return ( NULL != LLAvatarTracker::instance().getBuddyInfo(id) ); 1015} 1016 1017// static 1018bool LLAvatarActions::isBlocked(const LLUUID& id) 1019{ 1020 std::string name; 1021 gCacheName->getFullName(id, name); // needed for mute 1022 return LLMuteList::getInstance()->isMuted(id, name); 1023} 1024 1025// static 1026bool LLAvatarActions::canBlock(const LLUUID& id) 1027{ 1028 std::string full_name; 1029 gCacheName->getFullName(id, full_name); // needed for mute 1030 bool is_linden = (full_name.find("Linden") != std::string::npos); 1031 bool is_self = id == gAgentID; 1032 return !is_self && !is_linden; 1033}