PageRenderTime 45ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/newview/llinspectavatar.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 859 lines | 612 code | 134 blank | 113 comment | 57 complexity | 0c9ec0a60eaddd46af83b72991949acc MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llinspectavatar.cpp
  3. *
  4. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "llviewerprecompiledheaders.h"
  26. #include "llinspectavatar.h"
  27. // viewer files
  28. #include "llagent.h"
  29. #include "llagentdata.h"
  30. #include "llavataractions.h"
  31. #include "llavatarnamecache.h"
  32. #include "llavatarpropertiesprocessor.h"
  33. #include "llcallingcard.h"
  34. #include "lldateutil.h"
  35. #include "llfloaterreporter.h"
  36. #include "llfloaterworldmap.h"
  37. #include "llimview.h"
  38. #include "llinspect.h"
  39. #include "llmutelist.h"
  40. #include "llpanelblockedlist.h"
  41. #include "llstartup.h"
  42. #include "llspeakers.h"
  43. #include "llviewermenu.h"
  44. #include "llvoiceclient.h"
  45. #include "llviewerobjectlist.h"
  46. #include "lltransientfloatermgr.h"
  47. #include "llnotificationsutil.h"
  48. // Linden libraries
  49. #include "llfloater.h"
  50. #include "llfloaterreg.h"
  51. #include "llmenubutton.h"
  52. #include "lltextbox.h"
  53. #include "lltoggleablemenu.h"
  54. #include "lltooltip.h" // positionViewNearMouse()
  55. #include "lltrans.h"
  56. #include "lluictrl.h"
  57. #include "llavatariconctrl.h"
  58. class LLFetchAvatarData;
  59. //////////////////////////////////////////////////////////////////////////////
  60. // LLInspectAvatar
  61. //////////////////////////////////////////////////////////////////////////////
  62. // Avatar Inspector, a small information window used when clicking
  63. // on avatar names in the 2D UI and in the ambient inspector widget for
  64. // the 3D world.
  65. class LLInspectAvatar : public LLInspect, LLTransientFloater
  66. {
  67. friend class LLFloaterReg;
  68. public:
  69. // avatar_id - Avatar ID for which to show information
  70. // Inspector will be positioned relative to current mouse position
  71. LLInspectAvatar(const LLSD& avatar_id);
  72. virtual ~LLInspectAvatar();
  73. /*virtual*/ BOOL postBuild(void);
  74. // Because floater is single instance, need to re-parse data on each spawn
  75. // (for example, inspector about same avatar but in different position)
  76. /*virtual*/ void onOpen(const LLSD& avatar_id);
  77. // When closing they should close their gear menu
  78. /*virtual*/ void onClose(bool app_quitting);
  79. // Update view based on information from avatar properties processor
  80. void processAvatarData(LLAvatarData* data);
  81. // override the inspector mouse leave so timer is only paused if
  82. // gear menu is not open
  83. /* virtual */ void onMouseLeave(S32 x, S32 y, MASK mask);
  84. virtual LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::GLOBAL; }
  85. private:
  86. // Make network requests for all the data to display in this view.
  87. // Used on construction and if avatar id changes.
  88. void requestUpdate();
  89. // Set the volume slider to this user's current client-side volume setting,
  90. // hiding/disabling if the user is not nearby.
  91. void updateVolumeSlider();
  92. // Shows/hides moderator panel depending on voice state
  93. void updateModeratorPanel();
  94. // Moderator ability to enable/disable voice chat for avatar
  95. void toggleSelectedVoice(bool enabled);
  96. // Button callbacks
  97. void onClickAddFriend();
  98. void onClickViewProfile();
  99. void onClickIM();
  100. void onClickCall();
  101. void onClickTeleport();
  102. void onClickInviteToGroup();
  103. void onClickPay();
  104. void onClickShare();
  105. void onToggleMute();
  106. void onClickReport();
  107. void onClickFreeze();
  108. void onClickEject();
  109. void onClickKick();
  110. void onClickCSR();
  111. void onClickZoomIn();
  112. void onClickFindOnMap();
  113. bool onVisibleFindOnMap();
  114. bool onVisibleEject();
  115. bool onVisibleFreeze();
  116. bool onVisibleZoomIn();
  117. void onClickMuteVolume();
  118. void onVolumeChange(const LLSD& data);
  119. bool enableMute();
  120. bool enableUnmute();
  121. bool enableTeleportOffer();
  122. bool godModeEnabled();
  123. // Is used to determine if "Add friend" option should be enabled in gear menu
  124. bool isNotFriend();
  125. void onAvatarNameCache(const LLUUID& agent_id,
  126. const LLAvatarName& av_name);
  127. private:
  128. LLUUID mAvatarID;
  129. // Need avatar name information to spawn friend add request
  130. LLAvatarName mAvatarName;
  131. // an in-flight request for avatar properties from LLAvatarPropertiesProcessor
  132. // is represented by this object
  133. LLFetchAvatarData* mPropertiesRequest;
  134. };
  135. //////////////////////////////////////////////////////////////////////////////
  136. // LLFetchAvatarData
  137. //////////////////////////////////////////////////////////////////////////////
  138. // This object represents a pending request for avatar properties information
  139. class LLFetchAvatarData : public LLAvatarPropertiesObserver
  140. {
  141. public:
  142. // If the inspector closes it will delete the pending request object, so the
  143. // inspector pointer will be valid for the lifetime of this object
  144. LLFetchAvatarData(const LLUUID& avatar_id, LLInspectAvatar* inspector)
  145. : mAvatarID(avatar_id),
  146. mInspector(inspector)
  147. {
  148. LLAvatarPropertiesProcessor* processor =
  149. LLAvatarPropertiesProcessor::getInstance();
  150. // register ourselves as an observer
  151. processor->addObserver(mAvatarID, this);
  152. // send a request (duplicates will be suppressed inside the avatar
  153. // properties processor)
  154. processor->sendAvatarPropertiesRequest(mAvatarID);
  155. }
  156. ~LLFetchAvatarData()
  157. {
  158. // remove ourselves as an observer
  159. LLAvatarPropertiesProcessor::getInstance()->
  160. removeObserver(mAvatarID, this);
  161. }
  162. void processProperties(void* data, EAvatarProcessorType type)
  163. {
  164. // route the data to the inspector
  165. if (data
  166. && type == APT_PROPERTIES)
  167. {
  168. LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data);
  169. mInspector->processAvatarData(avatar_data);
  170. }
  171. }
  172. // Store avatar ID so we can un-register the observer on destruction
  173. LLUUID mAvatarID;
  174. LLInspectAvatar* mInspector;
  175. };
  176. LLInspectAvatar::LLInspectAvatar(const LLSD& sd)
  177. : LLInspect( LLSD() ), // single_instance, doesn't really need key
  178. mAvatarID(), // set in onOpen() *Note: we used to show partner's name but we dont anymore --angela 3rd Dec*
  179. mAvatarName(),
  180. mPropertiesRequest(NULL)
  181. {
  182. mCommitCallbackRegistrar.add("InspectAvatar.ViewProfile", boost::bind(&LLInspectAvatar::onClickViewProfile, this));
  183. mCommitCallbackRegistrar.add("InspectAvatar.AddFriend", boost::bind(&LLInspectAvatar::onClickAddFriend, this));
  184. mCommitCallbackRegistrar.add("InspectAvatar.IM",
  185. boost::bind(&LLInspectAvatar::onClickIM, this));
  186. mCommitCallbackRegistrar.add("InspectAvatar.Call", boost::bind(&LLInspectAvatar::onClickCall, this));
  187. mCommitCallbackRegistrar.add("InspectAvatar.Teleport", boost::bind(&LLInspectAvatar::onClickTeleport, this));
  188. mCommitCallbackRegistrar.add("InspectAvatar.InviteToGroup", boost::bind(&LLInspectAvatar::onClickInviteToGroup, this));
  189. mCommitCallbackRegistrar.add("InspectAvatar.Pay", boost::bind(&LLInspectAvatar::onClickPay, this));
  190. mCommitCallbackRegistrar.add("InspectAvatar.Share", boost::bind(&LLInspectAvatar::onClickShare, this));
  191. mCommitCallbackRegistrar.add("InspectAvatar.ToggleMute", boost::bind(&LLInspectAvatar::onToggleMute, this));
  192. mCommitCallbackRegistrar.add("InspectAvatar.Freeze", boost::bind(&LLInspectAvatar::onClickFreeze, this));
  193. mCommitCallbackRegistrar.add("InspectAvatar.Eject", boost::bind(&LLInspectAvatar::onClickEject, this));
  194. mCommitCallbackRegistrar.add("InspectAvatar.Kick", boost::bind(&LLInspectAvatar::onClickKick, this));
  195. mCommitCallbackRegistrar.add("InspectAvatar.CSR", boost::bind(&LLInspectAvatar::onClickCSR, this));
  196. mCommitCallbackRegistrar.add("InspectAvatar.Report", boost::bind(&LLInspectAvatar::onClickReport, this));
  197. mCommitCallbackRegistrar.add("InspectAvatar.FindOnMap", boost::bind(&LLInspectAvatar::onClickFindOnMap, this));
  198. mCommitCallbackRegistrar.add("InspectAvatar.ZoomIn", boost::bind(&LLInspectAvatar::onClickZoomIn, this));
  199. mCommitCallbackRegistrar.add("InspectAvatar.DisableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, false));
  200. mCommitCallbackRegistrar.add("InspectAvatar.EnableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, true));
  201. mEnableCallbackRegistrar.add("InspectAvatar.EnableGod", boost::bind(&LLInspectAvatar::godModeEnabled, this));
  202. mEnableCallbackRegistrar.add("InspectAvatar.VisibleFindOnMap", boost::bind(&LLInspectAvatar::onVisibleFindOnMap, this));
  203. mEnableCallbackRegistrar.add("InspectAvatar.VisibleEject", boost::bind(&LLInspectAvatar::onVisibleEject, this));
  204. mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreeze", boost::bind(&LLInspectAvatar::onVisibleFreeze, this));
  205. mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn", boost::bind(&LLInspectAvatar::onVisibleZoomIn, this));
  206. mEnableCallbackRegistrar.add("InspectAvatar.Gear.Enable", boost::bind(&LLInspectAvatar::isNotFriend, this));
  207. mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableCall", boost::bind(&LLAvatarActions::canCall));
  208. mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableTeleportOffer", boost::bind(&LLInspectAvatar::enableTeleportOffer, this));
  209. mEnableCallbackRegistrar.add("InspectAvatar.EnableMute", boost::bind(&LLInspectAvatar::enableMute, this));
  210. mEnableCallbackRegistrar.add("InspectAvatar.EnableUnmute", boost::bind(&LLInspectAvatar::enableUnmute, this));
  211. // can't make the properties request until the widgets are constructed
  212. // as it might return immediately, so do it in postBuild.
  213. LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::GLOBAL, this);
  214. LLTransientFloater::init(this);
  215. }
  216. LLInspectAvatar::~LLInspectAvatar()
  217. {
  218. // clean up any pending requests so they don't call back into a deleted
  219. // view
  220. delete mPropertiesRequest;
  221. mPropertiesRequest = NULL;
  222. LLTransientFloaterMgr::getInstance()->removeControlView(this);
  223. }
  224. /*virtual*/
  225. BOOL LLInspectAvatar::postBuild(void)
  226. {
  227. getChild<LLUICtrl>("add_friend_btn")->setCommitCallback(
  228. boost::bind(&LLInspectAvatar::onClickAddFriend, this) );
  229. getChild<LLUICtrl>("view_profile_btn")->setCommitCallback(
  230. boost::bind(&LLInspectAvatar::onClickViewProfile, this) );
  231. getChild<LLUICtrl>("mute_btn")->setCommitCallback(
  232. boost::bind(&LLInspectAvatar::onClickMuteVolume, this) );
  233. getChild<LLUICtrl>("volume_slider")->setCommitCallback(
  234. boost::bind(&LLInspectAvatar::onVolumeChange, this, _2));
  235. return TRUE;
  236. }
  237. // Multiple calls to showInstance("inspect_avatar", foo) will provide different
  238. // LLSD for foo, which we will catch here.
  239. //virtual
  240. void LLInspectAvatar::onOpen(const LLSD& data)
  241. {
  242. // Start open animation
  243. LLInspect::onOpen(data);
  244. // Extract appropriate avatar id
  245. mAvatarID = data["avatar_id"];
  246. BOOL self = mAvatarID == gAgent.getID();
  247. getChild<LLUICtrl>("gear_self_btn")->setVisible(self);
  248. getChild<LLUICtrl>("gear_btn")->setVisible(!self);
  249. // Position the inspector relative to the mouse cursor
  250. // Similar to how tooltips are positioned
  251. // See LLToolTipMgr::createToolTip
  252. if (data.has("pos"))
  253. {
  254. LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
  255. }
  256. else
  257. {
  258. LLUI::positionViewNearMouse(this);
  259. }
  260. // can't call from constructor as widgets are not built yet
  261. requestUpdate();
  262. updateVolumeSlider();
  263. updateModeratorPanel();
  264. }
  265. // virtual
  266. void LLInspectAvatar::onClose(bool app_quitting)
  267. {
  268. getChild<LLMenuButton>("gear_btn")->hideMenu();
  269. }
  270. void LLInspectAvatar::requestUpdate()
  271. {
  272. // Don't make network requests when spawning from the debug menu at the
  273. // login screen (which is useful to work on the layout).
  274. if (mAvatarID.isNull())
  275. {
  276. if (LLStartUp::getStartupState() >= STATE_STARTED)
  277. {
  278. // once we're running we don't want to show the test floater
  279. // for bogus LLUUID::null links
  280. closeFloater();
  281. }
  282. return;
  283. }
  284. // Clear out old data so it doesn't flash between old and new
  285. getChild<LLUICtrl>("user_name")->setValue("");
  286. getChild<LLUICtrl>("user_name_small")->setValue("");
  287. getChild<LLUICtrl>("user_slid")->setValue("");
  288. getChild<LLUICtrl>("user_subtitle")->setValue("");
  289. getChild<LLUICtrl>("user_details")->setValue("");
  290. // Make a new request for properties
  291. delete mPropertiesRequest;
  292. mPropertiesRequest = new LLFetchAvatarData(mAvatarID, this);
  293. // You can't re-add someone as a friend if they are already your friend
  294. bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL;
  295. bool is_self = (mAvatarID == gAgentID);
  296. if (is_self)
  297. {
  298. getChild<LLUICtrl>("add_friend_btn")->setVisible(false);
  299. getChild<LLUICtrl>("im_btn")->setVisible(false);
  300. }
  301. else if (is_friend)
  302. {
  303. getChild<LLUICtrl>("add_friend_btn")->setVisible(false);
  304. getChild<LLUICtrl>("im_btn")->setVisible(true);
  305. }
  306. else
  307. {
  308. getChild<LLUICtrl>("add_friend_btn")->setVisible(true);
  309. getChild<LLUICtrl>("im_btn")->setVisible(false);
  310. }
  311. // Use an avatar_icon even though the image id will come down with the
  312. // avatar properties because the avatar_icon code maintains a cache of icons
  313. // and this may result in the image being visible sooner.
  314. // *NOTE: This may generate a duplicate avatar properties request, but that
  315. // will be suppressed internally in the avatar properties processor.
  316. //remove avatar id from cache to get fresh info
  317. LLAvatarIconIDCache::getInstance()->remove(mAvatarID);
  318. getChild<LLUICtrl>("avatar_icon")->setValue(LLSD(mAvatarID) );
  319. LLAvatarNameCache::get(mAvatarID,
  320. boost::bind(&LLInspectAvatar::onAvatarNameCache,
  321. this, _1, _2));
  322. }
  323. void LLInspectAvatar::processAvatarData(LLAvatarData* data)
  324. {
  325. LLStringUtil::format_map_t args;
  326. {
  327. std::string birth_date = LLTrans::getString("AvatarBirthDateFormat");
  328. LLStringUtil::format(birth_date, LLSD().with("datetime", (S32) data->born_on.secondsSinceEpoch()));
  329. args["[BORN_ON]"] = birth_date;
  330. }
  331. args["[AGE]"] = LLDateUtil::ageFromDate(data->born_on, LLDate::now());
  332. args["[SL_PROFILE]"] = data->about_text;
  333. args["[RW_PROFILE"] = data->fl_about_text;
  334. args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(data);
  335. std::string payment_info = LLAvatarPropertiesProcessor::paymentInfo(data);
  336. args["[PAYMENTINFO]"] = payment_info;
  337. args["[COMMA]"] = (payment_info.empty() ? "" : ",");
  338. std::string subtitle = getString("Subtitle", args);
  339. getChild<LLUICtrl>("user_subtitle")->setValue( LLSD(subtitle) );
  340. std::string details = getString("Details", args);
  341. getChild<LLUICtrl>("user_details")->setValue( LLSD(details) );
  342. // Delete the request object as it has been satisfied
  343. delete mPropertiesRequest;
  344. mPropertiesRequest = NULL;
  345. }
  346. // For the avatar inspector, we only want to unpause the fade timer
  347. // if neither the gear menu or self gear menu are open
  348. void LLInspectAvatar::onMouseLeave(S32 x, S32 y, MASK mask)
  349. {
  350. LLToggleableMenu* gear_menu = getChild<LLMenuButton>("gear_btn")->getMenu();
  351. LLToggleableMenu* gear_menu_self = getChild<LLMenuButton>("gear_self_btn")->getMenu();
  352. if ( gear_menu && gear_menu->getVisible() &&
  353. gear_menu_self && gear_menu_self->getVisible() )
  354. {
  355. return;
  356. }
  357. if(childHasVisiblePopupMenu())
  358. {
  359. return;
  360. }
  361. mOpenTimer.unpause();
  362. }
  363. void LLInspectAvatar::updateModeratorPanel()
  364. {
  365. bool enable_moderator_panel = false;
  366. if (LLVoiceChannel::getCurrentVoiceChannel() &&
  367. mAvatarID != gAgent.getID())
  368. {
  369. LLUUID session_id = LLVoiceChannel::getCurrentVoiceChannel()->getSessionID();
  370. if (session_id != LLUUID::null)
  371. {
  372. LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id);
  373. if (speaker_mgr)
  374. {
  375. LLPointer<LLSpeaker> self_speakerp = speaker_mgr->findSpeaker(gAgent.getID());
  376. LLPointer<LLSpeaker> selected_speakerp = speaker_mgr->findSpeaker(mAvatarID);
  377. if(speaker_mgr->isVoiceActive() && selected_speakerp &&
  378. selected_speakerp->isInVoiceChannel() &&
  379. ((self_speakerp && self_speakerp->mIsModerator) || gAgent.isGodlike()))
  380. {
  381. getChild<LLUICtrl>("enable_voice")->setVisible(selected_speakerp->mModeratorMutedVoice);
  382. getChild<LLUICtrl>("disable_voice")->setVisible(!selected_speakerp->mModeratorMutedVoice);
  383. enable_moderator_panel = true;
  384. }
  385. }
  386. }
  387. }
  388. if (enable_moderator_panel)
  389. {
  390. if (!getChild<LLUICtrl>("moderator_panel")->getVisible())
  391. {
  392. getChild<LLUICtrl>("moderator_panel")->setVisible(true);
  393. // stretch the floater so it can accommodate the moderator panel
  394. reshape(getRect().getWidth(), getRect().getHeight() + getChild<LLUICtrl>("moderator_panel")->getRect().getHeight());
  395. }
  396. }
  397. else if (getChild<LLUICtrl>("moderator_panel")->getVisible())
  398. {
  399. getChild<LLUICtrl>("moderator_panel")->setVisible(false);
  400. // shrink the inspector floater back to original size
  401. reshape(getRect().getWidth(), getRect().getHeight() - getChild<LLUICtrl>("moderator_panel")->getRect().getHeight());
  402. }
  403. }
  404. void LLInspectAvatar::toggleSelectedVoice(bool enabled)
  405. {
  406. LLUUID session_id = LLVoiceChannel::getCurrentVoiceChannel()->getSessionID();
  407. LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id);
  408. if (speaker_mgr)
  409. {
  410. if (!gAgent.getRegion())
  411. return;
  412. std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
  413. LLSD data;
  414. data["method"] = "mute update";
  415. data["session-id"] = session_id;
  416. data["params"] = LLSD::emptyMap();
  417. data["params"]["agent_id"] = mAvatarID;
  418. data["params"]["mute_info"] = LLSD::emptyMap();
  419. // ctrl value represents ability to type, so invert
  420. data["params"]["mute_info"]["voice"] = !enabled;
  421. class MuteVoiceResponder : public LLHTTPClient::Responder
  422. {
  423. public:
  424. MuteVoiceResponder(const LLUUID& session_id)
  425. {
  426. mSessionID = session_id;
  427. }
  428. virtual void error(U32 status, const std::string& reason)
  429. {
  430. llwarns << status << ": " << reason << llendl;
  431. if ( gIMMgr )
  432. {
  433. //403 == you're not a mod
  434. //should be disabled if you're not a moderator
  435. if ( 403 == status )
  436. {
  437. gIMMgr->showSessionEventError(
  438. "mute",
  439. "not_a_moderator",
  440. mSessionID);
  441. }
  442. else
  443. {
  444. gIMMgr->showSessionEventError(
  445. "mute",
  446. "generic",
  447. mSessionID);
  448. }
  449. }
  450. }
  451. private:
  452. LLUUID mSessionID;
  453. };
  454. LLHTTPClient::post(
  455. url,
  456. data,
  457. new MuteVoiceResponder(speaker_mgr->getSessionID()));
  458. }
  459. closeFloater();
  460. }
  461. void LLInspectAvatar::updateVolumeSlider()
  462. {
  463. bool voice_enabled = LLVoiceClient::getInstance()->getVoiceEnabled(mAvatarID);
  464. // Do not display volume slider and mute button if it
  465. // is ourself or we are not in a voice channel together
  466. if (!voice_enabled || (mAvatarID == gAgent.getID()))
  467. {
  468. getChild<LLUICtrl>("mute_btn")->setVisible(false);
  469. getChild<LLUICtrl>("volume_slider")->setVisible(false);
  470. }
  471. else
  472. {
  473. getChild<LLUICtrl>("mute_btn")->setVisible(true);
  474. getChild<LLUICtrl>("volume_slider")->setVisible(true);
  475. // By convention, we only display and toggle voice mutes, not all mutes
  476. bool is_muted = LLMuteList::getInstance()->
  477. isMuted(mAvatarID, LLMute::flagVoiceChat);
  478. LLUICtrl* mute_btn = getChild<LLUICtrl>("mute_btn");
  479. bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");
  480. mute_btn->setEnabled( !is_linden);
  481. mute_btn->setValue( is_muted );
  482. LLUICtrl* volume_slider = getChild<LLUICtrl>("volume_slider");
  483. volume_slider->setEnabled( !is_muted );
  484. F32 volume;
  485. if (is_muted)
  486. {
  487. // it's clearer to display their volume as zero
  488. volume = 0.f;
  489. }
  490. else
  491. {
  492. // actual volume
  493. volume = LLVoiceClient::getInstance()->getUserVolume(mAvatarID);
  494. }
  495. volume_slider->setValue( (F64)volume );
  496. }
  497. }
  498. void LLInspectAvatar::onClickMuteVolume()
  499. {
  500. // By convention, we only display and toggle voice mutes, not all mutes
  501. LLMuteList* mute_list = LLMuteList::getInstance();
  502. bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat);
  503. LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT);
  504. if (!is_muted)
  505. {
  506. mute_list->add(mute, LLMute::flagVoiceChat);
  507. }
  508. else
  509. {
  510. mute_list->remove(mute, LLMute::flagVoiceChat);
  511. }
  512. updateVolumeSlider();
  513. }
  514. void LLInspectAvatar::onVolumeChange(const LLSD& data)
  515. {
  516. F32 volume = (F32)data.asReal();
  517. LLVoiceClient::getInstance()->setUserVolume(mAvatarID, volume);
  518. }
  519. void LLInspectAvatar::onAvatarNameCache(
  520. const LLUUID& agent_id,
  521. const LLAvatarName& av_name)
  522. {
  523. if (agent_id == mAvatarID)
  524. {
  525. getChild<LLUICtrl>("user_name")->setValue(av_name.mDisplayName);
  526. getChild<LLUICtrl>("user_name_small")->setValue(av_name.mDisplayName);
  527. getChild<LLUICtrl>("user_slid")->setValue(av_name.mUsername);
  528. mAvatarName = av_name;
  529. // show smaller display name if too long to display in regular size
  530. if (getChild<LLTextBox>("user_name")->getTextPixelWidth() > getChild<LLTextBox>("user_name")->getRect().getWidth())
  531. {
  532. getChild<LLUICtrl>("user_name_small")->setVisible( true );
  533. getChild<LLUICtrl>("user_name")->setVisible( false );
  534. }
  535. else
  536. {
  537. getChild<LLUICtrl>("user_name_small")->setVisible( false );
  538. getChild<LLUICtrl>("user_name")->setVisible( true );
  539. }
  540. }
  541. }
  542. void LLInspectAvatar::onClickAddFriend()
  543. {
  544. LLAvatarActions::requestFriendshipDialog(mAvatarID, mAvatarName.getLegacyName());
  545. closeFloater();
  546. }
  547. void LLInspectAvatar::onClickViewProfile()
  548. {
  549. LLAvatarActions::showProfile(mAvatarID);
  550. closeFloater();
  551. }
  552. bool LLInspectAvatar::isNotFriend()
  553. {
  554. return !LLAvatarActions::isFriend(mAvatarID);
  555. }
  556. bool LLInspectAvatar::onVisibleFindOnMap()
  557. {
  558. return gAgent.isGodlike() || is_agent_mappable(mAvatarID);
  559. }
  560. bool LLInspectAvatar::onVisibleEject()
  561. {
  562. return enable_freeze_eject( LLSD(mAvatarID) );
  563. }
  564. bool LLInspectAvatar::onVisibleFreeze()
  565. {
  566. // either user is a god and can do long distance freeze
  567. // or check for target proximity and permissions
  568. return gAgent.isGodlike() || enable_freeze_eject(LLSD(mAvatarID));
  569. }
  570. bool LLInspectAvatar::onVisibleZoomIn()
  571. {
  572. return gObjectList.findObject(mAvatarID);
  573. }
  574. void LLInspectAvatar::onClickIM()
  575. {
  576. LLAvatarActions::startIM(mAvatarID);
  577. closeFloater();
  578. }
  579. void LLInspectAvatar::onClickCall()
  580. {
  581. LLAvatarActions::startCall(mAvatarID);
  582. closeFloater();
  583. }
  584. void LLInspectAvatar::onClickTeleport()
  585. {
  586. LLAvatarActions::offerTeleport(mAvatarID);
  587. closeFloater();
  588. }
  589. void LLInspectAvatar::onClickInviteToGroup()
  590. {
  591. LLAvatarActions::inviteToGroup(mAvatarID);
  592. closeFloater();
  593. }
  594. void LLInspectAvatar::onClickPay()
  595. {
  596. LLAvatarActions::pay(mAvatarID);
  597. closeFloater();
  598. }
  599. void LLInspectAvatar::onClickShare()
  600. {
  601. LLAvatarActions::share(mAvatarID);
  602. closeFloater();
  603. }
  604. void LLInspectAvatar::onToggleMute()
  605. {
  606. LLMute mute(mAvatarID, mAvatarName.mDisplayName, LLMute::AGENT);
  607. if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))
  608. {
  609. LLMuteList::getInstance()->remove(mute);
  610. }
  611. else
  612. {
  613. LLMuteList::getInstance()->add(mute);
  614. }
  615. LLPanelBlockedList::showPanelAndSelect(mute.mID);
  616. closeFloater();
  617. }
  618. void LLInspectAvatar::onClickReport()
  619. {
  620. LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName.getCompleteName());
  621. closeFloater();
  622. }
  623. bool godlike_freeze(const LLSD& notification, const LLSD& response)
  624. {
  625. LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
  626. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  627. switch (option)
  628. {
  629. case 0:
  630. LLAvatarActions::freeze(avatar_id);
  631. break;
  632. case 1:
  633. LLAvatarActions::unfreeze(avatar_id);
  634. break;
  635. default:
  636. break;
  637. }
  638. return false;
  639. }
  640. void LLInspectAvatar::onClickFreeze()
  641. {
  642. if (gAgent.isGodlike())
  643. {
  644. // use godlike freeze-at-a-distance, with confirmation
  645. LLNotificationsUtil::add("FreezeAvatar",
  646. LLSD(),
  647. LLSD().with("avatar_id", mAvatarID),
  648. godlike_freeze);
  649. }
  650. else
  651. {
  652. // use default "local" version of freezing that requires avatar to be in range
  653. handle_avatar_freeze( LLSD(mAvatarID) );
  654. }
  655. closeFloater();
  656. }
  657. void LLInspectAvatar::onClickEject()
  658. {
  659. handle_avatar_eject( LLSD(mAvatarID) );
  660. closeFloater();
  661. }
  662. void LLInspectAvatar::onClickKick()
  663. {
  664. LLAvatarActions::kick(mAvatarID);
  665. closeFloater();
  666. }
  667. void LLInspectAvatar::onClickCSR()
  668. {
  669. std::string name;
  670. gCacheName->getFullName(mAvatarID, name);
  671. LLAvatarActions::csr(mAvatarID, name);
  672. closeFloater();
  673. }
  674. void LLInspectAvatar::onClickZoomIn()
  675. {
  676. handle_zoom_to_object(mAvatarID);
  677. closeFloater();
  678. }
  679. void LLInspectAvatar::onClickFindOnMap()
  680. {
  681. gFloaterWorldMap->trackAvatar(mAvatarID, mAvatarName.mDisplayName);
  682. LLFloaterReg::showInstance("world_map");
  683. }
  684. bool LLInspectAvatar::enableMute()
  685. {
  686. bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");
  687. bool is_self = mAvatarID == gAgent.getID();
  688. if (!is_linden && !is_self && !LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getLegacyName()))
  689. {
  690. return true;
  691. }
  692. else
  693. {
  694. return false;
  695. }
  696. }
  697. bool LLInspectAvatar::enableUnmute()
  698. {
  699. bool is_linden = LLStringUtil::endsWith(mAvatarName.getLegacyName(), " Linden");
  700. bool is_self = mAvatarID == gAgent.getID();
  701. if (!is_linden && !is_self && LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getLegacyName()))
  702. {
  703. return true;
  704. }
  705. else
  706. {
  707. return false;
  708. }
  709. }
  710. bool LLInspectAvatar::enableTeleportOffer()
  711. {
  712. return LLAvatarActions::canOfferTeleport(mAvatarID);
  713. }
  714. bool LLInspectAvatar::godModeEnabled()
  715. {
  716. return gAgent.isGodlike();
  717. }
  718. //////////////////////////////////////////////////////////////////////////////
  719. // LLInspectAvatarUtil
  720. //////////////////////////////////////////////////////////////////////////////
  721. void LLInspectAvatarUtil::registerFloater()
  722. {
  723. LLFloaterReg::add("inspect_avatar", "inspect_avatar.xml",
  724. &LLFloaterReg::build<LLInspectAvatar>);
  725. }