diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index b0572a070..f1999410c 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -436,20 +436,67 @@ class ContextUrl : public LLMemberListener } }; -class ContextUrlCopy : public LLMemberListener +class ContextIDUrl : public LLMemberListener { - - bool handleEvent(LLPointer, const LLSD& userdata) override +protected: + std::string getID(const std::string& type) const { const auto& url = get_focused_url(); - const auto& type = userdata.asStringRef(); // Empty works like avatar and group, "object" is an object (you needed to be told this) - const auto& id = type.empty() ? LLUrlAction::getUserID(url) : LLUrlAction::getObjectId(url); - LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(id)); + return type.empty() ? LLUrlAction::getUserID(url) : LLUrlAction::getObjectId(url); + } +}; + +class ContextUrlCopy : public ContextIDUrl +{ + bool handleEvent(LLPointer, const LLSD& userdata) override + { + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(getID(userdata.asStringRef()))); return true; } }; +class ContextUrlExt : public ContextIDUrl +{ + bool handleEvent(LLPointer, const LLSD& userdata) override + { + std::string cmd = userdata.asStringRef(); + std::string type; + const auto sep = cmd.find(','); + if (sep != std::string::npos) + { + type = cmd.substr(sep); + cmd = cmd.substr(0, sep); + } + mExtCallback(cmd, LLUUID(getID(type))); + return true; + } + LLTextEditor::ext_slurl_cb mExtCallback; +public: + ContextUrlExt(LLTextEditor::ext_slurl_cb cb) : mExtCallback(cb) {} +}; + +class ContextUrlExtVisible : public ContextIDUrl +{ + bool handleEvent(LLPointer, const LLSD& userdata) override + { + std::string cmd = userdata["data"]; + std::string type; + const auto sep = cmd.find(','); + if (sep != std::string::npos) + { + type = cmd.substr(sep); + cmd = cmd.substr(0, sep); + } + + LLMenuGL::sMenuContainer->findControl(userdata["control"].asString())->setValue(mExtVCB(cmd, LLUUID(getID(type)))); + return true; + } + LLTextEditor::ext_slurl_visible_cb mExtVCB; +public: + ContextUrlExtVisible(LLTextEditor::ext_slurl_visible_cb vcb) : mExtVCB(vcb) {} +}; + void LLTextEditor::spell_correct(void* data) { @@ -528,11 +575,13 @@ void LLTextEditor::spell_add(void* data) } //static -void LLTextEditor::addMenuListeners() +void LLTextEditor::addMenuListeners(ext_slurl_cb cb, ext_slurl_visible_cb vcb) { (new ContextText)->registerListener(LLMenuGL::sMenuContainer, "Text"); (new ContextUrl)->registerListener(LLMenuGL::sMenuContainer, "Text.Url"); (new ContextUrlCopy)->registerListener(LLMenuGL::sMenuContainer, "Text.Url.CopyUUID"); + (new ContextUrlExt(cb))->registerListener(LLMenuGL::sMenuContainer, "Text.Url.Ext"); + (new ContextUrlExtVisible(vcb))->registerListener(LLMenuGL::sMenuContainer, "Text.Url.ExtVisible"); } void LLTextEditor::setTrackColor( const LLColor4& color ) @@ -721,8 +770,8 @@ LLMenuGL* LLTextEditor::createUrlContextMenu(S32 x, S32 y, const std::string &in if (addFriendButton && removeFriendButton) { - addFriendButton->setEnabled(!isFriend); - removeFriendButton->setEnabled(isFriend); + addFriendButton->setVisible(!isFriend); + removeFriendButton->setVisible(isFriend); } } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index c8a67fdbd..b5d3eb699 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -80,7 +80,11 @@ public: static boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb); static boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb); - static void addMenuListeners(); + + typedef std::function ext_slurl_cb; + typedef std::function ext_slurl_visible_cb; + static void addMenuListeners(ext_slurl_cb cb, ext_slurl_visible_cb vcb); + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); virtual LLXMLNodePtr getXML(bool save_children = true) const; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 01aed529f..a494a025d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -63,6 +63,7 @@ #include "lldebugview.h" #include "llenvmanager.h" #include "llfirstuse.h" +#include "llfloateravatarlist.h" #include "llfloateravatartextures.h" #include "llfloaterbuy.h" #include "llfloaterbuycontents.h" @@ -9255,11 +9256,16 @@ class ListShare : public view_listener_t } }; +bool can_show_web_profile() +{ + return !gSavedSettings.getString("WebProfileURL").empty(); +} + +void show_log_browser(const LLUUID& id); class ListShowLog : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - void show_log_browser(const LLUUID& id); for (const LLUUID& id : get_focused_list_ids_selected()) show_log_browser(id); return true; @@ -9368,23 +9374,29 @@ class ListTrack : public view_listener_t }; void send_eject(const LLUUID& avatar_id, bool ban); +void confirm_eject(const uuid_vec_t& ids) +{ + LLNotificationsUtil::add("EjectAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_eject)); +} class ListEject : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("EjectAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_eject)); + confirm_eject(get_focused_list_ids_selected()); return true; } }; void send_freeze(const LLUUID& avatar_id, bool freeze); +void confirm_freeze(const uuid_vec_t& ids) +{ + LLNotificationsUtil::add("FreezeAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_freeze)); +} class ListFreeze : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("FreezeAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_freeze)); + confirm_freeze(get_focused_list_ids_selected()); return true; } }; @@ -9415,22 +9427,28 @@ void estate_bulk_eject(const uuid_vec_t& ids, bool ban, S32 option) if (!tphome) send_estate_message("kickestate", strings); } +void confirm_estate_ban(const uuid_vec_t& ids) +{ + LLNotificationsUtil::add("EstateBanUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, true, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); +} class ListEstateBan : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("EstateBanUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, true, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); + confirm_estate_ban(get_focused_list_ids_selected()); return true; } }; +void confirm_estate_kick(const uuid_vec_t& ids) +{ + LLNotificationsUtil::add("EstateKickUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, false, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); +} class ListEstateEject : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("EstateKickUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, false, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); + confirm_estate_kick(get_focused_list_ids_selected()); return true; } }; @@ -9446,6 +9464,59 @@ class ListToggleMute : public view_listener_t } }; +struct MenuSLURLDict : public LLSingleton +{ + typedef std::function cb; + typedef std::function vcb; + typedef std::map> slurl_menu_map; + slurl_menu_map mEntries; + MenuSLURLDict() + { + // Text Editor menus + LLTextEditor::setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0)); + LLTextEditor::setIsFriendCallback(LLAvatarActions::isFriend); + LLTextEditor::addMenuListeners(boost::bind(&MenuSLURLDict::action, this, _1, _2), boost::bind(&MenuSLURLDict::visible, this, _1, _2)); + + // Add the entries + insert("ShowWebProfile", boost::bind(LLAvatarActions::showProfile, _1, true), boost::bind(can_show_web_profile)); + insert("Pay", LLAvatarActions::pay); + insert("Call", LLAvatarActions::startCall); + insert("Share", LLAvatarActions::share); + insert("AbuseReport", LLFloaterReporter::showFromObject); + insert("InviteToGroup", [](const LLUUID& id) { LLAvatarActions::inviteToGroup(id); }); + insert("BanFromGroup", [](const LLUUID& id) { ban_from_group(uuid_vec_t(1, id)); }); + insert("ShowLog", [](const LLUUID& id) { show_log_browser(id); }); + insert("OfferTeleport", [](const LLUUID& id) { LLAvatarActions::offerTeleport(id); }, [](const LLUUID& id) { return LLAvatarActions::canOfferTeleport(id); }); + insert("RequestTeleport", LLAvatarActions::teleportRequest); + void teleport_to(const LLUUID& id); + insert("TeleportTo", teleport_to, is_nearby); + insert("Focus", LLFloaterAvatarList::setFocusAvatar, is_nearby); + insert("ParcelEject", [](const LLUUID& id) { confirm_eject(uuid_vec_t(1, id)); }, is_nearby); + insert("Freeze", [](const LLUUID& id) { confirm_freeze(uuid_vec_t(1, id)); }, is_nearby); + insert("EstateBan", [](const LLUUID& id) { confirm_estate_ban(uuid_vec_t(1, id)); }, is_nearby); + insert("EstateEject", [](const LLUUID & id) { confirm_estate_kick(uuid_vec_t(1, id)); }, is_nearby); + insert("Mute", LLAvatarActions::toggleBlock, [](const LLUUID& id) { return LLAvatarActions::canBlock(id) && !LLAvatarActions::isBlocked(id); }); + insert("Unmute", LLAvatarActions::toggleBlock, LLAvatarActions::isBlocked); + } + + void insert(const std::string& key, cb callback, vcb vcallback = nullptr) + { + mEntries[key] = std::make_pair(callback, vcallback); + } + + void action(const std::string& cmd, LLUUID id) const + { + auto it = mEntries.find(cmd); + if (it != mEntries.end()) + (*it).second.first(id); + } + bool visible(const std::string& cmd, LLUUID id) const + { + auto it = mEntries.find(cmd); + return it == mEntries.end() || !(*it).second.second || (*it).second.second(id); + } +}; + LLMediaCtrl* get_focused_media_ctrl() { auto media_ctrl = dynamic_cast(gFocusMgr.getKeyboardFocus()); @@ -9837,10 +9908,7 @@ void initialize_menus() add_radar_listeners(); - // Text Editor menus - LLTextEditor::setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0)); - LLTextEditor::setIsFriendCallback(LLAvatarActions::isFriend); - LLTextEditor::addMenuListeners(); + MenuSLURLDict::getInstance(); // Media Ctrl menus addMenu(new MediaCtrlCopyURL(), "Copy.PageURL"); diff --git a/indra/newview/skins/default/xui/en-us/menu_url_agent.xml b/indra/newview/skins/default/xui/en-us/menu_url_agent.xml index f9403282e..e23b42855 100644 --- a/indra/newview/skins/default/xui/en-us/menu_url_agent.xml +++ b/indra/newview/skins/default/xui/en-us/menu_url_agent.xml @@ -10,6 +10,14 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_agent_mini.xml b/indra/newview/skins/default/xui/en-us/menu_url_agent_mini.xml index ba3c272d7..c54fe7b61 100644 --- a/indra/newview/skins/default/xui/en-us/menu_url_agent_mini.xml +++ b/indra/newview/skins/default/xui/en-us/menu_url_agent_mini.xml @@ -10,6 +10,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +