From 8380fe9f71a9fe7906528aed3f06cafa5ae7e6f9 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 8 Jul 2013 01:41:07 +0200 Subject: [PATCH] Undo CHUI-90 and make avatar inspector useful again --- indra/newview/llinspectavatar.cpp | 494 +++++++++++++++++- .../skins/default/xui/en/inspect_avatar.xml | 100 +++- .../xui/en/menu_inspect_avatar_gear.xml | 151 ++++++ .../default/xui/en/menu_inspect_self_gear.xml | 260 +++++++++ 4 files changed, 987 insertions(+), 18 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml create mode 100644 indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 9c6db3676f..85dd92f6f7 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -48,6 +48,22 @@ #include "lltooltip.h" // positionViewNearMouse() #include "lltrans.h" +// Undo CHUI-90 and make avatar inspector useful again +#include "llagentdata.h" +#include "llcallingcard.h" +#include "llfloaterreporter.h" +#include "llfloaterworldmap.h" +#include "llimview.h" +#include "llpanelblockedlist.h" +#include "llspeakers.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llnotificationsutil.h" +#include "llmenubutton.h" +#include "lltoggleablemenu.h" +#include "lluictrl.h" +// + class LLFetchAvatarData; @@ -78,6 +94,15 @@ public: void processAvatarData(LLAvatarData* data); virtual LLTransientFloaterMgr::ETransientGroup getGroup() { return LLTransientFloaterMgr::GLOBAL; } + + // Undo CHUI-90 and make avatar inspector useful again + // When closing they should close their gear menu + /*virtual*/ void onClose(bool app_quitting); + + // override the inspector mouse leave so timer is only paused if + // gear menu is not open + /* virtual */ void onMouseLeave(S32 x, S32 y, MASK mask); + // private: // Make network requests for all the data to display in this view. @@ -88,10 +113,48 @@ private: // hiding/disabling if the user is not nearby. void updateVolumeSlider(); + // Undo CHUI-90 and make avatar inspector useful again + // Shows/hides moderator panel depending on voice state + void updateModeratorPanel(); + + // Moderator ability to enable/disable voice chat for avatar + void toggleSelectedVoice(bool enabled); + // + // Button callbacks void onClickMuteVolume(); void onVolumeChange(const LLSD& data); - + + // Undo CHUI-90 and make avatar inspector useful again + void onClickAddFriend(); + void onClickViewProfile(); + void onClickIM(); + void onClickCall(); + void onClickTeleport(); + void onClickInviteToGroup(); + void onClickPay(); + void onClickShare(); + void onToggleMute(); + void onClickReport(); + void onClickFreeze(); + void onClickEject(); + void onClickKick(); + void onClickCSR(); + void onClickZoomIn(); + void onClickFindOnMap(); + bool onVisibleFindOnMap(); + bool onVisibleEject(); + bool onVisibleFreeze(); + bool onVisibleZoomIn(); + bool enableMute(); + bool enableUnmute(); + bool enableTeleportOffer(); + bool godModeEnabled(); + + // Is used to determine if "Add friend" option should be enabled in gear menu + bool isNotFriend(); + // + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); @@ -158,6 +221,39 @@ LLInspectAvatar::LLInspectAvatar(const LLSD& sd) mPropertiesRequest(NULL), mAvatarNameCacheConnection() { + // Undo CHUI-90 and make avatar inspector useful again + mCommitCallbackRegistrar.add("InspectAvatar.ViewProfile", boost::bind(&LLInspectAvatar::onClickViewProfile, this)); + mCommitCallbackRegistrar.add("InspectAvatar.AddFriend", boost::bind(&LLInspectAvatar::onClickAddFriend, this)); + mCommitCallbackRegistrar.add("InspectAvatar.IM", + boost::bind(&LLInspectAvatar::onClickIM, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Call", boost::bind(&LLInspectAvatar::onClickCall, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Teleport", boost::bind(&LLInspectAvatar::onClickTeleport, this)); + mCommitCallbackRegistrar.add("InspectAvatar.InviteToGroup", boost::bind(&LLInspectAvatar::onClickInviteToGroup, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Pay", boost::bind(&LLInspectAvatar::onClickPay, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Share", boost::bind(&LLInspectAvatar::onClickShare, this)); + mCommitCallbackRegistrar.add("InspectAvatar.ToggleMute", boost::bind(&LLInspectAvatar::onToggleMute, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Freeze", boost::bind(&LLInspectAvatar::onClickFreeze, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Eject", boost::bind(&LLInspectAvatar::onClickEject, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Kick", boost::bind(&LLInspectAvatar::onClickKick, this)); + mCommitCallbackRegistrar.add("InspectAvatar.CSR", boost::bind(&LLInspectAvatar::onClickCSR, this)); + mCommitCallbackRegistrar.add("InspectAvatar.Report", boost::bind(&LLInspectAvatar::onClickReport, this)); + mCommitCallbackRegistrar.add("InspectAvatar.FindOnMap", boost::bind(&LLInspectAvatar::onClickFindOnMap, this)); + mCommitCallbackRegistrar.add("InspectAvatar.ZoomIn", boost::bind(&LLInspectAvatar::onClickZoomIn, this)); + mCommitCallbackRegistrar.add("InspectAvatar.DisableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, false)); + mCommitCallbackRegistrar.add("InspectAvatar.EnableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, true)); + + mEnableCallbackRegistrar.add("InspectAvatar.EnableGod", boost::bind(&LLInspectAvatar::godModeEnabled, this)); + mEnableCallbackRegistrar.add("InspectAvatar.VisibleFindOnMap", boost::bind(&LLInspectAvatar::onVisibleFindOnMap, this)); + mEnableCallbackRegistrar.add("InspectAvatar.VisibleEject", boost::bind(&LLInspectAvatar::onVisibleEject, this)); + mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreeze", boost::bind(&LLInspectAvatar::onVisibleFreeze, this)); + mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn", boost::bind(&LLInspectAvatar::onVisibleZoomIn, this)); + mEnableCallbackRegistrar.add("InspectAvatar.Gear.Enable", boost::bind(&LLInspectAvatar::isNotFriend, this)); + mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableCall", boost::bind(&LLAvatarActions::canCall)); + mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableTeleportOffer", boost::bind(&LLInspectAvatar::enableTeleportOffer, this)); + mEnableCallbackRegistrar.add("InspectAvatar.EnableMute", boost::bind(&LLInspectAvatar::enableMute, this)); + mEnableCallbackRegistrar.add("InspectAvatar.EnableUnmute", boost::bind(&LLInspectAvatar::enableUnmute, this)); + // + // can't make the properties request until the widgets are constructed // as it might return immediately, so do it in onOpen. @@ -182,6 +278,14 @@ LLInspectAvatar::~LLInspectAvatar() /*virtual*/ BOOL LLInspectAvatar::postBuild(void) { + // Undo CHUI-90 and make avatar inspector useful again + getChild("add_friend_btn")->setCommitCallback( + boost::bind(&LLInspectAvatar::onClickAddFriend, this) ); + + getChild("view_profile_btn")->setCommitCallback( + boost::bind(&LLInspectAvatar::onClickViewProfile, this) ); + // + getChild("mute_btn")->setCommitCallback( boost::bind(&LLInspectAvatar::onClickMuteVolume, this) ); @@ -202,6 +306,13 @@ void LLInspectAvatar::onOpen(const LLSD& data) // Extract appropriate avatar id mAvatarID = data["avatar_id"]; + // Undo CHUI-90 and make avatar inspector useful again + BOOL self = mAvatarID == gAgent.getID(); + + getChild("gear_self_btn")->setVisible(self); + getChild("gear_btn")->setVisible(!self); + // + // Position the inspector relative to the mouse cursor // Similar to how tooltips are positioned // See LLToolTipMgr::createToolTip @@ -215,14 +326,26 @@ void LLInspectAvatar::onOpen(const LLSD& data) } // Generate link to avatar profile. - getChild("avatar_profile_link")->setTextArg("[LINK]", LLSLURL("agent", mAvatarID, "about").getSLURLString()); + // Undo CHUI-90 and make avatar inspector useful again + //getChild("avatar_profile_link")->setTextArg("[LINK]", LLSLURL("agent", mAvatarID, "about").getSLURLString()); // can't call from constructor as widgets are not built yet requestUpdate(); updateVolumeSlider(); + + // Undo CHUI-90 and make avatar inspector useful again + updateModeratorPanel(); } +// Undo CHUI-90 and make avatar inspector useful again +// virtual +void LLInspectAvatar::onClose(bool app_quitting) +{ + getChild("gear_btn")->hideMenu(); +} +// + void LLInspectAvatar::requestUpdate() { // Don't make network requests when spawning from the debug menu at the @@ -249,6 +372,27 @@ void LLInspectAvatar::requestUpdate() delete mPropertiesRequest; mPropertiesRequest = new LLFetchAvatarData(mAvatarID, this); + // Undo CHUI-90 and make avatar inspector useful again + // You can't re-add someone as a friend if they are already your friend + bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL; + bool is_self = (mAvatarID == gAgentID); + if (is_self) + { + getChild("add_friend_btn")->setVisible(false); + getChild("im_btn")->setVisible(false); + } + else if (is_friend) + { + getChild("add_friend_btn")->setVisible(false); + getChild("im_btn")->setVisible(true); + } + else + { + getChild("add_friend_btn")->setVisible(true); + getChild("im_btn")->setVisible(false); + } + // + // Use an avatar_icon even though the image id will come down with the // avatar properties because the avatar_icon code maintains a cache of icons // and this may result in the image being visible sooner. @@ -399,6 +543,352 @@ void LLInspectAvatar::onAvatarNameCache( } } +// Undo CHUI-90 and make avatar inspector useful again +// For the avatar inspector, we only want to unpause the fade timer +// if neither the gear menu or self gear menu are open +void LLInspectAvatar::onMouseLeave(S32 x, S32 y, MASK mask) +{ + LLToggleableMenu* gear_menu = getChild("gear_btn")->getMenu(); + LLToggleableMenu* gear_menu_self = getChild("gear_self_btn")->getMenu(); + if ( gear_menu && gear_menu->getVisible() && + gear_menu_self && gear_menu_self->getVisible() ) + { + return; + } + + if(childHasVisiblePopupMenu()) + { + return; + } + + mOpenTimer.unpause(); +} + +void LLInspectAvatar::updateModeratorPanel() +{ + bool enable_moderator_panel = false; + + if (LLVoiceChannel::getCurrentVoiceChannel() && + mAvatarID != gAgent.getID()) + { + LLUUID session_id = LLVoiceChannel::getCurrentVoiceChannel()->getSessionID(); + + if (session_id != LLUUID::null) + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + + if (speaker_mgr) + { + LLPointer self_speakerp = speaker_mgr->findSpeaker(gAgent.getID()); + LLPointer selected_speakerp = speaker_mgr->findSpeaker(mAvatarID); + + if(speaker_mgr->isVoiceActive() && selected_speakerp && + selected_speakerp->isInVoiceChannel() && + ((self_speakerp && self_speakerp->mIsModerator) || gAgent.isGodlike())) + { + getChild("enable_voice")->setVisible(selected_speakerp->mModeratorMutedVoice); + getChild("disable_voice")->setVisible(!selected_speakerp->mModeratorMutedVoice); + + enable_moderator_panel = true; + } + } + } + } + + if (enable_moderator_panel) + { + if (!getChild("moderator_panel")->getVisible()) + { + getChild("moderator_panel")->setVisible(true); + // stretch the floater so it can accommodate the moderator panel + reshape(getRect().getWidth(), getRect().getHeight() + getChild("moderator_panel")->getRect().getHeight()); + } + } + else if (getChild("moderator_panel")->getVisible()) + { + getChild("moderator_panel")->setVisible(false); + // shrink the inspector floater back to original size + reshape(getRect().getWidth(), getRect().getHeight() - getChild("moderator_panel")->getRect().getHeight()); + } +} + +void LLInspectAvatar::toggleSelectedVoice(bool enabled) +{ + LLUUID session_id = LLVoiceChannel::getCurrentVoiceChannel()->getSessionID(); + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + + if (speaker_mgr) + { + if (!gAgent.getRegion()) + return; + + std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); + LLSD data; + data["method"] = "mute update"; + data["session-id"] = session_id; + data["params"] = LLSD::emptyMap(); + data["params"]["agent_id"] = mAvatarID; + data["params"]["mute_info"] = LLSD::emptyMap(); + // ctrl value represents ability to type, so invert + data["params"]["mute_info"]["voice"] = !enabled; + + class MuteVoiceResponder : public LLHTTPClient::Responder + { + public: + MuteVoiceResponder(const LLUUID& session_id) + { + mSessionID = session_id; + } + + virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + { + llwarns << "MuteVoiceResponder error [status:" << status << "]: " << content << llendl; + + if ( gIMMgr ) + { + //403 == you're not a mod + //should be disabled if you're not a moderator + if ( 403 == status ) + { + gIMMgr->showSessionEventError( + "mute", + "not_a_moderator", + mSessionID); + } + else + { + gIMMgr->showSessionEventError( + "mute", + "generic", + mSessionID); + } + } + } + + private: + LLUUID mSessionID; + }; + + LLHTTPClient::post( + url, + data, + new MuteVoiceResponder(speaker_mgr->getSessionID())); + } + + closeFloater(); + +} + +void LLInspectAvatar::onClickAddFriend() +{ + LLAvatarActions::requestFriendshipDialog(mAvatarID, mAvatarName.getDisplayName()); + closeFloater(); +} + +void LLInspectAvatar::onClickViewProfile() +{ + LLAvatarActions::showProfile(mAvatarID); + closeFloater(); +} + +bool LLInspectAvatar::isNotFriend() +{ + return !LLAvatarActions::isFriend(mAvatarID); +} + +bool LLInspectAvatar::onVisibleFindOnMap() +{ + return gAgent.isGodlike() || is_agent_mappable(mAvatarID); +} + +bool LLInspectAvatar::onVisibleEject() +{ + return enable_freeze_eject( LLSD(mAvatarID) ); +} + +bool LLInspectAvatar::onVisibleFreeze() +{ + // either user is a god and can do long distance freeze + // or check for target proximity and permissions + return gAgent.isGodlike() || enable_freeze_eject(LLSD(mAvatarID)); +} + +bool LLInspectAvatar::onVisibleZoomIn() +{ + return gObjectList.findObject(mAvatarID); +} + +void LLInspectAvatar::onClickIM() +{ + LLAvatarActions::startIM(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickCall() +{ + LLAvatarActions::startCall(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickTeleport() +{ + LLAvatarActions::offerTeleport(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickInviteToGroup() +{ + LLAvatarActions::inviteToGroup(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickPay() +{ + LLAvatarActions::pay(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickShare() +{ + LLAvatarActions::share(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onToggleMute() +{ + LLMute mute(mAvatarID, mAvatarName.getDisplayName(), LLMute::AGENT); + + if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName)) + { + LLMuteList::getInstance()->remove(mute); + } + else + { + LLMuteList::getInstance()->add(mute); + } + + LLPanelBlockedList::showPanelAndSelect(mute.mID); + closeFloater(); +} + +void LLInspectAvatar::onClickReport() +{ + LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName.getCompleteName()); + closeFloater(); +} + +bool godlike_freeze(const LLSD& notification, const LLSD& response) +{ + LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + switch (option) + { + case 0: + LLAvatarActions::freeze(avatar_id); + break; + case 1: + LLAvatarActions::unfreeze(avatar_id); + break; + default: + break; + } + + return false; +} + +void LLInspectAvatar::onClickFreeze() +{ + if (gAgent.isGodlike()) + { + // use godlike freeze-at-a-distance, with confirmation + LLNotificationsUtil::add("FreezeAvatar", + LLSD(), + LLSD().with("avatar_id", mAvatarID), + godlike_freeze); + } + else + { + // use default "local" version of freezing that requires avatar to be in range + handle_avatar_freeze( LLSD(mAvatarID) ); + } + closeFloater(); +} + +void LLInspectAvatar::onClickEject() +{ + handle_avatar_eject( LLSD(mAvatarID) ); + closeFloater(); +} + +void LLInspectAvatar::onClickKick() +{ + LLAvatarActions::kick(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickCSR() +{ + std::string name; + gCacheName->getFullName(mAvatarID, name); + LLAvatarActions::csr(mAvatarID, name); + closeFloater(); +} + +void LLInspectAvatar::onClickZoomIn() +{ + handle_zoom_to_object(mAvatarID); + closeFloater(); +} + +void LLInspectAvatar::onClickFindOnMap() +{ + gFloaterWorldMap->trackAvatar(mAvatarID, mAvatarName.getDisplayName()); + LLFloaterReg::showInstance("world_map"); +} + + +bool LLInspectAvatar::enableMute() +{ + bool is_linden = LLStringUtil::endsWith(mAvatarName.getDisplayName(), " Linden"); + bool is_self = mAvatarID == gAgent.getID(); + + if (!is_linden && !is_self && !LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getDisplayName())) + { + return true; + } + else + { + return false; + } +} + +bool LLInspectAvatar::enableUnmute() +{ + bool is_linden = LLStringUtil::endsWith(mAvatarName.getDisplayName(), " Linden"); + bool is_self = mAvatarID == gAgent.getID(); + + if (!is_linden && !is_self && LLMuteList::getInstance()->isMuted(mAvatarID, mAvatarName.getDisplayName())) + { + return true; + } + else + { + return false; + } +} + +bool LLInspectAvatar::enableTeleportOffer() +{ + return LLAvatarActions::canOfferTeleport(mAvatarID); +} + +bool LLInspectAvatar::godModeEnabled() +{ + return gAgent.isGodlike(); +} +// + ////////////////////////////////////////////////////////////////////////////// // LLInspectAvatarUtil ////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/skins/default/xui/en/inspect_avatar.xml b/indra/newview/skins/default/xui/en/inspect_avatar.xml index ef4f19cd4c..bc3bcd331b 100644 --- a/indra/newview/skins/default/xui/en/inspect_avatar.xml +++ b/indra/newview/skins/default/xui/en/inspect_avatar.xml @@ -2,14 +2,14 @@ +-->