summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorcallum_linden <none@none>2015-05-26 14:03:07 -0700
committercallum_linden <none@none>2015-05-26 14:03:07 -0700
commit80c67487c062b3105395d8dbf3dfc0be15cc678f (patch)
tree67e8aec40d3cd58030d28e1929bf09dcb75b96bc /indra/newview
parent80aa29eaec78d267b4fa1822cfbd3a33b268066a (diff)
parentf3c58f765c0168f25bb13c4427e34b4bdad2f671 (diff)
Merge with viewer-release after layer-limits release
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/VIEWER_VERSION.txt2
-rwxr-xr-xindra/newview/llagentwearables.cpp23
-rwxr-xr-xindra/newview/llappearancemgr.cpp314
-rwxr-xr-xindra/newview/llappearancemgr.h15
-rwxr-xr-xindra/newview/llinventorybridge.cpp90
-rwxr-xr-xindra/newview/llinventorybridge.h8
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp40
-rwxr-xr-xindra/newview/llinventoryicon.cpp2
-rwxr-xr-xindra/newview/llinventorypanel.cpp4
-rwxr-xr-xindra/newview/llinventorypanel.h2
-rwxr-xr-xindra/newview/lllocalbitmaps.cpp14
-rwxr-xr-xindra/newview/llpaneleditwearable.cpp44
-rwxr-xr-xindra/newview/llsidepanelappearance.cpp3
-rwxr-xr-xindra/newview/llviewerinventory.cpp2
-rwxr-xr-xindra/newview/llvoavatarself.cpp12
-rwxr-xr-xindra/newview/llwearableitemslist.cpp65
-rwxr-xr-xindra/newview/llwearableitemslist.h1
17 files changed, 405 insertions, 236 deletions
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 1523336b0d..ef239df8cd 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.7.29
+3.7.30
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index f06ffb4fb3..5589ab4aa7 100755
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -633,10 +633,13 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
// the versions themselves are compatible. This code can be removed before release.
if( wearable->getDefinitionVersion() == 24 )
{
- wearable->setDefinitionVersion(22);
- U32 index = getWearableIndex(wearable);
- LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL;
- saveWearable(wearable->getType(),index);
+ U32 index;
+ if (getWearableIndex(wearable,index))
+ {
+ LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL;
+ wearable->setDefinitionVersion(22);
+ saveWearable(wearable->getType(),index);
+ }
}
checkWearableAgainstInventory(viewer_wearable);
@@ -949,7 +952,7 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
LLViewerWearable* old_wearable = getViewerWearable(type,i);
if (old_wearable)
{
- popWearable(old_wearable);
+ eraseWearable(old_wearable);
old_wearable->removeFromAvatar();
}
}
@@ -961,7 +964,7 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
if (old_wearable)
{
- popWearable(old_wearable);
+ eraseWearable(old_wearable);
old_wearable->removeFromAvatar();
}
}
@@ -1163,7 +1166,13 @@ bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD&
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
- U32 index = gAgentWearables.getWearableIndex(wearable);
+ U32 index;
+ if (!gAgentWearables.getWearableIndex(wearable,index))
+ {
+ LL_WARNS() << "Wearable not found" << LL_ENDL;
+ delete wearable;
+ return false;
+ }
if (!new_item)
{
delete wearable;
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index a64d5b50b3..b3317e937e 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1338,90 +1338,113 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false)
}
}
-bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear,
+void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
+ bool do_update,
+ bool replace,
+ LLPointer<LLInventoryCallback> cb)
+{
+ bool first = true;
+
+ LLInventoryObject::const_object_list_t items_to_link;
+
+ for (uuid_vec_t::const_iterator it = item_ids_to_wear.begin();
+ it != item_ids_to_wear.end();
+ ++it)
+ {
+ replace = first && replace;
+ first = false;
+
+ const LLUUID& item_id_to_wear = *it;
+
+ if (item_id_to_wear.isNull()) continue;
+
+ LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
+ if (!item_to_wear) continue;
+
+ if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
+ {
+ LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
+ copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
+ continue;
+ }
+ else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
+ {
+ continue; // not in library and not in agent's inventory
+ }
+ else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
+ {
+ LLNotificationsUtil::add("CannotWearTrash");
+ continue;
+ }
+ else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911
+ {
+ continue;
+ }
+
+ switch (item_to_wear->getType())
+ {
+ case LLAssetType::AT_CLOTHING:
+ {
+ if (gAgentWearables.areWearablesLoaded())
+ {
+ if (!cb && do_update)
+ {
+ cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
+ }
+ LLWearableType::EType type = item_to_wear->getWearableType();
+ S32 wearable_count = gAgentWearables.getWearableCount(type);
+ if ((replace && wearable_count != 0) || !gAgentWearables.canAddWearable(type))
+ {
+ LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
+ wearable_count-1);
+ removeCOFItemLinks(item_id, cb);
+ }
+
+ items_to_link.push_back(item_to_wear);
+ }
+ }
+ break;
+
+ case LLAssetType::AT_BODYPART:
+ {
+ // TODO: investigate wearables may not be loaded at this point EXT-8231
+
+ // Remove the existing wearables of the same type.
+ // Remove existing body parts anyway because we must not be able to wear e.g. two skins.
+ removeCOFLinksOfType(item_to_wear->getWearableType());
+ if (!cb && do_update)
+ {
+ cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
+ }
+ items_to_link.push_back(item_to_wear);
+ }
+ break;
+
+ case LLAssetType::AT_OBJECT:
+ {
+ rez_attachment(item_to_wear, NULL, replace);
+ }
+ break;
+
+ default: continue;
+ }
+ }
+
+ // Batch up COF link creation - more efficient if using AIS.
+ if (items_to_link.size())
+ {
+ link_inventory_array(getCOF(), items_to_link, cb);
+ }
+}
+
+void LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear,
bool do_update,
bool replace,
LLPointer<LLInventoryCallback> cb)
{
-
- if (item_id_to_wear.isNull()) return false;
-
- // *TODO: issue with multi-wearable should be fixed:
- // in this case this method will be called N times - loading started for each item
- // and than N times will be called - loading completed for each item.
- // That means subscribers will be notified that loading is done after first item in a batch is worn.
- // (loading indicator disappears for example before all selected items are worn)
- // Have not fix this issue for 2.1 because of stability reason. EXT-7777.
-
- // Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times
-// gAgentWearables.notifyLoadingStarted();
-
- LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
- if (!item_to_wear) return false;
-
- if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
- {
- LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
- copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
- return false;
- }
- else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
- {
- return false; // not in library and not in agent's inventory
- }
- else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
- {
- LLNotificationsUtil::add("CannotWearTrash");
- return false;
- }
- else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911
- {
- return false;
- }
-
- switch (item_to_wear->getType())
- {
- case LLAssetType::AT_CLOTHING:
- if (gAgentWearables.areWearablesLoaded())
- {
- if (!cb && do_update)
- {
- cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
- }
- S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType());
- if ((replace && wearable_count != 0) ||
- (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) )
- {
- LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
- wearable_count-1);
- removeCOFItemLinks(item_id, cb);
- }
-
- addCOFItemLink(item_to_wear, cb);
- }
- break;
-
- case LLAssetType::AT_BODYPART:
- // TODO: investigate wearables may not be loaded at this point EXT-8231
-
- // Remove the existing wearables of the same type.
- // Remove existing body parts anyway because we must not be able to wear e.g. two skins.
- removeCOFLinksOfType(item_to_wear->getWearableType());
- if (!cb && do_update)
- {
- cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
- }
- addCOFItemLink(item_to_wear, cb);
- break;
-
- case LLAssetType::AT_OBJECT:
- rez_attachment(item_to_wear, NULL, replace);
- break;
-
- default: return false;;
- }
-
- return true;
+ uuid_vec_t ids;
+ ids.push_back(item_id_to_wear);
+ wearItemsOnAvatar(ids, do_update, replace, cb);
}
// Update appearance from outfit folder.
@@ -1782,6 +1805,49 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
return items.size() > 0;
}
+// Moved from LLWearableList::ContextMenu for wider utility.
+bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids)
+{
+ // TODO: investigate wearables may not be loaded at this point EXT-8231
+
+ U32 n_objects = 0;
+ U32 n_clothes = 0;
+
+ // Count given clothes (by wearable type) and objects.
+ for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(*it);
+ if (!item)
+ {
+ return false;
+ }
+
+ if (item->getType() == LLAssetType::AT_OBJECT)
+ {
+ ++n_objects;
+ }
+ else if (item->getType() == LLAssetType::AT_CLOTHING)
+ {
+ ++n_clothes;
+ }
+ else
+ {
+ LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
+ return false;
+ }
+ }
+
+ // Check whether we can add all the objects.
+ if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects))
+ {
+ return false;
+ }
+
+ // Check whether we can add all the clothes.
+ U32 sum_clothes = n_clothes + gAgentWearables.getClothingLayerCount();
+ return sum_clothes <= LLAgentWearables::MAX_CLOTHING_LAYERS;
+}
+
void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb)
{
LLInventoryModel::cat_array_t cats;
@@ -1804,25 +1870,39 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLIn
// Keep the last N wearables of each type. For viewer 2.0, N is 1 for
// both body parts and clothing items.
void LLAppearanceMgr::filterWearableItems(
- LLInventoryModel::item_array_t& items, S32 max_per_type)
-{
- // Divvy items into arrays by wearable type.
- std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT);
- divvyWearablesByType(items, items_by_type);
-
- // rebuild items list, retaining the last max_per_type of each array
- items.clear();
- for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
- {
- S32 size = items_by_type[i].size();
- if (size <= 0)
- continue;
- S32 start_index = llmax(0,size-max_per_type);
- for (S32 j = start_index; j<size; j++)
- {
- items.push_back(items_by_type[i][j]);
- }
- }
+ LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total)
+{
+ // Restrict by max total items first.
+ if ((max_total > 0) && (items.size() > max_total))
+ {
+ LLInventoryModel::item_array_t items_to_keep;
+ for (S32 i=0; i<max_total; i++)
+ {
+ items_to_keep.push_back(items[i]);
+ }
+ items = items_to_keep;
+ }
+
+ if (max_per_type > 0)
+ {
+ // Divvy items into arrays by wearable type.
+ std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT);
+ divvyWearablesByType(items, items_by_type);
+
+ // rebuild items list, retaining the last max_per_type of each array
+ items.clear();
+ for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
+ {
+ S32 size = items_by_type[i].size();
+ if (size <= 0)
+ continue;
+ S32 start_index = llmax(0,size-max_per_type);
+ for (S32 j = start_index; j<size; j++)
+ {
+ items.push_back(items_by_type[i][j]);
+ }
+ }
+ }
}
void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
@@ -1864,7 +1944,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
reverse(body_items.begin(), body_items.end());
// Reduce body items to max of one per type.
removeDuplicateItems(body_items);
- filterWearableItems(body_items, 1);
+ filterWearableItems(body_items, 1, 0);
// - Wearables: include COF contents only if appending.
LLInventoryModel::item_array_t wear_items;
@@ -1873,7 +1953,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING);
// Reduce wearables to max of one per type.
removeDuplicateItems(wear_items);
- filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
+ filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS);
// - Attachments: include COF contents only if appending.
LLInventoryModel::item_array_t obj_items;
@@ -2062,7 +2142,8 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list,
S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
LLAssetType::EType type,
- S32 max_items,
+ S32 max_items_per_type,
+ S32 max_items_total,
LLInventoryObject::object_list_t& items_to_kill)
{
S32 to_kill_count = 0;
@@ -2071,9 +2152,9 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
getDescendentsOfAssetType(cat_id, items, type);
LLInventoryModel::item_array_t curr_items = items;
removeDuplicateItems(items);
- if (max_items > 0)
+ if (max_items_per_type > 0 || max_items_total > 0)
{
- filterWearableItems(items, max_items);
+ filterWearableItems(items, max_items_per_type, max_items_total);
}
LLInventoryModel::item_array_t kill_items;
item_array_diff(curr_items,items,kill_items);
@@ -2092,11 +2173,11 @@ void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id,
LLInventoryObject::object_list_t& items_to_kill)
{
findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART,
- 1, items_to_kill);
+ 1, 0, items_to_kill);
findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING,
- LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
+ 0, LLAgentWearables::MAX_CLOTHING_LAYERS, items_to_kill);
findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT,
- -1, items_to_kill);
+ 0, 0, items_to_kill);
}
void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb)
@@ -2588,7 +2669,6 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
item_array,
LLInventoryModel::EXCLUDE_TRASH);
bool linked_already = false;
- U32 count = 0;
for (S32 i=0; i<item_array.size(); i++)
{
// Are these links to the same object?
@@ -2608,14 +2688,13 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
// type? If so, new item will replace old.
else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type))
{
- ++count;
- if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type))
+ if (is_body_part && inv_item->getIsLinkType())
{
remove_inventory_item(inv_item->getUUID(), cb);
}
- else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
+ else if (!gAgentWearables.canAddWearable(wearable_type))
{
- // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE
+ // MULTI-WEARABLES: make sure we don't go over clothing limits
remove_inventory_item(inv_item->getUUID(), cb);
}
}
@@ -4071,16 +4150,7 @@ void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
void wear_multiple(const uuid_vec_t& ids, bool replace)
{
LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
-
- bool first = true;
- uuid_vec_t::const_iterator it;
- for (it = ids.begin(); it != ids.end(); ++it)
- {
- // if replace is requested, the first item worn will replace the current top
- // item, and others will be added.
- LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb);
- first = false;
- }
+ LLAppearanceMgr::instance().wearItemsOnAvatar(ids, false, replace, cb);
}
// SLapp for easy-wearing of a stock (library) avatar
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 7742a19c07..ee9d3b7209 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -67,7 +67,8 @@ public:
void addCategoryToCurrentOutfit(const LLUUID& cat_id);
S32 findExcessOrDuplicateItems(const LLUUID& cat_id,
LLAssetType::EType type,
- S32 max_items,
+ S32 max_items_per_type,
+ S32 max_items_total,
LLInventoryObject::object_list_t& items_to_kill);
void findAllExcessOrDuplicateItems(const LLUUID& cat_id,
LLInventoryObject::object_list_t& items_to_kill);
@@ -99,6 +100,9 @@ public:
// Determine whether we can replace current outfit with the given one.
bool getCanReplaceCOF(const LLUUID& outfit_cat_id);
+ // Can we add all referenced items to the avatar?
+ bool canAddWearables(const uuid_vec_t& item_ids);
+
// Copy all items in a category.
void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb);
@@ -117,8 +121,13 @@ public:
// find the UUID of the currently worn outfit (Base Outfit)
const LLUUID getBaseOutfitUUID();
+ void wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
+ bool do_update,
+ bool replace,
+ LLPointer<LLInventoryCallback> cb = NULL);
+
// Wear/attach an item (from a user's inventory) on the agent
- bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false,
+ void wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false,
LLPointer<LLInventoryCallback> cb = NULL);
// Update the displayed outfit name in UI.
@@ -235,7 +244,7 @@ protected:
private:
- void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type);
+ void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total);
void getDescendentsOfAssetType(const LLUUID& category,
LLInventoryModel::item_array_t& items,
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 1dc5558555..a047ed6fee 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -74,6 +74,7 @@
#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llwearablelist.h"
+#include "llwearableitemslist.h"
#include "lllandmarkactions.h"
#include "llpanellandmarks.h"
@@ -557,6 +558,46 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
return TRUE;
}
+void disable_context_entries_if_present(LLMenuGL& menu,
+ const menuentry_vec_t &disabled_entries)
+{
+ const LLView::child_list_t *list = menu.getChildList();
+ for (LLView::child_list_t::const_iterator itor = list->begin();
+ itor != list->end();
+ ++itor)
+ {
+ LLView *menu_item = (*itor);
+ std::string name = menu_item->getName();
+
+ // descend into split menus:
+ LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item);
+ if ((name == "More") && branchp)
+ {
+ disable_context_entries_if_present(*branchp->getBranch(), disabled_entries);
+ }
+
+ bool found = false;
+ menuentry_vec_t::const_iterator itor2;
+ for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2)
+ {
+ if (*itor2 == name)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ menu_item->setVisible(TRUE);
+ // A bit of a hack so we can remember that some UI element explicitly set this to be visible
+ // so that some other UI element from multi-select doesn't later set this invisible.
+ menu_item->pushVisible(TRUE);
+
+ menu_item->setEnabled(FALSE);
+ }
+ }
+}
void hide_context_entries(LLMenuGL& menu,
const menuentry_vec_t &entries_to_show,
const menuentry_vec_t &disabled_entries)
@@ -765,6 +806,31 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
hide_context_entries(menu, items, disabled_items);
}
+bool get_selection_item_uuids(LLFolderView::selected_items_t& selected_items, uuid_vec_t& ids)
+{
+ uuid_vec_t results;
+ S32 non_item = 0;
+ for(LLFolderView::selected_items_t::iterator it = selected_items.begin(); it != selected_items.end(); ++it)
+ {
+ LLItemBridge *view_model = dynamic_cast<LLItemBridge *>((*it)->getViewModelItem());
+
+ if(view_model && view_model->getUUID().notNull())
+ {
+ results.push_back(view_model->getUUID());
+ }
+ else
+ {
+ non_item++;
+ }
+ }
+ if (non_item == 0)
+ {
+ ids = results;
+ return true;
+ }
+ return false;
+}
+
void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items,
menuentry_vec_t &disabled_items)
{
@@ -1120,7 +1186,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
{
LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
}
- new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags);
+ new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, LLWearableType::inventoryFlagsToWearableType(flags));
break;
case LLAssetType::AT_CATEGORY:
if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
@@ -3585,7 +3651,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
if(!model) return;
buildContextMenuOptions(flags, items, disabled_items);
- hide_context_entries(menu, items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
// Reposition the menu, in case we're adding items to an existing menu.
menu.needsArrange();
@@ -5770,7 +5836,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
if (LLWearableType::getAllowMultiwear(mWearableType))
{
items.push_back(std::string("Wearable Add"));
- if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
+ if (!gAgentWearables.canAddWearable(mWearableType))
{
disabled_items.push_back(std::string("Wearable Add"));
}
@@ -6439,4 +6505,22 @@ LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge(
return new_listener;
}
+LLFolderViewGroupedItemBridge::LLFolderViewGroupedItemBridge()
+{
+}
+
+void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu)
+{
+ uuid_vec_t ids;
+ menuentry_vec_t disabled_items;
+ if (get_selection_item_uuids(selected_items, ids))
+ {
+ if (!LLAppearanceMgr::instance().canAddWearables(ids))
+ {
+ disabled_items.push_back(std::string("Wearable Add"));
+ }
+ }
+ disable_context_entries_if_present(menu, disabled_items);
+}
+
// EOF
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index f8ef15991d..300cef7deb 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -37,6 +37,7 @@
#include "llviewerwearable.h"
#include "lltooldraganddrop.h"
#include "lllandmarklist.h"
+#include "llfolderviewitem.h"
class LLInventoryFilter;
class LLInventoryPanel;
@@ -689,4 +690,11 @@ void hide_context_entries(LLMenuGL& menu,
const menuentry_vec_t &entries_to_show,
const menuentry_vec_t &disabled_entries);
+class LLFolderViewGroupedItemBridge: public LLFolderViewGroupedItemModel
+{
+public:
+ LLFolderViewGroupedItemBridge();
+ virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu);
+};
+
#endif // LL_LLINVENTORYBRIDGE_H
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 1abc09bf3b..2546db546b 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -45,6 +45,7 @@
// newview includes
#include "llappearancemgr.h"
#include "llappviewer.h"
+#include "llavataractions.h"
#include "llclipboard.h"
#include "lldonotdisturbnotificationstorage.h"
#include "llfloaterinventory.h"
@@ -1114,16 +1115,35 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
LLFloater::setFloaterHost(multi_propertiesp);
}
- std::set<LLFolderViewItem*>::iterator set_iter;
-
- for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter)
- {
- LLFolderViewItem* folder_item = *set_iter;
- if(!folder_item) continue;
- LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
- if(!bridge) continue;
- bridge->performAction(model, action);
- }
+
+ std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
+ uuid_vec_t ids;
+ std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids));
+ // Check for actions that get handled in bulk
+ if (action == "wear")
+ {
+ wear_multiple(ids, true);
+ }
+ else if (action == "wear_add")
+ {
+ wear_multiple(ids, false);
+ }
+ else if (action == "take_off" || action == "detach")
+ {
+ LLAppearanceMgr::instance().removeItemsFromAvatar(ids);
+ }
+ else
+ {
+ std::set<LLFolderViewItem*>::iterator set_iter;
+ for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter)
+ {
+ LLFolderViewItem* folder_item = *set_iter;
+ if(!folder_item) continue;
+ LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
+ if(!bridge) continue;
+ bridge->performAction(model, action);
+ }
+ }
LLFloater::setFloaterHost(NULL);
if (multi_previewp)
diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
index b7c4ec6f8b..013a5a7629 100755
--- a/indra/newview/llinventoryicon.cpp
+++ b/indra/newview/llinventoryicon.cpp
@@ -183,6 +183,6 @@ const std::string& LLInventoryIcon::getIconName(LLInventoryType::EIconName idx)
LLInventoryType::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag)
{
- const LLWearableType::EType wearable_type = LLWearableType::EType(LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK & misc_flag);
+ const LLWearableType::EType wearable_type = LLWearableType::inventoryFlagsToWearableType(misc_flag);
return LLWearableType::getIconName(wearable_type);
}
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 3546317471..4a230accb6 100755
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -146,7 +146,8 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
mShowEmptyMessage(p.show_empty_message),
mViewsInitialized(false),
mInvFVBridgeBuilder(NULL),
- mInventoryViewModel(p.name)
+ mInventoryViewModel(p.name),
+ mGroupedItemBridge(new LLFolderViewGroupedItemBridge)
{
mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
@@ -186,6 +187,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
NULL,
root_id);
p.view_model = &mInventoryViewModel;
+ p.grouped_item_model = mGroupedItemBridge;
p.use_label_suffix = mParams.use_label_suffix;
p.allow_multiselect = mAllowMultiSelect;
p.show_empty_message = mShowEmptyMessage;
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index a490dfce5d..bc4c10e441 100755
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -43,6 +43,7 @@ class LLInvFVBridge;
class LLInventoryFolderViewModelBuilder;
class LLInvPanelComplObserver;
class LLFolderViewModelInventory;
+class LLFolderViewGroupedItemBridge;
namespace LLInitParam
{
@@ -240,6 +241,7 @@ protected:
LLScrollContainer* mScroller;
LLFolderViewModelInventory mInventoryViewModel;
+ LLPointer<LLFolderViewGroupedItemBridge> mGroupedItemBridge;
Params mParams; // stored copy of parameter block
std::map<LLUUID, LLFolderViewItem*> mItemMap;
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 8fb7550169..1380345164 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -545,12 +545,14 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp
LLAvatarAppearanceDefines::ETextureIndex reg_texind = getTexIndex(type, baked_texind);
if (reg_texind != LLAvatarAppearanceDefines::TEX_NUM_INDICES)
{
- U32 index = gAgentWearables.getWearableIndex(wearable);
- gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index);
- gAgentAvatarp->wearableUpdated(type);
-
- /* telling the manager to rebake once update cycle is fully done */
- LLLocalBitmapMgr::setNeedsRebake();
+ U32 index;
+ if (gAgentWearables.getWearableIndex(wearable,index))
+ {
+ gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index);
+ gAgentAvatarp->wearableUpdated(type);
+ /* telling the manager to rebake once update cycle is fully done */
+ LLLocalBitmapMgr::setNeedsRebake();
+ }
}
}
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 19a86cdcea..9bd6007772 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -925,17 +925,17 @@ void LLPanelEditWearable::onCommitSexChange()
if (!isAgentAvatarValid()) return;
LLWearableType::EType type = mWearablePtr->getType();
- U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
-
- if( !gAgentWearables.isWearableModifiable(type, index))
+ U32 index;
+ if( !gAgentWearables.getWearableIndex(mWearablePtr, index) ||
+ !gAgentWearables.isWearableModifiable(type, index))
{
- return;
+ return;
}
LLViewerVisualParam* param = static_cast<LLViewerVisualParam*>(gAgentAvatarp->getVisualParam( "male" ));
if( !param )
{
- return;
+ return;
}
bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE;
@@ -978,10 +978,17 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
}
if (getWearable())
{
- U32 index = gAgentWearables.getWearableIndex(getWearable());
- gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
- LLVisualParamHint::requestHintUpdates();
- gAgentAvatarp->wearableUpdated(type);
+ U32 index;
+ if (gAgentWearables.getWearableIndex(getWearable(), index))
+ {
+ gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
+ LLVisualParamHint::requestHintUpdates();
+ gAgentAvatarp->wearableUpdated(type);
+ }
+ else
+ {
+ LL_WARNS() << "wearable not found in gAgentWearables" << LL_ENDL;
+ }
}
}
else
@@ -1058,7 +1065,12 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)
return;
}
- U32 index = gAgentWearables.getWearableIndex(mWearablePtr);
+ U32 index;
+ if (!gAgentWearables.getWearableIndex(mWearablePtr, index))
+ {
+ LL_WARNS() << "wearable not found" << LL_ENDL;
+ return;
+ }
std::string new_name = mNameEditor->getText();
@@ -1574,6 +1586,12 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
LL_INFOS() << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << LL_ENDL;
+ U32 index;
+ if (!gAgentWearables.getWearableIndex(getWearable(),index))
+ {
+ LL_WARNS() << "wearable not found" << LL_ENDL;
+ return;
+ }
bool new_invis_state = checkbox_ctrl->get();
if (new_invis_state)
{
@@ -1581,9 +1599,8 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
mPreviousAlphaTexture[te] = lto->getID();
LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );
- U32 index = gAgentWearables.getWearableIndex(getWearable());
- gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
- gAgentAvatarp->wearableUpdated(getWearable()->getType());
+ gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType());
}
else
{
@@ -1598,7 +1615,6 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id);
if (!image) return;
- U32 index = gAgentWearables.getWearableIndex(getWearable());
gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
gAgentAvatarp->wearableUpdated(getWearable()->getType());
}
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 64f24cd291..ea7cf82674 100755
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -212,7 +212,8 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
}
if (is_wearable_edit_visible)
{
- if (gAgentWearables.getWearableIndex(wearable_ptr) == LLAgentWearables::MAX_CLOTHING_PER_TYPE)
+ U32 index;
+ if (!gAgentWearables.getWearableIndex(wearable_ptr,index))
{
// we're no longer wearing the wearable we were last editing, switch back to outfit editor
showOutfitEditPanel();
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index d6c8ba10f6..d112118082 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -2106,7 +2106,7 @@ LLWearableType::EType LLViewerInventoryItem::getWearableType() const
{
return LLWearableType::WT_INVALID;
}
- return LLWearableType::EType(getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK);
+ return LLWearableType::inventoryFlagsToWearableType(getFlags());
}
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 1e9945b514..56997c928a 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1570,8 +1570,16 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t
return LLVOAvatar::isTextureVisible(type);
}
- U32 index = gAgentWearables.getWearableIndex(wearable);
- return isTextureVisible(type,index);
+ U32 index;
+ if (gAgentWearables.getWearableIndex(wearable,index))
+ {
+ return isTextureVisible(type,index);
+ }
+ else
+ {
+ LL_WARNS() << "Wearable not found" << LL_ENDL;
+ return FALSE;
+ }
}
bool LLVOAvatarSelf::areTexturesCurrent() const
diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index fac0fd63ee..888ead0613 100755
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -894,13 +894,13 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu
setMenuItemVisible(menu, "wear_wear", n_already_worn == 0 && n_worn == 0 && can_be_worn);
setMenuItemEnabled(menu, "wear_wear", n_already_worn == 0 && n_worn == 0);
setMenuItemVisible(menu, "wear_add", wear_add_visible);
- setMenuItemEnabled(menu, "wear_add", canAddWearables(ids));
+ setMenuItemEnabled(menu, "wear_add", LLAppearanceMgr::instance().canAddWearables(ids));
setMenuItemVisible(menu, "wear_replace", n_worn == 0 && n_already_worn != 0 && can_be_worn);
//visible only when one item selected and this item is worn
setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1);
setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1);
setMenuItemVisible(menu, "create_new", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1);
- setMenuItemEnabled(menu, "create_new", canAddWearables(ids));
+ setMenuItemEnabled(menu, "create_new", LLAppearanceMgr::instance().canAddWearables(ids));
setMenuItemVisible(menu, "show_original", !standalone);
setMenuItemEnabled(menu, "show_original", n_items == 1 && n_links == n_items);
setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items);
@@ -1004,65 +1004,4 @@ void LLWearableItemsList::ContextMenu::createNewWearable(const LLUUID& item_id)
LLAgentWearables::createWearable(item->getWearableType(), true);
}
-// Returns true if all the given objects and clothes can be added.
-// static
-bool LLWearableItemsList::ContextMenu::canAddWearables(const uuid_vec_t& item_ids)
-{
- // TODO: investigate wearables may not be loaded at this point EXT-8231
-
- U32 n_objects = 0;
- boost::unordered_map<LLWearableType::EType, U32> clothes_by_type;
-
- // Count given clothes (by wearable type) and objects.
- for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it)
- {
- LLViewerInventoryItem* item = gInventory.getItem(*it);
- if (!item)
- {
- return false;
- }
-
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- ++n_objects;
- }
- else if (item->getType() == LLAssetType::AT_CLOTHING)
- {
- ++clothes_by_type[item->getWearableType()];
- }
- else
- {
- LL_WARNS() << "Unexpected wearable type" << LL_ENDL;
- return false;
- }
- }
-
- // Check whether we can add all the objects.
- if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects))
- {
- return false;
- }
-
- // Check whether we can add all the clothes.
- boost::unordered_map<LLWearableType::EType, U32>::const_iterator m_it;
- for (m_it = clothes_by_type.begin(); m_it != clothes_by_type.end(); ++m_it)
- {
- LLWearableType::EType w_type = m_it->first;
- U32 n_clothes = m_it->second;
-
- U32 wearable_count = gAgentWearables.getWearableCount(w_type);
- if ((wearable_count > 0) && !LLWearableType::getAllowMultiwear(w_type))
- {
- return false;
- }
- if ((wearable_count + n_clothes) > LLAgentWearables::MAX_CLOTHING_PER_TYPE)
- {
- return false;
- }
-
- }
-
- return true;
-}
-
// EOF
diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h
index c731a7d6cf..e6788ab249 100755
--- a/indra/newview/llwearableitemslist.h
+++ b/indra/newview/llwearableitemslist.h
@@ -429,7 +429,6 @@ public:
static void setMenuItemEnabled(LLContextMenu* menu, const std::string& name, bool val);
static void updateMask(U32& mask, LLAssetType::EType at);
static void createNewWearable(const LLUUID& item_id);
- static bool canAddWearables(const uuid_vec_t& item_ids);
LLWearableItemsList* mParent;
};