diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp
index 9dbbca976b..02a28b4317 100644
--- a/indra/llui/llchatentry.cpp
+++ b/indra/llui/llchatentry.cpp
@@ -278,3 +278,18 @@ void LLChatEntry::paste()
}
}
//
+
+// Add menu items to copy and/or insert mention URIs into chat
+void LLChatEntry::insertMentionAtCursor(const std::string& str)
+{
+ S32 cursor_from_end = getLength() - getCursorPos();
+
+ insertText(str);
+
+ std::string new_text(wstring_to_utf8str(getConvertedText()));
+ clear();
+ appendTextImpl(new_text, LLStyle::Params(), true);
+
+ setCursorPos(getLength() - cursor_from_end);
+}
+//
diff --git a/indra/llui/llchatentry.h b/indra/llui/llchatentry.h
index b87b15956c..7cffe854bb 100644
--- a/indra/llui/llchatentry.h
+++ b/indra/llui/llchatentry.h
@@ -71,6 +71,9 @@ public:
// Changed to public so we can update history when using modifier keys
void updateHistory();
+ // Add menu items to copy and/or insert mention URIs into chat
+ void insertMentionAtCursor(const std::string& str);
+
// Fix linefeed pasting
/*virtual*/ void paste();
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index c28b7d6070..15f80e0072 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -2451,6 +2451,11 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
enable_registrar.add("FS.EnableViewLog", std::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, EFSRegistrarFunctionActionType::FS_RGSTR_ACT_VIEW_TRANSCRIPT));
//
+ // Add menu items to copy and/or insert mention URIs into chat
+ registrar.add("Mention.CopyURI", boost::bind(&LLUrlAction::copyURLToClipboard, "secondlife:///app/agent/" + target_id_str + "/mention"));
+ registrar.add("Mention.Chat", boost::bind(&LLTextBase::insertMentionAtCursor, this, "secondlife:///app/agent/" + target_id_str + "/mention"));
+ //
+
// FIRE-30725 - Add more group functions to group URL context menu
registrar.add("FS.JoinGroup", std::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + target_id_str + "/groupjoin", true));
registrar.add("FS.LeaveGroup", std::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + target_id_str + "/groupleave", true));
@@ -2521,6 +2526,14 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
}
//
+ // Add menu items to copy and/or insert mention URIs into chat
+ if (!parent_floater || (parent_floater->getName() != "panel_im" && parent_floater->getName() != "nearby_chat"))
+ {
+ menu->getChild("MentionURISeparator")->setVisible(false);
+ menu->getChild("mention_in_chat")->setVisible(false);
+ }
+ //
+
menu->show(x, y);
LLMenuGL::showPopup(this, menu, x, y);
}
@@ -4577,3 +4590,10 @@ void LLTextBase::setWordWrap(bool wrap)
{
mWordWrap = wrap;
}
+
+// Add menu items to copy and/or insert mention URIs into chat
+// virtual
+void LLTextBase::insertMentionAtCursor(const std::string& str)
+{
+}
+//
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 87a5961b7d..b5ce3c2bd2 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -727,6 +727,9 @@ protected:
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link = e_underline::UNDERLINE_ALWAYS);
S32 normalizeUri(std::string& uri);
+ // Add menu items to copy and/or insert mention URIs into chat
+ virtual void insertMentionAtCursor(const std::string& str);
+
protected:
// virtual
std::string _getSearchText() const override
diff --git a/indra/newview/fschathistory.cpp b/indra/newview/fschathistory.cpp
index dfb0891dc3..45a66e44b5 100644
--- a/indra/newview/fschathistory.cpp
+++ b/indra/newview/fschathistory.cpp
@@ -128,6 +128,8 @@ LLObjectIMHandler gObjectIMHandler;
class FSChatHistoryHeader: public LLPanel
{
public:
+ typedef boost::function insert_mention_callback_t;
+
FSChatHistoryHeader()
: LLPanel(),
mInfoCtrl(NULL),
@@ -150,6 +152,7 @@ public:
mTimeBoxTextBox(NULL),
mHeaderLayoutStack(NULL),
mAvatarNameCacheConnection(),
+ mInsertMentionCallback(NULL),
mTime(0)
{}
@@ -180,6 +183,24 @@ public:
}
}
+ void setInsertMentionCallback(insert_mention_callback_t cb)
+ {
+ mInsertMentionCallback = cb;
+ }
+
+ void copyURLToClipboard()
+ {
+ LLUrlAction::copyURLToClipboard("secondlife:///app/agent/" + mAvatarID.asString() + "/mention");
+ }
+
+ void insertMentionAtCursor()
+ {
+ if (mInsertMentionCallback)
+ {
+ mInsertMentionCallback("secondlife:///app/agent/" + mAvatarID.asString() + "/mention");
+ }
+ }
+
bool handleMouseUp(S32 x, S32 y, MASK mask)
{
return LLPanel::handleMouseUp(x,y,mask);
@@ -1069,6 +1090,9 @@ protected:
registrar_enable.add("AvatarIcon.Enable", boost::bind(&FSChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2));
registrar_enable.add("AvatarIcon.Visible", boost::bind(&FSChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2));
+ registrar.add("Mention.CopyURI", boost::bind(&FSChatHistoryHeader::copyURLToClipboard, this));
+ registrar.add("Mention.Chat", boost::bind(&FSChatHistoryHeader::insertMentionAtCursor, this));
+
menu = LLUICtrlFactory::getInstance()->createFromFile("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
if (menu)
{
@@ -1256,6 +1280,8 @@ protected:
private:
boost::signals2::connection mAvatarNameCacheConnection;
+
+ insert_mention_callback_t mInsertMentionCallback;
};
FSChatHistory::FSChatHistory(const FSChatHistory::Params& p)
@@ -1353,6 +1379,17 @@ void FSChatHistory::initFromParams(const FSChatHistory::Params& p)
setShowContextMenu(true);
}
+// virtual
+void FSChatHistory::insertMentionAtCursor(const std::string& str)
+{
+ updateChatInputLine();
+ if (mChatInputLine)
+ {
+ mChatInputLine->insertMentionAtCursor(str);
+ mChatInputLine->setFocus(true);
+ }
+}
+
LLView* FSChatHistory::getSeparator()
{
LLPanel* separator = LLUICtrlFactory::getInstance()->createFromFile(mMessageSeparatorFilename, NULL, LLPanel::child_registry_t::instance());
@@ -1365,6 +1402,7 @@ LLView* FSChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style
if (header)
{
header->setup(chat, style_params, args);
+ header->setInsertMentionCallback(boost::bind(&FSChatHistory::insertMentionAtCursor, this, _1));
}
return header;
}
diff --git a/indra/newview/fschathistory.h b/indra/newview/fschathistory.h
index eea5f15067..a041d57ed0 100644
--- a/indra/newview/fschathistory.h
+++ b/indra/newview/fschathistory.h
@@ -110,6 +110,8 @@ class FSChatHistory : public LLTextEditor // FIRE-8600: TAB out of cha
LLSD getValue() const;
void initFromParams(const Params&);
+ virtual void insertMentionAtCursor(const std::string& str);
+
/**
* Appends a widget message.
* If last user appended message, concurs with current user,
diff --git a/indra/newview/fscontactsfriendsmenu.cpp b/indra/newview/fscontactsfriendsmenu.cpp
index 120d102af9..3573ac0fa0 100644
--- a/indra/newview/fscontactsfriendsmenu.cpp
+++ b/indra/newview/fscontactsfriendsmenu.cpp
@@ -61,6 +61,7 @@ LLContextMenu* FSContactsFriendsMenu::createMenu()
registrar.add("Contacts.Friends.CopyLabel", boost::bind(&FSContactsFriendsMenu::copyNameToClipboard, this, id));
registrar.add("Contacts.Friends.CopyUrl", boost::bind(&FSContactsFriendsMenu::copySLURLToClipboard, this, id));
registrar.add("Contacts.Friends.SelectOption", boost::bind(&FSContactsFriendsMenu::selectOption, this, _2));
+ registrar.add("Mention.CopyURI", boost::bind(&FSContactsFriendsMenu::copyURLToClipboard, this));
enable_registrar.add("Contacts.Friends.EnableItem", boost::bind(&FSContactsFriendsMenu::enableContextMenuItem, this, _2));
enable_registrar.add("Contacts.Friends.EnableZoomIn", boost::bind(&LLAvatarActions::canZoomIn, id));
@@ -237,3 +238,8 @@ bool FSContactsFriendsMenu::checkOption(const LLSD& userdata)
return false;
}
+
+void FSContactsFriendsMenu::copyURLToClipboard()
+{
+ LLUrlAction::copyURLToClipboard("secondlife:///app/agent/" + mUUIDs.front().asString() + "/mention");
+}
diff --git a/indra/newview/fscontactsfriendsmenu.h b/indra/newview/fscontactsfriendsmenu.h
index d8c0e21e6f..7c3dcff836 100644
--- a/indra/newview/fscontactsfriendsmenu.h
+++ b/indra/newview/fscontactsfriendsmenu.h
@@ -44,6 +44,7 @@ private:
void copySLURLToClipboard(const LLUUID& id);
void selectOption(const LLSD& userdata);
bool checkOption(const LLSD& userdata);
+ void copyURLToClipboard();
};
extern FSContactsFriendsMenu gFSContactsFriendsMenu;
diff --git a/indra/newview/fspanelimcontrolpanel.cpp b/indra/newview/fspanelimcontrolpanel.cpp
index 88a1b22ada..17a3351845 100644
--- a/indra/newview/fspanelimcontrolpanel.cpp
+++ b/indra/newview/fspanelimcontrolpanel.cpp
@@ -32,6 +32,8 @@
#include "fsparticipantlist.h"
#include "llagent.h"
+#include "llchatentry.h"
+#include "fsfloaterim.h"
#include "llimview.h"
#include "llspeakers.h"
@@ -88,9 +90,18 @@ void FSPanelGroupControlPanel::setSessionId(const LLUUID& session_id)
return;
mParticipantList = new FSParticipantList(speaker_manager, getChild("grp_speakers_list"), true,false);
+ if (mParticipantList)
+ {
+ mParticipantList->setInsertMentionCallback(boost::bind(&FSPanelGroupControlPanel::insertMentionAtCursor, this, _1));
+ }
}
}
+void FSPanelGroupControlPanel::insertMentionAtCursor(const LLUUID& avatar_id)
+{
+ FSFloaterIM::getInstance(getSessionId())->findChild("chat_editor")->insertMentionAtCursor("secondlife:///app/agent/" + avatar_id.asString() + "/mention");
+}
+
uuid_vec_t FSPanelGroupControlPanel::getParticipants() const
{
return mParticipantList->getAvatarIds();
diff --git a/indra/newview/fspanelimcontrolpanel.h b/indra/newview/fspanelimcontrolpanel.h
index f1877e9284..7ea3c8cedd 100644
--- a/indra/newview/fspanelimcontrolpanel.h
+++ b/indra/newview/fspanelimcontrolpanel.h
@@ -69,6 +69,7 @@ public:
void draw() override;
uuid_vec_t getParticipants() const override;
+ void insertMentionAtCursor(const LLUUID& url);
protected:
LLUUID mGroupID;
diff --git a/indra/newview/fsparticipantlist.cpp b/indra/newview/fsparticipantlist.cpp
index 4f3611dbc5..30229b52bc 100644
--- a/indra/newview/fsparticipantlist.cpp
+++ b/indra/newview/fsparticipantlist.cpp
@@ -39,6 +39,7 @@
#include "llnotificationsutil.h"
#include "lloutputmonitorctrl.h"
#include "llspeakers.h"
+#include "llurlaction.h"
#include "llviewercontrol.h"
#include "llviewermenu.h"
#include "llvoiceclient.h"
@@ -69,6 +70,7 @@ FSParticipantList::FSParticipantList(LLSpeakerMgr* data_source,
mParticipantListMenu(NULL),
mExcludeAgent(exclude_agent),
mValidateSpeakerCallback(NULL),
+ mInsertMentionCallback(NULL),
mConvType(CONV_UNKNOWN)
{
mSpeakerAddListener = new SpeakerAddListener(*this);
@@ -301,6 +303,11 @@ void FSParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t c
mValidateSpeakerCallback = cb;
}
+void FSParticipantList::setInsertMentionCallback(insert_mention_callback_t cb)
+{
+ mInsertMentionCallback = cb;
+}
+
void FSParticipantList::update()
{
mSpeakerMgr->update(true);
@@ -530,6 +537,9 @@ LLContextMenu* FSParticipantList::FSParticipantListMenu::createMenu()
registrar.add("ParticipantList.ModerateVoice", boost::bind(&FSParticipantList::FSParticipantListMenu::moderateVoice, this, _2));
+ registrar.add("Mention.CopyURI", boost::bind(&FSParticipantList::FSParticipantListMenu::copyURLToClipboard, this, mUUIDs.front()));
+ registrar.add("Mention.Chat", boost::bind(&FSParticipantList::FSParticipantListMenu::insertMentionAtCursor, this, mUUIDs.front()));
+
enable_registrar.add("ParticipantList.EnableItem", boost::bind(&FSParticipantList::FSParticipantListMenu::enableContextMenuItem, this, _2));
enable_registrar.add("ParticipantList.EnableItem.Moderate", boost::bind(&FSParticipantList::FSParticipantListMenu::enableModerateContextMenuItem, this, _2));
enable_registrar.add("ParticipantList.CheckItem", boost::bind(&FSParticipantList::FSParticipantListMenu::checkContextMenuItem, this, _2));
@@ -556,6 +566,19 @@ LLContextMenu* FSParticipantList::FSParticipantListMenu::createMenu()
return main_menu;
}
+void FSParticipantList::FSParticipantListMenu::copyURLToClipboard(const LLUUID& avatar_id)
+{
+ LLUrlAction::copyURLToClipboard("secondlife:///app/agent/" + mUUIDs.front().asString() + "/mention");
+}
+
+void FSParticipantList::FSParticipantListMenu::insertMentionAtCursor(const LLUUID& avatar_id)
+{
+ if (mParent.mInsertMentionCallback)
+ {
+ mParent.mInsertMentionCallback(avatar_id);
+ }
+}
+
void FSParticipantList::FSParticipantListMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
{
if (uuids.size() == 0) return;
diff --git a/indra/newview/fsparticipantlist.h b/indra/newview/fsparticipantlist.h
index e206d2d72c..0427b27083 100644
--- a/indra/newview/fsparticipantlist.h
+++ b/indra/newview/fsparticipantlist.h
@@ -53,6 +53,7 @@ public:
};
typedef boost::function validate_speaker_callback_t;
+ typedef boost::function insert_mention_callback_t;
FSParticipantList(LLSpeakerMgr* data_source,
LLAvatarList* avatar_list,
@@ -94,6 +95,7 @@ public:
* @see onAddItemEvent()
*/
void setValidateSpeakerCallback(validate_speaker_callback_t cb);
+ void setInsertMentionCallback(insert_mention_callback_t cb);
EConversationType const getType() const { return mConvType; }
@@ -240,6 +242,10 @@ protected:
static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response);
void handleAddToContactSet();
+
+ // mentions support
+ void copyURLToClipboard(const LLUUID& avatar_id);
+ void insertMentionAtCursor(const LLUUID& avatar_id);
};
/**
@@ -300,6 +306,8 @@ private:
LLPointer mSortByRecentSpeakers;
validate_speaker_callback_t mValidateSpeakerCallback;
+ insert_mention_callback_t mInsertMentionCallback;
+
EConversationType mConvType;
};
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
index 36e3f85472..de8e0e11e1 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
@@ -129,6 +129,14 @@
name="copy url">
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/en/menu_fs_contacts_friends.xml b/indra/newview/skins/default/xui/en/menu_fs_contacts_friends.xml
index 6451ccb2c5..8dd6be75f9 100644
--- a/indra/newview/skins/default/xui/en/menu_fs_contacts_friends.xml
+++ b/indra/newview/skins/default/xui/en/menu_fs_contacts_friends.xml
@@ -115,6 +115,15 @@
+
+
+
+
+