PageRenderTime 115ms CodeModel.GetById 3ms app.highlight 101ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llavataractions.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1033 lines | 770 code | 136 blank | 127 comment | 121 complexity | d270770c431d19f9510d590f7711dd6f MD5 | raw file
   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}