summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llui/llfolderview.cpp9
-rw-r--r--indra/llui/llfolderview.h2
-rw-r--r--indra/newview/llconversationmodel.cpp43
-rwxr-xr-xindra/newview/llconversationmodel.h19
-rw-r--r--indra/newview/llimfloater.h1
-rw-r--r--indra/newview/llimfloatercontainer.cpp199
-rw-r--r--indra/newview/llimfloatercontainer.h5
-rw-r--r--indra/newview/llinventorypanel.cpp1
-rw-r--r--indra/newview/skins/default/xui/en/menu_conversation.xml109
9 files changed, 383 insertions, 5 deletions
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index ce1bc5914c..9a4a90206b 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -138,7 +138,8 @@ LLFolderView::Params::Params()
use_label_suffix("use_label_suffix"),
allow_multiselect("allow_multiselect", true),
show_empty_message("show_empty_message", true),
- use_ellipses("use_ellipses", false)
+ use_ellipses("use_ellipses", false),
+ options_menu("options_menu", "")
{
folder_indentation = -4;
}
@@ -228,7 +229,7 @@ LLFolderView::LLFolderView(const Params& p)
// make the popup menu available
- LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
+ LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
if (!menu)
{
menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
@@ -1530,14 +1531,18 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
&& menu )
{
if (mCallbackRegistrar)
+ {
mCallbackRegistrar->pushScope();
+ }
updateMenuOptions(menu);
menu->updateParent(LLMenuGL::sMenuContainer);
LLMenuGL::showPopup(this, menu, x, y);
if (mCallbackRegistrar)
+ {
mCallbackRegistrar->popScope();
+ }
}
else
{
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 81b0f087e8..487391a477 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -94,6 +94,8 @@ public:
use_ellipses,
show_item_link_overlays;
Mandatory<LLFolderViewModelInterface*> view_model;
+ Mandatory<std::string> options_menu;
+
Params();
};
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 9fa8758d11..265f77365f 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -84,6 +84,24 @@ void LLConversationItem::showProperties(void)
{
}
+void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items)
+{
+ items.push_back(std::string("view_profile"));
+ items.push_back(std::string("im"));
+ items.push_back(std::string("offer_teleport"));
+ items.push_back(std::string("voice_call"));
+ items.push_back(std::string("chat_history"));
+ items.push_back(std::string("separator_chat_history"));
+ items.push_back(std::string("add_friend"));
+ items.push_back(std::string("remove_friend"));
+ items.push_back(std::string("invite_to_group"));
+ items.push_back(std::string("separator_invite_to_group"));
+ items.push_back(std::string("map"));
+ items.push_back(std::string("share"));
+ items.push_back(std::string("pay"));
+ items.push_back(std::string("block_unblock"));
+}
+
//
// LLConversationItemSession
//
@@ -191,6 +209,22 @@ void LLConversationItemSession::setDistance(const LLUUID& participant_id, F64 di
}
}
+void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ lldebugs << "LLConversationItemParticipant::buildContextMenu()" << llendl;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ if(this->getType() == CONV_SESSION_1_ON_1)
+ {
+ items.push_back(std::string("close_conversation"));
+ items.push_back(std::string("separator_disconnect_from_voice"));
+ buildParticipantMenuOptions(items);
+ }
+
+ hide_context_entries(menu, items, disabled_items);
+}
+
// The time of activity of a session is the time of the most recent activity, session and participants included
const bool LLConversationItemSession::getTime(F64& time) const
{
@@ -249,6 +283,15 @@ LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid,
mConvType = CONV_PARTICIPANT;
}
+void LLConversationItemParticipant::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ buildParticipantMenuOptions(items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
void LLConversationItemParticipant::onAvatarNameCache(const LLAvatarName& av_name)
{
mName = (av_name.mUsername.empty() ? av_name.mDisplayName : av_name.mUsername);
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index 30f94d51ae..f84fbe39f1 100755
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -41,6 +41,8 @@ class LLConversationItemParticipant;
typedef std::map<LLUUID, LLConversationItem*> conversations_items_map;
typedef std::map<LLUUID, LLFolderViewItem*> conversations_widgets_map;
+typedef std::vector<std::string> menuentry_vec_t;
+
// Conversation items: we hold a list of those and create an LLFolderViewItem widget for each
// that we tuck into the mConversationsListPanel.
class LLConversationItem : public LLFolderViewModelItemCommon
@@ -124,6 +126,8 @@ public:
void resetRefresh() { mNeedsRefresh = false; }
bool needsRefresh() { return mNeedsRefresh; }
+ void buildParticipantMenuOptions(menuentry_vec_t& items);
+
protected:
std::string mName; // Name of the session or the participant
LLUUID mUUID; // UUID of the session or the participant
@@ -155,6 +159,7 @@ public:
bool isLoaded() { return mIsLoaded; }
+ void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual const bool getTime(F64& time) const;
void dumpDebugData();
@@ -178,7 +183,8 @@ public:
void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; }
void setTimeNow() { mLastActiveTime = LLFrameTimer::getElapsedSeconds(); mNeedsRefresh = true; }
void setDistance(F64 dist) { mDistToAgent = dist; mNeedsRefresh = true; }
-
+
+ void buildContextMenu(LLMenuGL& menu, U32 flags);
void onAvatarNameCache(const LLAvatarName& av_name);
virtual const bool getDistanceToAgent(F64& dist) const { dist = mDistToAgent; return (dist >= 0.0); }
@@ -273,4 +279,15 @@ public:
private:
};
+// Utility function to hide all entries except those in the list
+// Can be called multiple times on the same menu (e.g. if multiple items
+// are selected). If "append" is false, then only common enabled items
+// are set as enabled.
+
+//(defined in inventorybridge.cpp)
+//TODO: Gilbert Linden - Refactor to make this function non-global
+void hide_context_entries(LLMenuGL& menu,
+ const menuentry_vec_t &entries_to_show,
+ const menuentry_vec_t &disabled_entries);
+
#endif // LL_LLCONVERSATIONMODEL_H
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index d444270716..5ed1d1ab35 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -127,6 +127,7 @@ public:
static void onIMChicletCreated(const LLUUID& session_id);
bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; }
+ const LLUUID& getOtherParticipantUUID() {return mOtherParticipantUUID;}
static boost::signals2::connection setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb);
static floater_showed_signal_t sIMFloaterShowedSignal;
diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp
index 6f7eb7822a..d25a195f33 100644
--- a/indra/newview/llimfloatercontainer.cpp
+++ b/indra/newview/llimfloatercontainer.cpp
@@ -58,8 +58,12 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed)
mConversationsRoot(NULL),
mInitialized(false)
{
+ mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2));
mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLIMFloaterContainer::onCustomAction, this, _2));
- mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2));
+
+ mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLIMFloaterContainer::checkContextMenuItem, this, _2));
+ mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLIMFloaterContainer::enableContextMenuItem, this, _2));
+ mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLIMFloaterContainer::doToSelected, this, _2));
// Firstly add our self to IMSession observers, so we catch session events
LLIMMgr::getInstance()->addSessionObserver(this);
@@ -134,7 +138,9 @@ BOOL LLIMFloaterContainer::postBuild()
p.view_model = &mConversationViewModel;
p.root = NULL;
p.use_ellipses = true;
+ p.options_menu = "menu_conversation.xml";
mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
+ mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
// a scroller for folder view
LLRect scroller_view_rect = mConversationsListPanel->getRect();
@@ -547,7 +553,7 @@ void LLIMFloaterContainer::collapseConversationsPane(bool collapse)
{
widget->setOpen(false);
}
- }
+}
}
}
@@ -711,6 +717,195 @@ void LLIMFloaterContainer::setSortOrder(const LLConversationSort& order)
gSavedSettings.setU32("ConversationSortOrder", (U32)order);
}
+void LLIMFloaterContainer::getSelectedUUIDs(uuid_vec_t& selected_uuids)
+{
+ const std::set<LLFolderViewItem*> selectedItems = mConversationsRoot->getSelectionList();
+
+ std::set<LLFolderViewItem*>::const_iterator it = selectedItems.begin();
+ const std::set<LLFolderViewItem*>::const_iterator it_end = selectedItems.end();
+ LLConversationItem * conversationItem;
+
+ for (; it != it_end; ++it)
+ {
+ conversationItem = static_cast<LLConversationItem *>((*it)->getViewModelItem());
+ selected_uuids.push_back(conversationItem->getUUID());
+ }
+}
+void LLIMFloaterContainer::doToSelected(const LLSD& userdata)
+{
+ std::string command = userdata.asString();
+ uuid_vec_t selected_uuids;
+ LLUUID currentSelectedUUID;
+ LLIMFloater * conversation;
+
+ getSelectedUUIDs(selected_uuids);
+ //Find the conversation floater associated with the selected id
+ conversation = LLIMFloater::findInstance(selected_uuids.front());
+
+ //When a one-on-one conversation exists, retrieve the participant id from the conversation floater b/c
+ //selected_uuids.front() does not pertain to the UUID of the person you are having the conversation with.
+ if(conversation &&
+ mConversationsRoot &&
+ mConversationsRoot->getCurSelectedItem() &&
+ mConversationsRoot->getCurSelectedItem()->getViewModelItem() &&
+ static_cast<LLConversationItem *>(mConversationsRoot->getCurSelectedItem()->getViewModelItem())->getType() == LLConversationItem::CONV_SESSION_1_ON_1)
+ {
+ currentSelectedUUID = conversation->getOtherParticipantUUID();
+ }
+ //Otherwise can get the UUID directly from selected_uuids
+ else
+ {
+ currentSelectedUUID = selected_uuids.front();
+ }
+
+ //Close the selected conversation
+ if(conversation && "close_conversation" == command)
+ {
+ LLFloater::onClickClose(conversation);
+ }
+ else if ("view_profile" == command)
+ {
+ LLAvatarActions::showProfile(currentSelectedUUID);
+ }
+ else if("im" == command)
+ {
+ LLAvatarActions::startIM(currentSelectedUUID);
+ }
+ else if("offer_teleport" == command)
+ {
+ LLAvatarActions::offerTeleport(selected_uuids);
+ }
+ else if("voice_call" == command)
+ {
+ LLAvatarActions::startCall(currentSelectedUUID);
+ }
+ else if("add_friend" == command)
+ {
+ LLAvatarActions::requestFriendshipDialog(currentSelectedUUID);
+ }
+ else if("remove_friend" == command)
+ {
+ LLAvatarActions::removeFriendDialog(currentSelectedUUID);
+ }
+ else if("invite_to_group" == command)
+ {
+ LLAvatarActions::inviteToGroup(currentSelectedUUID);
+ }
+ else if("map" == command)
+ {
+ LLAvatarActions::showOnMap(currentSelectedUUID);
+ }
+ else if("share" == command)
+ {
+ LLAvatarActions::share(currentSelectedUUID);
+ }
+ else if("pay" == command)
+ {
+ LLAvatarActions::pay(currentSelectedUUID);
+ }
+ else if("block_unblock" == command)
+ {
+ LLAvatarActions::toggleBlock(currentSelectedUUID);
+ }
+}
+
+bool LLIMFloaterContainer::enableContextMenuItem(const LLSD& userdata)
+{
+ std::string item = userdata.asString();
+ uuid_vec_t mUUIDs;
+ getSelectedUUIDs(mUUIDs);
+
+ // Note: can_block and can_delete is used only for one person selected menu
+ // so we don't need to go over all uuids.
+
+ if (item == std::string("can_block"))
+ {
+ const LLUUID& id = mUUIDs.front();
+ return LLAvatarActions::canBlock(id);
+ }
+ else if (item == std::string("can_add"))
+ {
+ // We can add friends if:
+ // - there are selected people
+ // - and there are no friends among selection yet.
+
+ //EXT-7389 - disable for more than 1
+ if(mUUIDs.size() > 1)
+ {
+ return false;
+ }
+
+ bool result = (mUUIDs.size() > 0);
+
+ uuid_vec_t::const_iterator
+ id = mUUIDs.begin(),
+ uuids_end = mUUIDs.end();
+
+ for (;id != uuids_end; ++id)
+ {
+ if ( LLAvatarActions::isFriend(*id) )
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+ else if (item == std::string("can_delete"))
+ {
+ // We can remove friends if:
+ // - there are selected people
+ // - and there are only friends among selection.
+
+ bool result = (mUUIDs.size() > 0);
+
+ uuid_vec_t::const_iterator
+ id = mUUIDs.begin(),
+ uuids_end = mUUIDs.end();
+
+ for (;id != uuids_end; ++id)
+ {
+ if ( !LLAvatarActions::isFriend(*id) )
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+ else if (item == std::string("can_call"))
+ {
+ return LLAvatarActions::canCall();
+ }
+ else if (item == std::string("can_show_on_map"))
+ {
+ const LLUUID& id = mUUIDs.front();
+
+ return (LLAvatarTracker::instance().isBuddyOnline(id) && is_agent_mappable(id))
+ || gAgent.isGodlike();
+ }
+ else if(item == std::string("can_offer_teleport"))
+ {
+ return LLAvatarActions::canOfferTeleport(mUUIDs);
+ }
+ return false;
+}
+
+bool LLIMFloaterContainer::checkContextMenuItem(const LLSD& userdata)
+{
+ std::string item = userdata.asString();
+ const LLUUID& id = static_cast<LLConversationItem *>(mConversationsRoot->getCurSelectedItem()->getViewModelItem())->getUUID();
+
+ if (item == std::string("is_blocked"))
+ {
+ return LLAvatarActions::isBlocked(id);
+ }
+
+ return false;
+}
+
void LLIMFloaterContainer::setConvItemSelect(const LLUUID& session_id)
{
LLFolderViewItem* widget = mConversationsWidgets[session_id];
diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h
index 2debc2455b..49a41e5cdd 100644
--- a/indra/newview/llimfloatercontainer.h
+++ b/indra/newview/llimfloatercontainer.h
@@ -111,6 +111,11 @@ private:
void setSortOrderParticipants(const LLConversationFilter::ESortOrderType order);
void setSortOrder(const LLConversationSort& order);
+ void getSelectedUUIDs(uuid_vec_t& selected_uuids);
+ void doToSelected(const LLSD& userdata);
+ bool checkContextMenuItem(const LLSD& userdata);
+ bool enableContextMenuItem(const LLSD& userdata);
+
LLButton* mExpandCollapseBtn;
LLLayoutPanel* mMessagesPane;
LLLayoutPanel* mConversationsPane;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index a77b57638f..a8d99ad7de 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -172,6 +172,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
p.show_empty_message = mShowEmptyMessage;
p.show_item_link_overlays = mShowItemLinkOverlays;
p.root = NULL;
+ p.options_menu = "menu_inventory.xml";
return LLUICtrlFactory::create<LLFolderView>(p);
}
diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml
new file mode 100644
index 0000000000..94399be61c
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_conversation.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ bottom="806"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="menu_conversation_participant"
+ visible="false">
+ <menu_item_call
+ label="Close conversation"
+ layout="topleft"
+ name="close_conversation">
+ <on_click function="Avatar.DoToSelected" parameter="close_conversation"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Open voice conversation"
+ layout="topleft"
+ name="open_voice_conversation">
+ <on_click function="Avatar.DoToSelected" parameter="open_voice_conversation"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Disconnect from voice"
+ layout="topleft"
+ name="disconnect_from_voice">
+ <on_click function="Avatar.DoToSelected" parameter="disconnect_from_voice"/>
+ </menu_item_call>
+ <menu_item_separator layout="topleft" name="separator_disconnect_from_voice"/>
+ <menu_item_call
+ label="View Profile"
+ layout="topleft"
+ name="view_profile">
+ <on_click function="Avatar.DoToSelected" parameter="view_profile"/>
+ </menu_item_call>
+ <menu_item_call
+ label="IM"
+ layout="topleft"
+ name="im">
+ <on_click function="Avatar.DoToSelected" parameter="im"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Offer teleport"
+ layout="topleft"
+ name="offer_teleport">
+ <on_click function="Avatar.DoToSelected" parameter="offer_teleport"/>
+ <on_enable function="Avatar.EnableItem" parameter="can_offer_teleport"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Voice call"
+ layout="topleft"
+ name="voice_call">
+ <on_click function="Avatar.DoToSelected" parameter="voice_call"/>
+ <on_enable function="Avatar.EnableItem" parameter="can_call" />
+ </menu_item_call>
+ <menu_item_call
+ label="Chat history..."
+ layout="topleft"
+ name="chat_history">
+ <on_click function="Avatar.DoToSelected" parameter="chat_history"/>
+ </menu_item_call>
+ <menu_item_separator layout="topleft" name="separator_chat_history"/>
+ <menu_item_call
+ label="Add friend"
+ layout="topleft"
+ name="add_friend">
+ <on_click function="Avatar.DoToSelected" parameter="add_friend"/>
+ <on_enable function="Avatar.EnableItem" parameter="can_add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove friend"
+ layout="topleft"
+ name="remove_friend">
+ <on_click function="Avatar.DoToSelected" parameter="remove_friend" />
+ <on_enable function="Avatar.EnableItem" parameter="can_delete" />
+ </menu_item_call>
+ <menu_item_call
+ label="Invite to group..."
+ layout="topleft"
+ name="invite_to_group">
+ <on_click function="Avatar.DoToSelected" parameter="invite_to_group" />
+ </menu_item_call>
+ <menu_item_separator layout="topleft" name="separator_invite_to_group"/>
+ <menu_item_call
+ label="Map"
+ layout="topleft"
+ name="map">
+ <on_click function="Avatar.DoToSelected" parameter="map" />
+ <on_enable function="Avatar.EnableItem" parameter="can_show_on_map" />
+ </menu_item_call>
+ <menu_item_call
+ label="Share"
+ layout="topleft"
+ name="share">
+ <on_click function="Avatar.DoToSelected" parameter="share" />
+ </menu_item_call>
+ <menu_item_call
+ label="Pay"
+ layout="topleft"
+ name="pay">
+ <on_click function="Avatar.DoToSelected" parameter="pay" />
+ </menu_item_call>
+ <menu_item_check
+ label="Block / unblock"
+ layout="topleft"
+ name="block_unblock">
+ <on_click function="Avatar.DoToSelected" parameter="block_unblock" />
+ <on_check function="Avatar.CheckItem" parameter="is_blocked" />
+ <on_enable function="Avatar.EnableItem" parameter="can_block" />
+ </menu_item_check>
+</toggleable_menu>