summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorMaxim Nikolenko <maximnproductengine@lindenlab.com>2023-03-29 13:51:40 +0300
committerMaxim Nikolenko <maximnproductengine@lindenlab.com>2023-03-29 13:51:40 +0300
commite5b8b799cc75f3b9cd259403c323cd47b59453d8 (patch)
treeefd077f3b8677f806a7c9a715b2a4cb6d4c3f8b3 /indra/newview
parent11b2f138cecc123c3e6876b56ea63c5fbd734d56 (diff)
SL-19379 WIP add basic context menu
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llavataractions.cpp160
-rw-r--r--indra/newview/llavataractions.h1
-rw-r--r--indra/newview/llinventoryfunctions.cpp70
-rw-r--r--indra/newview/llinventoryfunctions.h2
-rw-r--r--indra/newview/llinventorygallery.cpp18
-rw-r--r--indra/newview/llinventorygallery.h5
-rw-r--r--indra/newview/llinventorygallerymenu.cpp616
-rw-r--r--indra/newview/llinventorygallerymenu.h55
-rw-r--r--indra/newview/skins/default/xui/en/menu_gallery_inventory.xml531
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml23
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_gallery.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml4
13 files changed, 1393 insertions, 96 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index d587f8bfc4..1d7c238629 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -381,6 +381,7 @@ set(viewer_SOURCE_FILES
llinventoryfilter.cpp
llinventoryfunctions.cpp
llinventorygallery.cpp
+ llinventorygallerymenu.cpp
llinventoryicon.cpp
llinventoryitemslist.cpp
llinventorylistitem.cpp
@@ -1025,6 +1026,7 @@ set(viewer_HEADER_FILES
llinventoryfilter.h
llinventoryfunctions.h
llinventorygallery.h
+ llinventorygallerymenu.h
llinventoryicon.h
llinventoryitemslist.h
llinventorylistitem.h
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 3e450e6dec..6bd2b8bbee 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -730,6 +730,37 @@ namespace action_give_inventory
/**
* Checks My Inventory visibility.
*/
+ static bool is_give_inventory_acceptable_ids(const std::set<LLUUID> inventory_selected_uuids)
+ {
+ if (inventory_selected_uuids.empty()) return false; // nothing selected
+
+ bool acceptable = false;
+ std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
+ const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end();
+ for (; it != it_end; ++it)
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ // any category can be offered.
+ if (inv_cat)
+ {
+ acceptable = true;
+ continue;
+ }
+
+ LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
+ // check if inventory item can be given
+ if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
+ {
+ acceptable = true;
+ continue;
+ }
+
+ // there are neither item nor category in inventory
+ acceptable = false;
+ break;
+ }
+ return acceptable;
+ }
static bool is_give_inventory_acceptable(LLInventoryPanel* panel = NULL)
{
@@ -737,32 +768,7 @@ namespace action_give_inventory
const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
if (inventory_selected_uuids.empty()) return false; // nothing selected
- bool acceptable = false;
- std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
- const std::set<LLUUID>::const_iterator it_end = inventory_selected_uuids.end();
- for (; it != it_end; ++it)
- {
- LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
- // any category can be offered.
- if (inv_cat)
- {
- acceptable = true;
- continue;
- }
-
- LLViewerInventoryItem* inv_item = gInventory.getItem(*it);
- // check if inventory item can be given
- if (LLGiveInventory::isInventoryGiveAcceptable(inv_item))
- {
- acceptable = true;
- continue;
- }
-
- // there are neither item nor category in inventory
- acceptable = false;
- break;
- }
- return acceptable;
+ return is_give_inventory_acceptable_ids(inventory_selected_uuids);
}
static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string)
@@ -890,46 +896,58 @@ namespace action_give_inventory
* @param avatar_names - avatar names request to be sent.
* @param avatar_uuids - avatar names request to be sent.
*/
- static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
- {
- llassert(avatar_names.size() == avatar_uuids.size());
- const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
- if (inventory_selected_uuids.empty())
- {
- return;
- }
+ static void give_inventory_ids(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, const uuid_set_t inventory_selected_uuids)
+ {
+ llassert(avatar_names.size() == avatar_uuids.size());
- std::string residents;
- LLAvatarActions::buildResidentsString(avatar_names, residents, true);
+ if (inventory_selected_uuids.empty())
+ {
+ return;
+ }
- std::string items;
- build_items_string(inventory_selected_uuids, items);
+ std::string residents;
+ LLAvatarActions::buildResidentsString(avatar_names, residents, true);
- int folders_count = 0;
- std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
+ std::string items;
+ build_items_string(inventory_selected_uuids, items);
- //traverse through selected inventory items and count folders among them
- for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
- {
- LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
- if (NULL != inv_cat)
- {
- folders_count++;
- }
- }
+ int folders_count = 0;
+ std::set<LLUUID>::const_iterator it = inventory_selected_uuids.begin();
- // EXP-1599
- // In case of sharing multiple folders, make the confirmation
- // dialog contain a warning that only one folder can be shared at a time.
- std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
- LLSD substitutions;
- substitutions["RESIDENTS"] = residents;
- substitutions["ITEMS"] = items;
- LLShareInfo::instance().mAvatarNames = avatar_names;
- LLShareInfo::instance().mAvatarUuids = avatar_uuids;
- LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
- }
+ //traverse through selected inventory items and count folders among them
+ for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it)
+ {
+ LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it);
+ if (NULL != inv_cat)
+ {
+ folders_count++;
+ }
+ }
+
+ // EXP-1599
+ // In case of sharing multiple folders, make the confirmation
+ // dialog contain a warning that only one folder can be shared at a time.
+ std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation";
+ LLSD substitutions;
+ substitutions["RESIDENTS"] = residents;
+ substitutions["ITEMS"] = items;
+ LLShareInfo::instance().mAvatarNames = avatar_names;
+ LLShareInfo::instance().mAvatarUuids = avatar_uuids;
+ LLNotificationsUtil::add(notification, substitutions, LLSD(), boost::bind(&give_inventory_cb, _1, _2, inventory_selected_uuids));
+ }
+
+ static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector<LLAvatarName> avatar_names, LLInventoryPanel* panel = NULL)
+ {
+ llassert(avatar_names.size() == avatar_uuids.size());
+
+ const std::set<LLUUID> inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(panel);
+ if (inventory_selected_uuids.empty())
+ {
+ return;
+ }
+ give_inventory_ids(avatar_uuids, avatar_names, inventory_selected_uuids);
+ }
}
// static
@@ -1037,6 +1055,28 @@ void LLAvatarActions::shareWithAvatars(LLView * panel)
LLNotificationsUtil::add("ShareNotification");
}
+//static
+void LLAvatarActions::shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater)
+{
+ using namespace action_give_inventory;
+
+ LLFloaterAvatarPicker* picker =
+ LLFloaterAvatarPicker::show(boost::bind(give_inventory_ids, _1, _2, inventory_selected_uuids), TRUE, FALSE, FALSE, root_floater->getName());
+ if (!picker)
+ {
+ return;
+ }
+
+ picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable_ids, inventory_selected_uuids));
+ picker->openFriendsTab();
+
+ if (root_floater)
+ {
+ root_floater->addDependentFloater(picker);
+ }
+ LLNotificationsUtil::add("ShareNotification");
+}
+
// static
bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NULL*/)
{
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 86183cc119..8a0f40dd52 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -133,6 +133,7 @@ public:
* Share items with the picked avatars.
*/
static void shareWithAvatars(LLView * panel);
+ static void shareWithAvatars(const uuid_set_t inventory_selected_uuids, LLFloater* root_floater);
/**
* Block/unblock the avatar by id.
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index fbcce5f078..d38208da71 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -2125,6 +2125,45 @@ std::string get_localized_folder_name(LLUUID cat_uuid)
return localized_root_name;
}
+
+void new_folder_window(const LLUUID& folder_id)
+{
+ LLPanelMainInventory::newFolderWindow(folder_id);
+}
+
+void ungroup_folder_items(const LLUUID& folder_id)
+{
+ LLInventoryCategory* inv_cat = gInventory.getCategory(folder_id);
+ if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+ {
+ return;
+ }
+ const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
+ LLInventoryModel::cat_array_t cats = *cat_array;
+ LLInventoryModel::item_array_t items = *item_array;
+
+ for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
+ {
+ LLViewerInventoryCategory* cat = *cat_iter;
+ if (cat)
+ {
+ gInventory.changeCategoryParent(cat, new_cat_uuid, false);
+ }
+ }
+ for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
+ {
+ LLViewerInventoryItem* item = *item_iter;
+ if(item)
+ {
+ gInventory.changeItemParent(item, new_cat_uuid, false);
+ }
+ }
+ gInventory.removeCategory(inv_cat->getUUID());
+ gInventory.notifyObservers();
+}
///----------------------------------------------------------------------------
/// LLMarketplaceValidator implementations
///----------------------------------------------------------------------------
@@ -2977,36 +3016,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
if (selected_uuid_set.size() == 1)
{
- LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());
- if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
- {
- return;
- }
- const LLUUID &new_cat_uuid = inv_cat->getParentUUID();
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array);
- LLInventoryModel::cat_array_t cats = *cat_array;
- LLInventoryModel::item_array_t items = *item_array;
-
- for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter)
- {
- LLViewerInventoryCategory* cat = *cat_iter;
- if (cat)
- {
- gInventory.changeCategoryParent(cat, new_cat_uuid, false);
- }
- }
- for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter)
- {
- LLViewerInventoryItem* item = *item_iter;
- if(item)
- {
- gInventory.changeItemParent(item, new_cat_uuid, false);
- }
- }
- gInventory.removeCategory(inv_cat->getUUID());
- gInventory.notifyObservers();
+ ungroup_folder_items(*ids.begin());
}
}
else
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index f7755be1dd..5f1c5067d5 100644
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -101,6 +101,8 @@ bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_out
bool can_move_to_landmarks(LLInventoryItem* inv_item);
bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit);
std::string get_localized_folder_name(LLUUID cat_uuid);
+void new_folder_window(const LLUUID& folder_id);
+void ungroup_folder_items(const LLUUID& folder_id);
/** Miscellaneous global functions
** **
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
index 08836555d4..bfca22ba8a 100644
--- a/indra/newview/llinventorygallery.cpp
+++ b/indra/newview/llinventorygallery.cpp
@@ -27,8 +27,8 @@
#include "llviewerprecompiledheaders.h"
#include "llinventorygallery.h"
+#include "llinventorygallerymenu.h"
-#include "llaccordionctrltab.h"
#include "llcommonutils.h"
#include "lliconctrl.h"
#include "llinventorybridge.h"
@@ -115,12 +115,14 @@ BOOL LLInventoryGallery::postBuild()
LLPanel::Params params = LLPanel::getDefaultParams();
mGalleryPanel = LLUICtrlFactory::create<LLPanel>(params);
mMessageTextBox = getChild<LLTextBox>("empty_txt");
-
+ mInventoryGalleryMenu = new LLInventoryGalleryContextMenu(this);
return TRUE;
}
LLInventoryGallery::~LLInventoryGallery()
{
+ delete mInventoryGalleryMenu;
+
while (!mUnusedRowPanels.empty())
{
LLPanel* panelp = mUnusedRowPanels.back();
@@ -600,7 +602,7 @@ void LLInventoryGallery::updateAddedItem(LLUUID item_id)
LLInventoryGalleryItem* item = buildGalleryItem(name, item_id, obj->getType(), thumbnail_id, obj->getIsLinkType());
mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item));
-
+ item->setRightMouseDownCallback(boost::bind(&LLInventoryGallery::showContextMenu, this, _1, _2, _3, item_id));
item->setFocusReceivedCallback(boost::bind(&LLInventoryGallery::onChangeItemSelection, this, item_id));
if (mGalleryCreated)
{
@@ -671,6 +673,16 @@ void LLInventoryGallery::updateItemThumbnail(LLUUID item_id)
}
}
+void LLInventoryGallery::showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id)
+{
+ if (mInventoryGalleryMenu && item_id.notNull())
+ {
+ uuid_vec_t selected_uuids;
+ selected_uuids.push_back(item_id);
+ mInventoryGalleryMenu->show(ctrl, selected_uuids, x, y);
+ }
+}
+
void LLInventoryGallery::onChangeItemSelection(const LLUUID& category_id)
{
if (mSelectedItemID == category_id)
diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h
index 1c45a8345f..5c529e7589 100644
--- a/indra/newview/llinventorygallery.h
+++ b/indra/newview/llinventorygallery.h
@@ -27,6 +27,7 @@
#ifndef LL_LLINVENTORYGALLERY_H
#define LL_LLINVENTORYGALLERY_H
+#include "lllistcontextmenu.h"
#include "llpanel.h"
#include "llinventorymodel.h"
@@ -35,6 +36,8 @@ class LLInventoryGalleryItem;
class LLScrollContainer;
class LLTextBox;
+class LLInventoryGalleryContextMenu;
+
class LLInventoryGallery : public LLPanel
{
public:
@@ -108,6 +111,7 @@ public:
protected:
void onChangeItemSelection(const LLUUID& category_id);
+ void showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id);
void applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring);
@@ -171,6 +175,7 @@ private:
int mRowPanWidthFactor;
int mGalleryWidthFactor;
+ LLInventoryGalleryContextMenu* mInventoryGalleryMenu;
std::string mFilterSubString;
typedef std::map<LLUUID, LLInventoryGalleryItem*> gallery_item_map_t;
diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp
new file mode 100644
index 0000000000..11dd5e6690
--- /dev/null
+++ b/indra/newview/llinventorygallerymenu.cpp
@@ -0,0 +1,616 @@
+/**
+ * @file llinventorygallerymenu.cpp
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinventorygallery.h"
+#include "llinventorygallerymenu.h"
+
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llavataractions.h"
+#include "llclipboard.h"
+#include "llfloaterreg.h"
+#include "llgiveinventory.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "llmarketplacefunctions.h"
+#include "llmenugl.h"
+#include "llnotificationsutil.h"
+#include "llviewerfoldertype.h"
+#include "llviewerwindow.h"
+
+LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
+{
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ //LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+ LLUUID selected_id = mUUIDs.front();
+
+ registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2, selected_id));
+ registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2, selected_id));
+ registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
+ registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
+
+ std::set<LLUUID> uuids{selected_id};
+ registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
+
+ LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml");
+
+ updateMenuItemsVisibility(menu);
+
+ return menu;
+}
+
+void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLUUID& selected_id)
+{
+ std::string action = userdata.asString();
+ LLInventoryObject* obj = gInventory.getObject(selected_id);
+ if(!obj) return;
+
+ bool is_folder = (obj->getType() == LLAssetType::AT_CATEGORY);
+
+ if ("open_selected_folder" == action)
+ {
+ mGallery->setRootFolder(selected_id);
+ }
+ else if ("open_in_new_window" == action)
+ {
+ new_folder_window(selected_id);
+ }
+ else if ("properties" == action)
+ {
+ show_item_profile(selected_id);
+ }
+ else if ("restore" == action)
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
+ if(cat)
+ {
+ const LLUUID new_parent = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType()));
+ // do not restamp children on restore
+ gInventory.changeCategoryParent(cat, new_parent, false);
+ }
+ else
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+ if(item)
+ {
+ bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
+
+ const LLUUID new_parent = gInventory.findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
+ // do not restamp children on restore
+ gInventory.changeItemParent(item, new_parent, false);
+ }
+ }
+ }
+ else if ("copy_uuid" == action)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+ if(item)
+ {
+ LLUUID asset_id = item->getProtectedAssetUUID();
+ std::string buffer;
+ asset_id.toString(buffer);
+
+ gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));
+ }
+ }
+ else if ("purge" == action)
+ {
+ remove_inventory_object(selected_id, NULL);
+ }
+ else if ("goto" == action)
+ {
+ show_item_original(selected_id);
+ }
+ else if ("thumbnail" == action)
+ {
+ LLSD data(selected_id);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
+ }
+ else if ("cut" == action)
+ {
+ bool allow = false;
+ if(is_folder)
+ {
+ allow = get_is_category_removable(&gInventory, selected_id);
+ }
+ else
+ {
+ allow = get_is_item_removable(&gInventory, selected_id);
+ }
+ if(allow)
+ {
+ LLClipboard::instance().setCutMode(true);
+ LLClipboard::instance().addToClipboard(selected_id);
+ }
+ }
+ else if ("paste" == action)
+ {
+ {
+ const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ if(gInventory.isObjectDescendentOf(selected_id, marketplacelistings_id))
+ {
+ return;
+ }
+
+ bool is_cut_mode = (LLClipboard::instance().isCutMode());
+ {
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
+ {
+ const LLUUID& item_id = (*iter);
+ if(gInventory.isObjectDescendentOf(item_id, marketplacelistings_id) && (LLMarketplaceData::instance().isInActiveFolder(item_id) ||
+ LLMarketplaceData::instance().isListedAndActive(item_id)))
+ {
+ return;
+ }
+ LLViewerInventoryCategory* cat = gInventory.getCategory(item_id);
+ if (cat)
+ {
+ if(is_cut_mode)
+ {
+ gInventory.changeCategoryParent(cat, selected_id, false);
+ }
+ else
+ {
+ copy_inventory_category(&gInventory, cat, selected_id);
+ }
+ }
+ else
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(item_id);
+ if (item)
+ {
+ if(is_cut_mode)
+ {
+ gInventory.changeItemParent(item, selected_id, false);
+ }
+ else
+ {
+ if (item->getIsLinkType())
+ {
+ link_inventory_object(selected_id, item_id,
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ else
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ selected_id,
+ std::string(),
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ }
+ }
+ }
+ }
+ LLClipboard::instance().setCutMode(false);
+ }
+
+ }
+ }
+ else if ("delete" == action)
+ {
+ if (is_folder)
+ {
+ if(get_is_category_removable(&gInventory, selected_id))
+ {
+ gInventory.removeCategory(selected_id);
+ }
+ }
+ else
+ {
+ if(get_is_item_removable(&gInventory, selected_id))
+ {
+ gInventory.removeItem(selected_id);
+ }
+ }
+ }
+ else if ("copy" == action)
+ {
+ if(is_folder)
+ {
+ LLClipboard::instance().reset();
+ LLClipboard::instance().addToClipboard(selected_id);
+ }
+ else
+ {
+ LLViewerInventoryItem* inv_item = gInventory.getItem(selected_id);
+ if (inv_item && inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) && !get_is_item_worn(selected_id))
+ {
+ LLClipboard::instance().reset();
+ LLClipboard::instance().addToClipboard(selected_id);
+ }
+ }
+ }
+ else if ("paste_as_link" == action)
+ {
+ link_inventory_object(selected_id, obj, LLPointer<LLInventoryCallback>(NULL));
+ }
+ else if ("rename" == action)
+ {
+ LLSD args;
+ args["NAME"] = obj->getName();
+
+ LLSD payload;
+ payload["id"] = selected_id;
+
+ LLNotificationsUtil::add("RenameItem", args, payload, boost::bind(onRename, _1, _2));
+ }
+ else if ("open" == action || "open_original" == action)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(), selected_id , &gInventory);
+ }
+ }
+ else if ("ungroup_folder_items" == action)
+ {
+ ungroup_folder_items(selected_id);
+ }
+}
+
+void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return; // canceled
+
+ std::string new_name = response["new_name"].asString();
+ LLStringUtil::trim(new_name);
+ if (!new_name.empty())
+ {
+ LLUUID id = notification["payload"]["id"].asUUID();
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(id);
+ if(cat && (cat->getName() != new_name))
+ {
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_category(cat->getUUID(),updates, NULL);
+ return;
+ }
+
+ LLViewerInventoryItem* item = gInventory.getItem(id);
+ if(item && (item->getName() != new_name))
+ {
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_item(item->getUUID(),updates, NULL);
+ }
+ }
+}
+
+void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata, const LLUUID& selected_id)
+{
+ const std::string param = userdata.asString();
+ if (param == "model")
+ {
+ gSavedPerAccountSettings.setString("ModelUploadFolder", selected_id.asString());
+ }
+ else if (param == "texture")
+ {
+ gSavedPerAccountSettings.setString("TextureUploadFolder", selected_id.asString());
+ }
+ else if (param == "sound")
+ {
+ gSavedPerAccountSettings.setString("SoundUploadFolder", selected_id.asString());
+ }
+ else if (param == "animation")
+ {
+ gSavedPerAccountSettings.setString("AnimationUploadFolder", selected_id.asString());
+ }
+}
+
+bool can_share_item(LLUUID item_id)
+{
+ bool can_share = false;
+
+ if (gInventory.isObjectDescendentOf(item_id, gInventory.getRootFolderID()))
+ {
+ const LLViewerInventoryItem *item = gInventory.getItem(item_id);
+ if (item)
+ {
+ if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item))
+ {
+ can_share = LLGiveInventory::isInventoryGiveAcceptable(item);
+ }
+ }
+ else
+ {
+ can_share = (gInventory.getCategory(item_id) != NULL);
+ }
+
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if ((item_id == trash_id) || gInventory.isObjectDescendentOf(item_id, trash_id))
+ {
+ can_share = false;
+ }
+ }
+
+ return can_share;
+}
+
+bool is_inbox_folder(LLUUID item_id)
+{
+ const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
+
+ if (inbox_id.isNull())
+ {
+ return false;
+ }
+
+ return gInventory.isObjectDescendentOf(item_id, inbox_id);
+}
+
+void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* menu)
+{
+ LLUUID selected_id = mUUIDs.front();
+ LLInventoryObject* obj = gInventory.getObject(selected_id);
+ if (!obj)
+ {
+ return;
+ }
+
+ std::vector<std::string> items;
+ std::vector<std::string> disabled_items;
+
+ bool is_agent_inventory = gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID());
+ bool is_link = obj->getIsLinkType();
+ bool is_folder = (obj->getType() == LLAssetType::AT_CATEGORY);
+ bool is_cof = LLAppearanceMgr::instance().getIsInCOF(selected_id);
+ bool is_inbox = is_inbox_folder(selected_id);
+ bool is_trash = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));
+ bool is_in_trash = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));
+ bool is_lost_and_found = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
+ bool is_outfits= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS));
+ //bool is_favorites= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));
+
+ bool is_system_folder = false;
+ LLFolderType::EType folder_type(LLFolderType::FT_NONE);
+ bool has_children = false;
+ bool is_full_perm_item = false;
+ bool is_copyable = false;
+ LLViewerInventoryItem* selected_item = gInventory.getItem(selected_id);
+
+ if(is_folder)
+ {
+ LLInventoryCategory* category = gInventory.getCategory(selected_id);
+ if (category)
+ {
+ folder_type = category->getPreferredType();
+ is_system_folder = LLFolderType::lookupIsProtectedType(folder_type);
+ has_children = (gInventory.categoryHasChildren(selected_id) != LLInventoryModel::CHILDREN_NO);
+ }
+ }
+ else
+ {
+ if (selected_item)
+ {
+ is_full_perm_item = selected_item->getIsFullPerm();
+ is_copyable = selected_item->getPermissions().allowCopyBy(gAgent.getID());
+ }
+ }
+
+ if(!is_link)
+ {
+ items.push_back(std::string("thumbnail"));
+ LLViewerInventoryItem* inv_item = gInventory.getItem(selected_id);
+ if (inv_item && !inv_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+ {
+ disabled_items.push_back(std::string("thumbnail"));
+ }
+ }
+
+ if (is_folder)
+ {
+ items.push_back(std::string("Copy Separator"));
+
+ items.push_back(std::string("open_in_current_window"));
+ items.push_back(std::string("open_in_new_window"));
+ items.push_back(std::string("Open Folder Separator"));
+ }
+
+ if(is_trash)
+ {
+ items.push_back(std::string("Empty Trash"));
+
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(selected_id, cat_array, item_array);
+ if (0 == cat_array->size() && 0 == item_array->size())
+ {
+ disabled_items.push_back(std::string("Empty Trash"));
+ }
+ }
+ else if(is_in_trash)
+ {
+ if (is_link)
+ {
+ items.push_back(std::string("Find Original"));
+ if (LLAssetType::lookupIsLinkType(obj->getType()))
+ {
+ disabled_items.push_back(std::string("Find Original"));
+ }
+ }
+ items.push_back(std::string("Purge Item"));
+ if (!get_is_category_removable(&gInventory, selected_id))
+ {
+ disabled_items.push_back(std::string("Purge Item"));
+ }
+ items.push_back(std::string("Restore Item"));
+ }
+ else
+ {
+ if(can_share_item(selected_id))
+ {
+ items.push_back(std::string("Share"));
+ }
+ if (is_folder && is_agent_inventory)
+ {
+ if (!is_cof && (folder_type != LLFolderType::FT_OUTFIT) && !is_outfits && !is_inbox_folder(selected_id))
+ {
+ if (!gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD)))
+ {
+ items.push_back(std::string("New Folder"));
+ }
+ items.push_back(std::string("upload_def"));
+ }
+
+ if(is_outfits)
+ {
+ items.push_back(std::string("New Outfit"));
+ }
+
+ items.push_back(std::string("Subfolder Separator"));
+ if (!is_system_folder)
+ {
+ if(has_children && (folder_type != LLFolderType::FT_OUTFIT))
+ {
+ items.push_back(std::string("Ungroup folder items"));
+ }
+ items.push_back(std::string("Cut"));
+ items.push_back(std::string("Delete"));
+ if(!get_is_category_removable(&gInventory, selected_id))
+ {
+ disabled_items.push_back(std::string("Delete"));
+ disabled_items.push_back(std::string("Cut"));
+ }
+ if(!is_inbox)
+ {
+ items.push_back(std::string("Rename"));
+ }
+ }
+ if (LLClipboard::instance().hasContents() && is_agent_inventory && !is_cof && !is_inbox_folder(selected_id))
+ {
+ items.push_back(std::string("Paste"));
+
+ static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);
+ if (inventory_linking)
+ {
+ items.push_back(std::string("Paste As Link"));
+ }
+ }
+ if(!is_system_folder)
+ {
+ items.push_back(std::string("Copy"));
+ }
+ }
+ else if(!is_folder)
+ {
+ items.push_back(std::string("Properties"));
+ items.push_back(std::string("Copy Asset UUID"));
+ items.push_back(std::string("Copy Separator"));
+
+ bool is_asset_knowable = is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(obj->getType());
+ if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308
+ || (! ( is_full_perm_item || gAgent.isGodlike())))
+ {
+ disabled_items.push_back(std::string("Copy Asset UUID"));
+ }
+ if(is_agent_inventory)
+ {
+ items.push_back(std::string("Cut"));
+ if (!is_link || !is_cof || !get_is_item_worn(selected_id))
+ {
+ items.push_back(std::string("Delete"));
+ }
+ if(!get_is_item_removable(&gInventory, selected_id))
+ {
+ disabled_items.push_back(std::string("Delete"));
+ disabled_items.push_back(std::string("Cut"));
+ }
+
+ if (selected_item && (selected_item->getInventoryType() != LLInventoryType::IT_CALLINGCARD) && !is_inbox && selected_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+ {
+ items.push_back(std::string("Rename"));
+ }
+ }
+ items.push_back(std::string("Copy"));
+ if (!is_copyable)
+ {
+ disabled_items.push_back(std::string("Copy"));
+ }
+ }
+ if((obj->getType() == LLAssetType::AT_SETTINGS)
+ || ((obj->getType() <= LLAssetType::AT_GESTURE)
+ && obj->getType() != LLAssetType::AT_OBJECT
+ && obj->getType() != LLAssetType::AT_CLOTHING
+ && obj->getType() != LLAssetType::AT_CATEGORY
+ && obj->getType() != LLAssetType::AT_BODYPART))
+ {
+ bool can_open = !LLAssetType::lookupIsLinkType(obj->getType());
+
+ if (can_open)
+ {
+ if (is_link)
+ items.push_back(std::string("Open Original"));
+ else
+ items.push_back(std::string("Open"));
+ }
+ else
+ {
+ disabled_items.push_back(std::string("Open"));
+ disabled_items.push_back(std::string("Open Original"));
+ }
+ }
+ else if(LLAssetType::AT_LANDMARK == obj->getType())
+ {
+ items.push_back(std::string("Landmark Open"));
+ }
+ if (is_link)
+ {
+ items.push_back(std::string("Find Original"));
+ if (LLAssetType::lookupIsLinkType(obj->getType()))
+ {
+ disabled_items.push_back(std::string("Find Original"));
+ }
+ }
+ if (is_lost_and_found)
+ {
+ items.push_back(std::string("Empty Lost And Found"));
+
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(selected_id, cat_array, item_array);
+ // Enable Empty menu item only when there is something to act upon.
+ if (0 == cat_array->size() && 0 == item_array->size())
+ {
+ disabled_items.push_back(std::string("Empty Lost And Found"));
+ }
+
+ disabled_items.push_back(std::string("New Folder"));
+ disabled_items.push_back(std::string("upload_def"));
+ }
+ }
+
+ hide_context_entries(*menu, items, disabled_items);
+}
+
diff --git a/indra/newview/llinventorygallerymenu.h b/indra/newview/llinventorygallerymenu.h
new file mode 100644
index 0000000000..1768c07e6e
--- /dev/null
+++ b/indra/newview/llinventorygallerymenu.h
@@ -0,0 +1,55 @@
+/**
+ * @file llinventorygallerymenu.h
+ *
+ * $LicenseInfo:firstyear=2023&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2023, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLINVENTORYGALLERYMENU_H
+#define LL_LLINVENTORYGALLERYMENU_H
+
+#include "lllistcontextmenu.h"
+
+class LLInventoryGalleryContextMenu : public LLListContextMenu
+{
+public:
+ LLInventoryGalleryContextMenu(LLInventoryGallery* gallery)
+ : LLListContextMenu(),
+ mGallery(gallery){}
+ /*virtual*/ LLContextMenu* createMenu();
+
+protected:
+ //virtual void buildContextMenu(class LLMenuGL& menu, U32 flags);
+ void updateMenuItemsVisibility(LLContextMenu* menu);
+
+ void doToSelected(const LLSD& userdata, const LLUUID& selected_id);
+ void fileUploadLocation(const LLSD& userdata, const LLUUID& selected_id);
+
+ static void onRename(const LLSD& notification, const LLSD& response);
+
+private:
+ bool enableContextMenuItem(const LLSD& userdata);
+ bool checkContextMenuItem(const LLSD& userdata);
+
+ LLInventoryGallery* mGallery;
+};
+
+#endif
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
new file mode 100644
index 0000000000..15466e8f32
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
@@ -0,0 +1,531 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Gallery">
+ <menu_item_call
+ label="Share"
+ layout="topleft"
+ name="Share">
+ <menu_item_call.on_click
+ function="Inventory.Share" />
+ </menu_item_call>
+ <menu_item_call
+ label="Empty Trash"
+ layout="topleft"
+ name="Empty Trash">
+ <menu_item_call.on_click
+ function="Inventory.EmptyTrash"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Empty Lost And Found"
+ layout="topleft"
+ name="Empty Lost And Found">
+ <menu_item_call.on_click
+ function="Inventory.EmptyLostAndFound"/>
+ </menu_item_call>
+ <menu_item_call
+ label="New Folder"
+ layout="topleft"
+ name="New Folder">
+ <menu_item_call.on_click
+ function="Inventory.DoCreate"
+ parameter="category" />
+ </menu_item_call>
+ <menu_item_call
+ label="New Outfit"
+ layout="topleft"
+ name="New Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoCreate"
+ parameter="outfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Teleport"
+ layout="topleft"
+ name="Landmark Open">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Folder Wearables Separator" />
+ <menu_item_call
+ label="Replace Current Outfit"
+ layout="topleft"
+ name="Replace Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="replaceoutfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add To Current Outfit"
+ layout="topleft"
+ name="Add To Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="addtooutfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove From Current Outfit"
+ layout="topleft"
+ name="Remove From Outfit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="removefromoutfit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy outfit list to clipboard"
+ layout="topleft"
+ name="Copy outfit list to clipboard">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copyoutfittoclipboard" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Outfit Separator" />
+ <menu_item_call
+ label="Find Original"
+ layout="topleft"
+ name="Find Original">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="goto" />
+ </menu_item_call>
+ <menu_item_call
+ label="Purge Item"
+ layout="topleft"
+ name="Purge Item">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="purge"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Restore Item"
+ layout="topleft"
+ name="Restore Item">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="restore" />
+ </menu_item_call>
+ <menu_item_call
+ label="Open"
+ layout="topleft"
+ name="Open">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open" />
+ </menu_item_call>
+ <menu_item_call
+ label="Open Original"
+ layout="topleft"
+ name="Open Original">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open_original" />
+ </menu_item_call>
+ <menu_item_call
+ label="Properties"
+ layout="topleft"
+ name="Properties">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="properties" />
+ </menu_item_call>
+ <menu_item_call
+ label="Image..."
+ layout="topleft"
+ name="thumbnail">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="thumbnail" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy Asset UUID"
+ layout="topleft"
+ name="Copy Asset UUID">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy_uuid" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Copy Separator" />
+ <menu_item_call
+ label="Open"
+ layout="topleft"
+ name="open_in_current_window">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open_selected_folder" />
+ </menu_item_call>
+ <menu_item_call
+ label="Open in new window"
+ layout="topleft"
+ name="open_in_new_window">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="open_in_new_window" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Open Folder Separator" />
+ <menu_item_call
+ label="Rename"
+ layout="topleft"
+ name="Rename">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="rename" />
+ </menu_item_call>
+ <menu_item_call
+ label="Cut"
+ layout="topleft"
+ name="Cut">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="cut" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy"
+ layout="topleft"
+ name="Copy">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy" />
+ </menu_item_call>
+ <menu_item_call
+ label="Paste"
+ layout="topleft"
+ name="Paste">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="paste" />
+ </menu_item_call>
+ <menu_item_call
+ label="Paste As Link"
+ layout="topleft"
+ name="Paste As Link">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="paste_link" />
+ </menu_item_call>
+ <menu_item_call
+ label="Replace Links"
+ layout="topleft"
+ name="Replace Links">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="replace_links" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Paste Separator" />
+ <menu_item_call
+ label="Delete"
+ layout="topleft"
+ name="Delete">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="delete" />
+ </menu_item_call>
+ <menu_item_call
+ label="Delete System Folder"
+ layout="topleft"
+ name="Delete System Folder">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="delete_system_folder" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_call
+ label="Play"
+ layout="topleft"
+ name="Sound Play">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="sound_play" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Landmark Separator" />
+ <menu_item_call
+ label="Copy SLurl"
+ layout="topleft"
+ name="url_copy">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy_slurl" />
+ </menu_item_call>
+ <menu_item_call
+ label="About Landmark"
+ layout="topleft"
+ name="About Landmark">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="about" />
+ </menu_item_call>
+ <menu_item_call
+ label="Show on Map"
+ layout="topleft"
+ name="show_on_map">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="show_on_map" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Animation Separator" />
+ <menu_item_call
+ label="Play Inworld"
+ layout="topleft"
+ name="Animation Play">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="playworld" />
+ </menu_item_call>
+ <menu_item_call
+ label="Play Locally"
+ layout="topleft"
+ name="Animation Audition">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="playlocal" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Send Instant Message Separator" />
+ <menu_item_call
+ label="Send Instant Message"
+ layout="topleft"
+ name="Send Instant Message">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="begin_im" />
+ </menu_item_call>
+ <menu_item_call
+ label="Offer Teleport..."
+ layout="topleft"
+ name="Offer Teleport...">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="lure" />
+ </menu_item_call>
+ <menu_item_call
+ label="Request Teleport..."
+ layout="topleft"
+ name="Request Teleport...">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="request_lure" />
+ </menu_item_call>
+ <menu_item_call
+ label="Start Conference Chat"
+ layout="topleft"
+ name="Conference Chat">
+ <menu_item_call.on_click
+ function="Inventory.BeginIMSession"
+ parameter="selected" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Gesture Separator" />
+ <menu_item_call
+ label="Activate"
+ layout="topleft"
+ name="Activate">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="activate" />
+ </menu_item_call>
+ <menu_item_call
+ label="Deactivate"
+ layout="topleft"
+ name="Deactivate">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="deactivate" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Texture Separator" />
+ <menu_item_call
+ label="Save As"
+ layout="topleft"
+ name="Save As">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="save_as" />
+ </menu_item_call>
+ <menu_item_call
+ label="Save Selected As"
+ layout="topleft"
+ name="Save Selected As">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="save_selected_as" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Wearable And Object Separator"/>
+ <menu_item_call
+ label="Wear"
+ layout="topleft"
+ name="Wearable And Object Wear">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="wear" />
+ </menu_item_call>
+ <menu
+ label="Attach To"
+ layout="topleft"
+ name="Attach To" />
+ <menu
+ label="Attach To HUD"
+ layout="topleft"
+ name="Attach To HUD" />
+ <menu_item_call
+ label="Touch"
+ layout="topleft"
+ name="Attachment Touch">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="touch" />
+ </menu_item_call>
+ <menu_item_call
+ label="Edit"
+ layout="topleft"
+ name="Wearable Edit">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="edit" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add"
+ layout="topleft"
+ name="Wearable Add">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="wear_add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Detach From Yourself"
+ layout="topleft"
+ name="Detach From Yourself">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="detach" />
+ </menu_item_call>
+ <menu_item_call
+ label="Take Off"
+ layout="topleft"
+ name="Take Off">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="take_off" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Settings Separator" />
+ <menu_item_call
+ name="Settings Apply Local"
+ layout="topleft"
+ label="Apply Only To Myself">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="apply_settings_local" />
+ </menu_item_call>
+ <menu_item_call
+ name="Settings Apply Parcel"
+ layout="topleft"
+ label="Apply To Parcel">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="apply_settings_parcel" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft"
+ name="Subfolder Separator" />
+ <menu_item_call
+ label="Create folder from selected"
+ layout="topleft"
+ name="New folder from selected">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="new_folder_from_selected" />
+ </menu_item_call>
+ <menu_item_call
+ label="Ungroup folder items"
+ layout="topleft"
+ name="Ungroup folder items">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="ungroup_folder_items" />
+ </menu_item_call>
+ <menu
+ label="Use as default for"
+ layout="topleft"
+ name="upload_def">
+ <menu_item_call
+ label="Image uploads"
+ layout="topleft"
+ name="Image uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="texture" />
+ </menu_item_call>
+ <menu_item_call
+ label="Sound uploads"
+ layout="topleft"
+ name="Sound uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="sound" />
+ </menu_item_call>
+ <menu_item_call
+ label="Animation uploads"
+ layout="topleft"
+ name="Animation uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="animation" />
+ </menu_item_call>
+ <menu_item_call
+ label="Model uploads"
+ layout="topleft"
+ name="Model uploads">
+ <menu_item_call.on_click
+ function="Inventory.FileUploadLocation"
+ parameter="model" />
+ </menu_item_call>
+ </menu>
+ <menu_item_separator
+ layout="topleft"
+ name="Marketplace Separator" />
+ <menu_item_call
+ label="Copy to Marketplace Listings"
+ layout="topleft"
+ name="Marketplace Copy">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="copy_to_marketplace_listings" />
+ </menu_item_call>
+ <menu_item_call
+ label="Move to Marketplace Listings"
+ layout="topleft"
+ name="Marketplace Move">
+ <menu_item_call.on_click
+ function="Inventory.DoToSelected"
+ parameter="move_to_marketplace_listings" />
+ </menu_item_call>
+ <menu_item_call
+ label="--no options--"
+ layout="topleft"
+ name="--no options--" />
+ <menu_item_separator
+ layout="topleft" />
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d2d3cb4523..70edd567a1 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3249,6 +3249,29 @@ See https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries
<notification
icon="alertmodal.tga"
+ label="Rename Selected Item"
+ name="RenameItem"
+ type="alertmodal">
+ Choose a new name for [NAME]
+ <tag>confirm</tag>
+ <form name="form">
+ <input name="new_name" type="text" width="300">
+ [NAME]
+ </input>
+ <button
+ default="true"
+ index="0"
+ name="OK"
+ text="OK"/>
+ <button
+ index="1"
+ name="Cancel"
+ text="Cancel"/>
+ </form>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="RemoveFromFriends"
type="alertmodal">
<tag>friendship</tag>
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
index 68f78a77c8..b32d592bf6 100644
--- a/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery.xml
@@ -26,7 +26,7 @@
</text>
<scroll_container
follows="all"
- height="400"
+ height="390"
layout="topleft"
left="4"
top="0"
diff --git a/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
index 73889af71a..1d216df094 100644
--- a/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_inventory_gallery_item.xml
@@ -53,7 +53,7 @@
left="0"
top="129"
height="25"
- width="148"
+ width="130"
name="text_bg_panel">
<text
read_only="true"
@@ -65,7 +65,7 @@
name="item_name"
parse_urls="false"
top="2"
- width="150"
+ width="130"
use_ellipses="true">
Item name, folder name.
</text>