summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/llassettype.cpp26
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llagentwearables.cpp138
-rw-r--r--indra/newview/llagentwearables.h1
-rw-r--r--indra/newview/llappearancemgr.cpp793
-rw-r--r--indra/newview/llappearancemgr.h70
-rw-r--r--indra/newview/llfolderviewitem.cpp6
-rw-r--r--indra/newview/llinventorybridge.cpp879
-rw-r--r--indra/newview/llinventorybridge.h9
-rw-r--r--indra/newview/llinventoryfilter.h1
-rw-r--r--indra/newview/llinventorymodel.cpp55
-rw-r--r--indra/newview/llinventorymodel.h28
-rw-r--r--indra/newview/llstartup.cpp7
-rw-r--r--indra/newview/lltooldraganddrop.cpp5
-rw-r--r--indra/newview/llviewerinventory.cpp40
-rw-r--r--indra/newview/llviewerinventory.h9
-rw-r--r--indra/newview/llviewermenu.cpp5
17 files changed, 1212 insertions, 862 deletions
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index e595cc1f8b..5d7672b378 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -80,27 +80,27 @@ LLAssetDictionary::LLAssetDictionary()
{
// DESCRIPTION TYPE NAME HUMAN NAME CATEGORY NAME DRAG&DROP CAN LINK? PROTECTED?
// |--------------------|-----------|-------------------|-------------------|---------------|-----------|-----------|
- addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", "Textures", DAD_TEXTURE, FALSE, TRUE));
- addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", "Sounds", DAD_SOUND, FALSE, TRUE));
- addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", "Calling Cards", DAD_CALLINGCARD, FALSE, TRUE));
- addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", "Landmarks", DAD_LANDMARK, FALSE, TRUE));
- addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", "Scripts", DAD_NONE, FALSE, TRUE));
+ addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", "Textures", DAD_TEXTURE, TRUE, TRUE));
+ addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", "Sounds", DAD_SOUND, TRUE, TRUE));
+ addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", "Calling Cards", DAD_CALLINGCARD, TRUE, TRUE));
+ addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", "Landmarks", DAD_LANDMARK, TRUE, TRUE));
+ addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", "Scripts", DAD_NONE, TRUE, TRUE));
addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", "Clothing", DAD_CLOTHING, TRUE, TRUE));
addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", "Objects", DAD_OBJECT, TRUE, TRUE));
- addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", "Notecards", DAD_NOTECARD, FALSE, TRUE));
+ addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", "Notecards", DAD_NOTECARD, TRUE, TRUE));
addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", "New Folder", DAD_CATEGORY, TRUE, TRUE));
addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", "Inventory", DAD_ROOT_CATEGORY, TRUE, TRUE));
- addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", "Scripts", DAD_SCRIPT, FALSE, TRUE));
- addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", "Scripts", DAD_NONE, FALSE, TRUE));
- addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", "Uncompressed Images", DAD_NONE, FALSE, TRUE));
+ addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", "Scripts", DAD_SCRIPT, TRUE, TRUE));
+ addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", "Scripts", DAD_NONE, TRUE, TRUE));
+ addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", "Uncompressed Images", DAD_NONE, TRUE, TRUE));
addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", "Body Parts", DAD_BODYPART, TRUE, TRUE));
addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", "Trash", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", "Photo Album", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", "Lost And Found", DAD_NONE, FALSE, TRUE));
- addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", "Uncompressed SoundS", DAD_NONE, FALSE, TRUE));
- addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, FALSE, TRUE));
- addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, FALSE, TRUE));
- addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, FALSE, TRUE));
+ addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", "Uncompressed SoundS", DAD_NONE, TRUE, TRUE));
+ addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, TRUE, TRUE));
+ addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, TRUE, TRUE));
+ addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, TRUE, TRUE));
addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, TRUE, TRUE));
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", "New Folder", DAD_NONE, FALSE, TRUE));
addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "favorite", "favorite", DAD_NONE, FALSE, TRUE));
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 321a238f70..96aace9e2d 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -74,6 +74,7 @@ set(viewer_SOURCE_FILES
llagentui.cpp
llagentwearables.cpp
llanimstatelabels.cpp
+ llappearancemgr.cpp
llappviewer.cpp
llassetuploadresponders.cpp
llassetuploadqueue.cpp
@@ -532,6 +533,7 @@ set(viewer_HEADER_FILES
llassetuploadresponders.h
llassetuploadqueue.h
llaudiosourcevo.h
+ llappearancemgr.h
llavataractions.h
llavatariconctrl.h
llavatarlist.h
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 0f735282cb..54b94482de 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -45,6 +45,7 @@
#include "llwearable.h"
#include "llwearablelist.h"
#include "llgesturemgr.h"
+#include "llappearancemgr.h"
#include <boost/scoped_ptr.hpp>
@@ -76,11 +77,9 @@ public:
initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg
protected:
- void processInitialWearables();
+ void processWearablesMessage();
};
-
-
LLAgentWearables gAgentWearables;
BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
@@ -737,7 +736,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
gAgentWearables.mItemsAwaitingWearableUpdate.clear();
for (S32 i=0; i < num_wearables; i++)
{
- // Parse initial werables data from message system
+ // Parse initial wearables data from message system
U8 type_u8 = 0;
gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);
if (type_u8 >= WT_COUNT)
@@ -1195,7 +1194,7 @@ LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name,
if (!item) continue;
LLPointer<LLInventoryCallback> cb = NULL;
link_inventory_item(gAgent.getID(),
- item->getUUID(),
+ item->getLinkedUUID(),
folder_id,
item->getName(),
LLAssetType::AT_LINK,
@@ -1226,7 +1225,7 @@ LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name,
LLPointer<LLInventoryCallback> cb = NULL;
link_inventory_item(gAgent.getID(),
- item->getUUID(),
+ item->getLinkedUUID(),
folder_id,
item->getName(),
LLAssetType::AT_LINK,
@@ -1781,6 +1780,57 @@ void LLAgentWearables::userRemoveAllAttachments(void* userdata)
gMessageSystem->sendReliable(gAgent.getRegionHost());
}
+void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array)
+{
+ // Build a compound message to send all the objects that need to be rezzed.
+ S32 obj_count = obj_item_array.count();
+
+ // Limit number of packets to send
+ const S32 MAX_PACKETS_TO_SEND = 10;
+ const S32 OBJECTS_PER_PACKET = 4;
+ const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
+ if( obj_count > MAX_OBJECTS_TO_SEND )
+ {
+ obj_count = MAX_OBJECTS_TO_SEND;
+ }
+
+ // Create an id to keep the parts of the compound message together
+ LLUUID compound_msg_id;
+ compound_msg_id.generate();
+ LLMessageSystem* msg = gMessageSystem;
+
+ for(S32 i = 0; i < obj_count; ++i)
+ {
+ if( 0 == (i % OBJECTS_PER_PACKET) )
+ {
+ // Start a new message chunk
+ msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_HeaderData);
+ msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id );
+ msg->addU8Fast(_PREHASH_TotalObjects, obj_count );
+ msg->addBOOLFast(_PREHASH_FirstDetachAll, true );
+ }
+
+ const LLInventoryItem* item = obj_item_array.get(i).get();
+ msg->nextBlockFast(_PREHASH_ObjectData );
+ msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
+ msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
+ msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point
+ pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
+ msg->addStringFast(_PREHASH_Name, item->getName());
+ msg->addStringFast(_PREHASH_Description, item->getDescription());
+
+ if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
+ {
+ // End of message chunk
+ msg->sendReliable( gAgent.getRegion()->getHost() );
+ }
+ }
+}
+
void LLAgentWearables::checkWearablesLoaded() const
{
#ifdef SHOW_ASSERT
@@ -1812,69 +1862,29 @@ void LLAgentWearables::updateServer()
void LLInitialWearablesFetch::done()
{
- // Get the complete information on the items in the library,
- // and set up an observer that will wait for that to happen.
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
+ // No longer need this observer hanging around.
+ gInventory.removeObserver(this);
+ // Fetch the wearable items from the Current Outfit Folder
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t wearable_array;
LLFindWearables is_wearable;
- gInventory.collectDescendentsIf(mCompleteFolders.front(),
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- is_wearable);
- S32 count = item_array.count();
- mCOFInitialWearables.reserve(count);
+ gInventory.collectDescendentsIf(mCompleteFolders.front(), cat_array, wearable_array,
+ LLInventoryModel::EXCLUDE_TRASH, is_wearable);
- for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
- iter != item_array.end();
- iter++)
- {
- const LLViewerInventoryItem *item = (*iter).get();
- // We're only concerned with linked items in the COF. Ignore
- // any non-link items or links to folders.
- if (item->getActualType() != LLAssetType::AT_LINK)
- {
- continue;
- }
- EWearableType type = (EWearableType) (item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK);
- // MULTI-WEARABLE: update
- InitialWearableData wearable_data(type, 0, item->getUUID(), item->getAssetUUID());
- mCOFInitialWearables.push_back(wearable_data);
+ if (wearable_array.count() > 0)
+ {
+ LLAppearanceManager::instance().updateAppearanceFromCOF();
+ }
+ else
+ {
+ processWearablesMessage();
}
-
- gInventory.removeObserver(this);
- processInitialWearables();
delete this;
}
-// This will either grab the contents of the Current Outfit Folder if they exist,
-// or use the old-style initial agent wearables message.
-void LLInitialWearablesFetch::processInitialWearables()
+void LLInitialWearablesFetch::processWearablesMessage()
{
-#ifdef USE_CURRENT_OUTFIT_FOLDER
- if (!mCOFInitialWearables.empty())
- {
- for (U8 i = 0; i < mCOFInitialWearables.size(); ++i)
- {
- // Fetch the wearables in the current outfit folder
- InitialWearableData *wearable_data = new InitialWearableData(mCOFInitialWearables[i]); // This will be deleted in the callback.
- if (wearable_data->mAssetID.notNull())
- {
- LLWearableList::instance().getAsset(wearable_data->mAssetID,
- LLStringUtil::null,
- LLWearableDictionary::getAssetType(wearable_data->mType),
- LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data));
- }
- else
- {
- llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
- << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
- }
- }
- }
- else
-#endif
if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead.
{
LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
@@ -1882,7 +1892,7 @@ void LLInitialWearablesFetch::processInitialWearables()
{
// Populate the current outfit folder with links to the wearables passed in the message
InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback.
-
+
if (wearable_data->mAssetID.notNull())
{
#ifdef USE_CURRENT_OUTFIT_FOLDER
@@ -1899,7 +1909,7 @@ void LLInitialWearablesFetch::processInitialWearables()
else
{
llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
- << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
+ << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
}
}
}
@@ -1908,3 +1918,5 @@ void LLInitialWearablesFetch::processInitialWearables()
LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL;
}
}
+
+
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index b415ef9eb3..cb4de555d5 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -182,6 +182,7 @@ public:
static void userRemoveWearable(void* userdata); // userdata is EWearableType
static void userRemoveAllClothes(void* userdata); // userdata is NULL
static void userRemoveAllAttachments(void* userdata); // userdata is NULL
+ static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array);
BOOL itemUpdatePending(const LLUUID& item_id) const;
U32 itemUpdatePendingCount() const;
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
new file mode 100644
index 0000000000..6c234f23fe
--- /dev/null
+++ b/indra/newview/llappearancemgr.cpp
@@ -0,0 +1,793 @@
+/**
+ * @file llappearancemgr.cpp
+ * @brief Manager for initiating appearance changes on the viewer
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappearancemgr.h"
+#include "llinventorymodel.h"
+#include "llnotifications.h"
+#include "llgesturemgr.h"
+#include "llinventorybridge.h"
+#include "llwearablelist.h"
+#include "llagentwearables.h"
+#include "llagent.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
+#include "llviewerregion.h"
+#include "llfloatercustomize.h"
+
+class LLWearInventoryCategoryCallback : public LLInventoryCallback
+{
+public:
+ LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append)
+ {
+ mCatID = cat_id;
+ mAppend = append;
+ }
+ void fire(const LLUUID& item_id)
+ {
+ /*
+ * Do nothing. We only care about the destructor
+ *
+ * The reason for this is that this callback is used in a hack where the
+ * same callback is given to dozens of items, and the destructor is called
+ * after the last item has fired the event and dereferenced it -- if all
+ * the events actually fire!
+ */
+ }
+
+protected:
+ ~LLWearInventoryCategoryCallback()
+ {
+ // Is the destructor called by ordinary dereference, or because the app's shutting down?
+ // If the inventory callback manager goes away, we're shutting down, no longer want the callback.
+ if( LLInventoryCallbackManager::is_instantiated() )
+ {
+ LLAppearanceManager::wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
+ }
+ else
+ {
+ llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl;
+ }
+ }
+
+private:
+ LLUUID mCatID;
+ bool mAppend;
+};
+
+class LLOutfitObserver : public LLInventoryFetchObserver
+{
+public:
+ LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) :
+ mCatID(cat_id),
+ mCopyItems(copy_items),
+ mAppend(append)
+ {}
+ ~LLOutfitObserver() {}
+ virtual void done(); //public
+
+protected:
+ LLUUID mCatID;
+ bool mCopyItems;
+ bool mAppend;
+};
+
+void LLOutfitObserver::done()
+{
+ // We now have an outfit ready to be copied to agent inventory. Do
+ // it, and wear that outfit normally.
+ if(mCopyItems)
+ {
+ LLInventoryCategory* cat = gInventory.getCategory(mCatID);
+ std::string name;
+ if(!cat)
+ {
+ // should never happen.
+ name = "New Outfit";
+ }
+ else
+ {
+ name = cat->getName();
+ }
+ LLViewerInventoryItem* item = NULL;
+ item_ref_t::iterator it = mComplete.begin();
+ item_ref_t::iterator end = mComplete.end();
+ LLUUID pid;
+ for(; it < end; ++it)
+ {
+ item = (LLViewerInventoryItem*)gInventory.getItem(*it);
+ if(item)
+ {
+ if(LLInventoryType::IT_GESTURE == item->getInventoryType())
+ {
+ pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE);
+ }
+ else
+ {
+ pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING);
+ }
+ break;
+ }
+ }
+ if(pid.isNull())
+ {
+ pid = gInventory.getRootFolderID();
+ }
+
+ LLUUID cat_id = gInventory.createNewCategory(
+ pid,
+ LLAssetType::AT_NONE,
+ name);
+ mCatID = cat_id;
+ LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(mCatID, mAppend);
+ it = mComplete.begin();
+ for(; it < end; ++it)
+ {
+ item = (LLViewerInventoryItem*)gInventory.getItem(*it);
+ if(item)
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ cat_id,
+ std::string(),
+ cb);
+ }
+ }
+ }
+ else
+ {
+ // Wear the inventory category.
+ LLAppearanceManager::wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
+ }
+}
+
+class LLOutfitFetch : public LLInventoryFetchDescendentsObserver
+{
+public:
+ LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {}
+ ~LLOutfitFetch() {}
+ virtual void done();
+protected:
+ bool mCopyItems;
+ bool mAppend;
+};
+
+void LLOutfitFetch::done()
+{
+ // What we do here is get the complete information on the items in
+ // the library, and set up an observer that will wait for that to
+ // happen.
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectDescendents(mCompleteFolders.front(),
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH);
+ S32 count = item_array.count();
+ if(!count)
+ {
+ llwarns << "Nothing fetched in category " << mCompleteFolders.front()
+ << llendl;
+ //dec_busy_count();
+ gInventory.removeObserver(this);
+ delete this;
+ return;
+ }
+
+ LLOutfitObserver* outfit_observer = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend);
+ LLInventoryFetchObserver::item_ref_t ids;
+ for(S32 i = 0; i < count; ++i)
+ {
+ ids.push_back(item_array.get(i)->getUUID());
+ }
+
+ // clean up, and remove this as an observer since the call to the
+ // outfit could notify observers and throw us into an infinite
+ // loop.
+ //dec_busy_count();
+ gInventory.removeObserver(this);
+ delete this;
+
+ // increment busy count and either tell the inventory to check &
+ // call done, or add this object to the inventory for observation.
+ //inc_busy_count();
+
+ // do the fetch
+ outfit_observer->fetchItems(ids);
+ if(outfit_observer->isEverythingComplete())
+ {
+ // everything is already here - call done.
+ outfit_observer->done();
+ }
+ else
+ {
+ // it's all on it's way - add an observer, and the inventory
+ // will call done for us when everything is here.
+ gInventory.addObserver(outfit_observer);
+ }
+}
+
+class LLUpdateAppearanceOnCount: public LLInventoryCallback
+{
+public:
+ LLUpdateAppearanceOnCount(S32 count):
+ mCount(count)
+ {
+ }
+
+ virtual ~LLUpdateAppearanceOnCount()
+ {
+ }
+
+ /* virtual */ void fire(const LLUUID& inv_item)
+ {
+ mCount--;
+ if (mCount==0)
+ {
+ done();
+ }
+ }
+
+ void done()
+ {
+ LLAppearanceManager::updateAppearanceFromCOF();
+ }
+private:
+ S32 mCount;
+};
+
+struct LLFoundData
+{
+ LLFoundData(const LLUUID& item_id,
+ const LLUUID& asset_id,
+ const std::string& name,
+ LLAssetType::EType asset_type) :
+ mItemID(item_id),
+ mAssetID(asset_id),
+ mName(name),
+ mAssetType(asset_type),
+ mWearable( NULL ) {}
+
+ LLUUID mItemID;
+ LLUUID mAssetID;
+ std::string mName;
+ LLAssetType::EType mAssetType;
+ LLWearable* mWearable;
+};
+
+
+struct LLWearableHoldingPattern
+{
+ LLWearableHoldingPattern() : mResolved(0) {}
+ ~LLWearableHoldingPattern()
+ {
+ for_each(mFoundList.begin(), mFoundList.end(), DeletePointer());
+ mFoundList.clear();
+ }
+ typedef std::list<LLFoundData*> found_list_t;
+ found_list_t mFoundList;
+ S32 mResolved;
+ bool append;
+};
+
+
+void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src)
+{
+ LLInventoryModel::item_array_t new_dst;
+ std::set<LLUUID> mark_inventory;
+ std::set<LLUUID> mark_asset;
+
+ S32 inventory_dups = 0;
+ S32 asset_dups = 0;
+
+ for (LLInventoryModel::item_array_t::const_iterator src_pos = src.begin();
+ src_pos != src.end();
+ ++src_pos)
+ {
+ LLUUID src_item_id = (*src_pos)->getLinkedUUID();
+ mark_inventory.insert(src_item_id);
+ LLUUID src_asset_id = (*src_pos)->getAssetUUID();
+ mark_asset.insert(src_asset_id);
+ }
+
+ for (LLInventoryModel::item_array_t::const_iterator dst_pos = dst.begin();
+ dst_pos != dst.end();
+ ++dst_pos)
+ {
+ LLUUID dst_item_id = (*dst_pos)->getLinkedUUID();
+
+ if (mark_inventory.find(dst_item_id) == mark_inventory.end())
+ {
+ }
+ else
+ {
+ inventory_dups++;
+ }
+
+ LLUUID dst_asset_id = (*dst_pos)->getAssetUUID();
+
+ if (mark_asset.find(dst_asset_id) == mark_asset.end())
+ {
+ // Item is not already present in COF.
+ new_dst.put(*dst_pos);
+ mark_asset.insert(dst_item_id);
+ }
+ else
+ {
+ asset_dups++;
+ }
+ }
+ llinfos << "removeDups, original " << dst.count() << " final " << new_dst.count()
+ << " inventory dups " << inventory_dups << " asset_dups " << asset_dups << llendl;
+
+ dst = new_dst;
+}
+
+
+/* static */ LLUUID LLAppearanceManager::getCOF()
+{
+ return gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
+}
+
+// Update appearance from outfit folder.
+/* static */ void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, bool append, bool follow_folder_links)
+{
+ if (!proceed)
+ return;
+
+ updateCOFFromOutfit(category, append, follow_folder_links);
+}
+
+// Update COF contents from outfit folder.
+/* static */ void LLAppearanceManager::updateCOFFromOutfit(const LLUUID& category, bool append, bool follow_folder_links)
+{
+ // BAP consolidate into one "get all 3 types of descendents" function, use both places.
+ LLInventoryModel::item_array_t wear_items;
+ LLInventoryModel::item_array_t obj_items;
+ LLInventoryModel::item_array_t gest_items;
+ getUserDescendents(category, wear_items, obj_items, gest_items, follow_folder_links);
+
+ // Find all the wearables that are in the category's subtree.
+ lldebugs << "updateCOFFromOutfit()" << llendl;
+ if( !wear_items.count() && !obj_items.count() && !gest_items.count())
+ {
+ LLNotifications::instance().add("CouldNotPutOnOutfit");
+ return;
+ }
+
+ const LLUUID &current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
+ // Processes that take time should show the busy cursor
+ //inc_busy_count();
+
+ LLInventoryModel::cat_array_t cof_cats;
+ LLInventoryModel::item_array_t cof_items;
+ gInventory.collectDescendents(current_outfit_id, cof_cats, cof_items,
+ LLInventoryModel::EXCLUDE_TRASH);
+ if (append)
+ {
+ // Remove duplicates
+ removeDuplicateItems(wear_items, cof_items);
+ removeDuplicateItems(obj_items, cof_items);
+ removeDuplicateItems(gest_items, cof_items);
+ }
+
+
+ if (wear_items.count() > 0 || obj_items.count() > 0)
+ {
+ if (!append)
+ {
+ // Remove all current outfit folder links if we're now replacing the contents.
+ for (S32 i = 0; i < cof_items.count(); ++i)
+ {
+ gInventory.purgeObject(cof_items.get(i)->getUUID());
+ }
+ }
+ }
+
+ // BAP should we just link all contents, rather than restricting to these 3 types?
+
+ S32 total_links = gest_items.count() + wear_items.count() + obj_items.count();
+ LLPointer<LLUpdateAppearanceOnCount> link_waiter = new LLUpdateAppearanceOnCount(total_links);
+
+ // Link all gestures in this folder
+ if (gest_items.count() > 0)
+ {
+ llinfos << "Linking " << gest_items.count() << " gestures" << llendl;
+ for (S32 i = 0; i < gest_items.count(); ++i)
+ {
+ const LLInventoryItem* gest_item = gest_items.get(i).get();
+ link_inventory_item(gAgent.getID(), gest_item->getLinkedUUID(), current_outfit_id,
+ gest_item->getName(),
+ LLAssetType::AT_LINK, link_waiter);
+ }
+ }
+
+ // Link all wearables
+ if(wear_items.count() > 0)
+ {
+ llinfos << "Linking " << wear_items.count() << " wearables" << llendl;
+ for(S32 i = 0; i < wear_items.count(); ++i)
+ {
+ // Populate the current outfit folder with links to the newly added wearables
+ const LLInventoryItem* wear_item = wear_items.get(i).get();
+ link_inventory_item(gAgent.getID(),
+ wear_item->getLinkedUUID(), // If this item is a link, then we'll use the linked item's UUID.
+ current_outfit_id,
+ wear_item->getName(),
+ LLAssetType::AT_LINK,
+ link_waiter);
+ }
+ }
+
+ // Link all attachments.
+ if( obj_items.count() > 0 )
+ {
+ llinfos << "Linking " << obj_items.count() << " attachments" << llendl;
+ LLVOAvatar* avatar = gAgent.getAvatarObject();
+ if( avatar )
+ {
+ for(S32 i = 0; i < obj_items.count(); ++i)
+ {
+ const LLInventoryItem* obj_item = obj_items.get(i).get();
+ link_inventory_item(gAgent.getID(),
+ obj_item->getLinkedUUID(), // If this item is a link, then we'll use the linked item's UUID.
+ current_outfit_id,
+ obj_item->getName(),
+ LLAssetType::AT_LINK, link_waiter);
+ }
+ }
+ }
+
+ // In the particular case that we're switching to a different outfit,
+ // create a link to the folder that we wore.
+ LLViewerInventoryCategory* catp = gInventory.getCategory(category);
+ if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT)
+ {
+ link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(),
+ LLAssetType::AT_LINK_FOLDER, LLPointer<LLInventoryCallback>(NULL));
+ }
+}
+
+/* static */
+void LLAppearanceManager::onWearableAssetFetch(LLWearable* wearable, void* data)
+{
+ LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
+ bool append = holder->append;
+
+ if(wearable)
+ {
+ for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
+ iter != holder->mFoundList.end(); ++iter)
+ {
+ LLFoundData* data = *iter;
+ if(wearable->getAssetID() == data->mAssetID)
+ {
+ data->mWearable = wearable;
+ break;
+ }
+ }
+ }
+ holder->mResolved += 1;
+ if(holder->mResolved >= (S32)holder->mFoundList.size())
+ {
+ LLAppearanceManager::updateAgentWearables(holder, append);
+ }
+}
+
+/* static */
+void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder, bool append)
+{
+ lldebugs << "updateAgentWearables()" << llendl;
+ LLInventoryItem::item_array_t items;
+ LLDynamicArray< LLWearable* > wearables;
+
+ // For each wearable type, find the first instance in the category
+ // that we recursed through.
+ for( S32 i = 0; i < WT_COUNT; i++ )
+ {
+ for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
+ iter != holder->mFoundList.end(); ++iter)
+ {
+ LLFoundData* data = *iter;
+ LLWearable* wearable = data->mWearable;
+ if( wearable && ((S32)wearable->getType() == i) )
+ {
+ LLViewerInventoryItem* item;
+ item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID);
+ if( item && (item->getAssetUUID() == wearable->getAssetID()) )
+ {
+ items.put(item);
+ wearables.put(wearable);
+ }
+ break;
+ }
+ }
+ }
+
+ if(wearables.count() > 0)
+ {
+ gAgentWearables.setWearableOutfit(items, wearables, !append);
+ gInventory.notifyObservers();
+ }
+
+ delete holder;
+
+// dec_busy_count();
+}
+
+/* static */ void LLAppearanceManager::updateAppearanceFromCOF()
+{
+ bool follow_folder_links = true;
+ LLUUID current_outfit_id = getCOF();
+
+ // Find all the wearables that are in the COF's subtree.
+ lldebugs << "LLAppearanceManager::updateFromCOF()" << llendl;
+ LLInventoryModel::item_array_t wear_items;
+ LLInventoryModel::item_array_t obj_items;
+ LLInventoryModel::item_array_t gest_items;
+ getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links);
+
+ if( !wear_items.count() && !obj_items.count() && !gest_items.count())
+ {
+ LLNotifications::instance().add("CouldNotPutOnOutfit");
+ return;
+ }
+
+ // Processes that take time should show the busy cursor
+ //inc_busy_count(); // BAP this is currently a no-op in llinventorybridge.cpp - do we need it?
+
+ // Activate all gestures in this folder
+ if (gest_items.count() > 0)
+ {
+ llinfos << "Activating " << gest_items.count() << " gestures" << llendl;
+
+ LLGestureManager::instance().activateGestures(gest_items);
+
+ // Update the inventory item labels to reflect the fact
+ // they are active.
+ LLViewerInventoryCategory* catp = gInventory.getCategory(current_outfit_id);
+ if (catp)
+ {
+ gInventory.updateCategory(catp);
+ gInventory.notifyObservers();
+ }
+ }
+
+ if(wear_items.count() > 0)
+ {
+ // Note: can't do normal iteration, because if all the
+ // wearables can be resolved immediately, then the
+ // callback will be called (and this object deleted)
+ // before the final getNextData().
+ LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
+ LLFoundData* found;
+ LLDynamicArray<LLFoundData*> found_container;
+ for(S32 i = 0; i < wear_items.count(); ++i)
+ {
+ found = new LLFoundData(wear_items.get(i)->getUUID(),
+ wear_items.get(i)->getAssetUUID(),
+ wear_items.get(i)->getName(),
+ wear_items.get(i)->getType());
+ holder->mFoundList.push_front(found);
+ found_container.put(found);
+ }
+ for(S32 i = 0; i < wear_items.count(); ++i)
+ {
+ holder->append = false;
+ found = found_container.get(i);
+
+ // Fetch the wearables about to be worn.
+ LLWearableList::instance().getAsset(found->mAssetID,
+ found->mName,
+ found->mAssetType,
+ LLAppearanceManager::onWearableAssetFetch,
+ (void*)holder);
+ }
+ }
+
+
+ //If the folder doesn't contain only gestures, take off all attachments.
+ if (!(wear_items.count() == 0 && obj_items.count() == 0 && gest_items.count() > 0) )
+ {
+ LLAgentWearables::userRemoveAllAttachments(NULL);
+ }
+
+ if( obj_items.count() > 0 )
+ {
+ // We've found some attachments. Add these.
+ LLVOAvatar* avatar = gAgent.getAvatarObject();
+ if( avatar )
+ {
+ LLAgentWearables::userAttachMultipleAttachments(obj_items);
+ }
+ }
+}
+
+/* static */ void LLAppearanceManager::getUserDescendents(const LLUUID& category,
+ LLInventoryModel::item_array_t& wear_items,
+ LLInventoryModel::item_array_t& obj_items,
+ LLInventoryModel::item_array_t& gest_items,
+ bool follow_folder_links)
+{
+ LLInventoryModel::cat_array_t wear_cats;
+ LLFindWearables is_wearable;
+ gInventory.collectDescendentsIf(category,
+ wear_cats,
+ wear_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_wearable,
+ follow_folder_links);
+
+ LLInventoryModel::cat_array_t obj_cats;
+ LLIsType is_object( LLAssetType::AT_OBJECT );
+ gInventory.collectDescendentsIf(category,
+ obj_cats,
+ obj_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_object,
+ follow_folder_links);
+
+ // Find all gestures in this folder
+ LLInventoryModel::cat_array_t gest_cats;
+ LLIsType is_gesture( LLAssetType::AT_GESTURE );
+ gInventory.collectDescendentsIf(category,
+ gest_cats,
+ gest_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_gesture,
+ follow_folder_links);
+}
+
+void LLAppearanceManager::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
+{
+ if(!category) return;
+
+ lldebugs << "wearInventoryCategory( " << category->getName()
+ << " )" << llendl;
+ // What we do here is get the complete information on the items in
+ // the inventory, and set up an observer that will wait for that to
+ // happen.
+ LLOutfitFetch* outfit_fetcher = new LLOutfitFetch(copy, append);
+ LLInventoryFetchDescendentsObserver::folder_ref_t folders;
+ folders.push_back(category->getUUID());
+ outfit_fetcher->fetchDescendents(folders);
+ //inc_busy_count();
+ if(outfit_fetcher->isEverythingComplete())
+ {
+ // everything is already here - call done.
+ outfit_fetcher->done();
+ }
+ else
+ {
+ // it's all on it's way - add an observer, and the inventory
+ // will call done for us when everything is here.
+ gInventory.addObserver(outfit_fetcher);
+ }
+}
+
+// *NOTE: hack to get from avatar inventory to avatar
+/* static */
+void LLAppearanceManager::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append )
+{
+ // Avoid unintentionally overwriting old wearables. We have to do
+ // this up front to avoid having to deal with the case of multiple
+ // wearables being dirty.
+ if(!category) return;
+ lldebugs << "wearInventoryCategoryOnAvatar( " << category->getName()
+ << " )" << llendl;
+
+ bool follow_folder_links = (category->getPreferredType() == LLAssetType::AT_CURRENT_OUTFIT || category->getPreferredType() == LLAssetType::AT_OUTFIT );
+ if( gFloaterCustomize )
+ {
+ gFloaterCustomize->askToSaveIfDirty(boost::bind(LLAppearanceManager::changeOutfit, _1, category->getUUID(), append, follow_folder_links));
+ }
+ else
+ {
+ LLAppearanceManager::changeOutfit(TRUE, category->getUUID(), append, follow_folder_links );
+ }
+}
+
+/* static */
+void LLAppearanceManager::wearOutfitByName(const std::string& name)
+{
+ llinfos << "Wearing category " << name << llendl;
+ //inc_busy_count();
+
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ LLNameCategoryCollector has_name(name);
+ gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ has_name);
+ bool copy_items = false;
+ LLInventoryCategory* cat = NULL;
+ if (cat_array.count() > 0)
+ {
+ // Just wear the first one that matches
+ cat = cat_array.get(0);
+ }
+ else
+ {
+ gInventory.collectDescendentsIf(LLUUID::null,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ has_name);
+ if(cat_array.count() > 0)
+ {
+ cat = cat_array.get(0);
+ copy_items = true;
+ }
+ }
+
+ if(cat)
+ {
+ LLAppearanceManager::wearInventoryCategory(cat, copy_items, false);
+ }
+ else
+ {
+ llwarns << "Couldn't find outfit " <<name<< " in wearOutfitByName()"
+ << llendl;
+ }
+
+ //dec_busy_count();
+}
+
+void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update )
+{
+ // BAP add check for already in COF.
+ LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
+ link_inventory_item( gAgent.getID(),
+ item->getLinkedUUID(),
+ getCOF(),
+ item->getName(),
+ LLAssetType::AT_LINK,
+ cb);
+}
+
+void LLAppearanceManager::wearEnsemble( LLInventoryCategory* cat, bool do_update )
+{
+ // BAP add check for already in COF.
+ LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
+ link_inventory_item( gAgent.getID(),
+ cat->getLinkedUUID(),
+ getCOF(),
+ cat->getName(),
+ LLAssetType::AT_LINK_FOLDER,
+ cb);
+}
+
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
new file mode 100644
index 0000000000..89b95833d7
--- /dev/null
+++ b/indra/newview/llappearancemgr.h
@@ -0,0 +1,70 @@
+/**
+ * @file llappearancemgr.h
+ * @brief Manager for initiating appearance changes on the viewer
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAPPEARANCEMGR_H
+#define LL_LLAPPEARANCEMGR_H
+
+#include "llsingleton.h"
+#include "llinventorymodel.h"
+
+class LLWearable;
+struct LLWearableHoldingPattern;
+
+class LLAppearanceManager: public LLSingleton<LLAppearanceManager>
+{
+public:
+ static void updateAppearanceFromCOF();
+ static bool needToSaveCOF();
+ static void changeOutfit(bool proceed, const LLUUID& category, bool append, bool follow_folder_links);
+ static void updateCOFFromOutfit(const LLUUID& category, bool append, bool follow_folder_links);
+ static void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
+ static void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
+ static void wearOutfitByName(const std::string& name);
+
+ // Add COF link to individual item.
+ static void wearItem(LLInventoryItem* item, bool do_update = true);
+
+ // Add COF link to ensemble folder.
+ static void wearEnsemble(LLInventoryCategory* item, bool do_update = true);
+
+private:
+ static LLUUID getCOF();
+ static void getUserDescendents(const LLUUID& category,
+ LLInventoryModel::item_array_t& wear_items,
+ LLInventoryModel::item_array_t& obj_items,
+ LLInventoryModel::item_array_t& gest_items,
+ bool follow_folder_links);
+ static void onWearableAssetFetch(LLWearable* wearable, void* data);
+ static void updateAgentWearables(LLWearableHoldingPattern* holder, bool append);
+};
+
+#endif
diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index f1e499e14b..490929e5a6 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -1183,6 +1183,8 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter)
// you will automatically fail this time, so we only
// check against items that have passed the filter
S32 must_pass_generation = filter.getMustPassGeneration();
+
+ bool autoopen_folders = (filter.hasFilterString());
// if we have already been filtered against this generation, skip out
if (getCompletedFilterGeneration() >= filter_generation)
@@ -1255,7 +1257,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter)
if ((*fit)->getFiltered() || (*fit)->hasFilteredDescendants(filter.getMinRequiredGeneration()))
{
mMostFilteredDescendantGeneration = filter_generation;
- if (getRoot()->needsAutoSelect())
+ if (getRoot()->needsAutoSelect() && autoopen_folders)
{
(*fit)->setOpenArrangeRecursively(TRUE);
}
@@ -1271,7 +1273,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter)
if ((*fit)->getFiltered() || (*fit)->hasFilteredDescendants(filter_generation))
{
mMostFilteredDescendantGeneration = filter_generation;
- if (getRoot()->needsAutoSelect())
+ if (getRoot()->needsAutoSelect() && autoopen_folders)
{
(*fit)->setOpenArrangeRecursively(TRUE);
}
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index adc73111e0..eb07078402 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -92,6 +92,7 @@
#include "llsidetray.h"
#include "llfloateropenobject.h"
#include "lltrans.h"
+#include "llappearancemgr.h"
using namespace LLOldEvents;
@@ -111,12 +112,7 @@ void dec_busy_count()
}
// Function declarations
-struct LLWearableHoldingPattern;
void wear_add_inventory_item_on_avatar(LLInventoryItem* item);
-void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append);
-void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links);
-void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*);
-void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append);
void remove_inventory_category_from_avatar(LLInventoryCategory* category);
void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id);
bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
@@ -161,8 +157,6 @@ std::string ICON_NAME[ICON_NAME_COUNT] =
"inv_item_linkfolder.tga"
};
-BOOL gAddToOutfit = FALSE;
-
// +=================================================+
// | LLInventoryPanelObserver |
@@ -474,7 +468,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
{
return FALSE;
}
- LLInventoryModel* model = getInventoryModel();
+ const LLInventoryModel* model = getInventoryModel();
if (!model)
{
return FALSE;
@@ -485,7 +479,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const
S32 count = objects.count();
for(S32 i = 0; i < count; i++)
{
- LLInventoryItem *item = model->getItem(objects.get(i));
+ const LLInventoryItem *item = model->getItem(objects.get(i));
if (item)
{
if (!LLAssetType::lookupCanLink(item->getActualType()))
@@ -665,7 +659,7 @@ BOOL LLInvFVBridge::isInTrash() const
{
LLInventoryModel* model = getInventoryModel();
if(!model) return FALSE;
- const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
return model->isObjectDescendentOf(mUUID, trash_id);
}
@@ -673,12 +667,12 @@ BOOL LLInvFVBridge::isLinkedObjectInTrash() const
{
if (isInTrash()) return TRUE;
- LLInventoryObject *obj = getInventoryObject();
+ const LLInventoryObject *obj = getInventoryObject();
if (obj && obj->getIsLinkType())
{
LLInventoryModel* model = getInventoryModel();
if(!model) return FALSE;
- const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id);
}
return FALSE;
@@ -686,12 +680,24 @@ BOOL LLInvFVBridge::isLinkedObjectInTrash() const
BOOL LLInvFVBridge::isAgentInventory() const
{
- LLInventoryModel* model = getInventoryModel();
+ const LLInventoryModel* model = getInventoryModel();
if(!model) return FALSE;
if(gInventory.getRootFolderID() == mUUID) return TRUE;
return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
}
+BOOL LLInvFVBridge::isCOFFolder() const
+{
+ const LLInventoryModel* model = getInventoryModel();
+ if(!model) return TRUE;
+ const LLUUID cof_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
+ if (mUUID == cof_id || model->isObjectDescendentOf(mUUID, cof_id))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
BOOL LLInvFVBridge::isItemPermissive() const
{
return FALSE;
@@ -993,7 +999,7 @@ void LLItemBridge::restoreItem()
if(item)
{
LLInventoryModel* model = getInventoryModel();
- LLUUID new_parent = model->findCategoryUUIDForType(item->getType());
+ const LLUUID new_parent = model->findCategoryUUIDForType(item->getType());
// do not restamp on restore.
LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
}
@@ -1026,8 +1032,7 @@ void LLItemBridge::restoreToWorld()
}
// Check if it's in the trash. (again similar to the normal rez logic)
- LLUUID trash_id;
- trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id))
{
remove_from_inventory = TRUE;
@@ -1423,6 +1428,46 @@ BOOL LLFolderBridge::copyToClipboard() const
return FALSE;
}
+BOOL LLFolderBridge::isClipboardPasteableAsLink() const
+{
+ // Check normal paste-as-link permissions
+ if (!LLInvFVBridge::isClipboardPasteableAsLink())
+ {
+ return FALSE;
+ }
+
+ const LLInventoryModel* model = getInventoryModel();
+ if (!model)
+ {
+ return FALSE;
+ }
+
+ const LLViewerInventoryCategory *current_cat = getCategory();
+ if (current_cat)
+ {
+ const LLUUID &current_cat_id = current_cat->getUUID();
+ LLDynamicArray<LLUUID> objects;
+ LLInventoryClipboard::instance().retrieve(objects);
+ S32 count = objects.count();
+ for(S32 i = 0; i < count; i++)
+ {
+ const LLInventoryCategory *cat = model->getCategory(objects.get(i));
+ if (cat)
+ {
+ const LLUUID &cat_id = cat->getUUID();
+ // Don't allow recursive pasting
+ if ((cat_id == current_cat_id) ||
+ model->isObjectDescendentOf(current_cat_id, cat_id))
+ {
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+
+}
+
BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
BOOL drop)
{
@@ -1436,8 +1481,8 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
if(!avatar) return FALSE;
- // cannot drag into library
- if(!isAgentInventory())
+ // cannot drag categories into library or COF
+ if(!isAgentInventory() || isCOFFolder())
{
return FALSE;
}
@@ -1456,14 +1501,14 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
const LLUUID& cat_id = inv_cat->getUUID();
// Is the destination the trash?
- LLUUID trash_id;
- trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
BOOL move_is_into_trash = (mUUID == trash_id)
|| model->isObjectDescendentOf(mUUID, trash_id);
BOOL is_movable = (!LLAssetType::lookupIsProtectedCategoryType(inv_cat->getPreferredType()));
LLUUID current_outfit_id = model->findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
- if (move_is_into_current_outfit)
+ BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLAssetType::AT_OUTFIT);
+ if (move_is_into_current_outfit || move_is_into_outfit)
{
// BAP - restrictions?
is_movable = true;
@@ -1533,16 +1578,25 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
}
-
- if (current_outfit_id == mUUID) // if target is current outfit folder we use link
+ // if target is an outfit or current outfit folder we use link
+ if (move_is_into_current_outfit || move_is_into_outfit)
{
- link_inventory_item(
- gAgent.getID(),
- inv_cat->getUUID(),
- mUUID,
- inv_cat->getName(),
- LLAssetType::AT_LINK_FOLDER,
- LLPointer<LLInventoryCallback>(NULL));
+ // BAP - should skip if dup.
+ if (move_is_into_current_outfit)
+ {
+ LLAppearanceManager::wearEnsemble(inv_cat);
+ }
+ else
+ {
+ LLPointer<LLInventoryCallback> cb = NULL;
+ link_inventory_item(
+ gAgent.getID(),
+ inv_cat->getUUID(),
+ mUUID,
+ inv_cat->getName(),
+ LLAssetType::AT_LINK_FOLDER,
+ cb);
+ }
}
else
{
@@ -1856,7 +1910,7 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask)
mContentsCount)
{
gInventory.removeObserver(this);
- wear_inventory_category(category, FALSE, TRUE);
+ LLAppearanceManager::wearInventoryCategory(category, FALSE, TRUE);
delete this;
}
}
@@ -2117,8 +2171,7 @@ BOOL LLFolderBridge::removeItem()
LLInventoryModel* model = getInventoryModel();
if(!model) return FALSE;
- LLUUID trash_id;
- trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
// Look for any gestures and deactivate them
LLInventoryModel::cat_array_t descendent_categories;
@@ -2176,7 +2229,7 @@ void LLFolderBridge::pasteFromClipboard()
void LLFolderBridge::pasteLinkFromClipboard()
{
- LLInventoryModel* model = getInventoryModel();
+ const LLInventoryModel* model = getInventoryModel();
if(model)
{
LLDynamicArray<LLUUID> objects;
@@ -2224,7 +2277,7 @@ void LLFolderBridge::folderOptionsMenu()
if(!model) return;
const LLInventoryCategory* category = model->getCategory(mUUID);
- bool is_default_folder = category &&
+ const bool is_default_folder = category &&
(LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType()));
// calling card related functionality for folders.
@@ -2262,10 +2315,6 @@ void LLFolderBridge::folderOptionsMenu()
}
mItems.push_back(std::string("Take Off Items"));
}
- if (LLAssetType::AT_CURRENT_OUTFIT == category->getPreferredType())
- {
- mItems.push_back(std::string("Replace Outfit"));
- }
hideContextEntries(*mMenu, mItems, disabled_items);
}
@@ -2321,26 +2370,40 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
LLViewerInventoryCategory *cat = getCategory();
- // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694.
- if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat))
- mItems.push_back(std::string("New Folder"));
- mItems.push_back(std::string("New Script"));
- mItems.push_back(std::string("New Note"));
- mItems.push_back(std::string("New Gesture"));
- mItems.push_back(std::string("New Clothes"));
- mItems.push_back(std::string("New Body Parts"));
- mItems.push_back(std::string("Change Type"));
-
- if (cat && LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType()))
+ if (!isCOFFolder() && cat &&
+ LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType()))
+ {
+ // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694.
+ if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat))
+ mItems.push_back(std::string("New Folder"));
+ mItems.push_back(std::string("New Script"));
+ mItems.push_back(std::string("New Note"));
+ mItems.push_back(std::string("New Gesture"));
+ mItems.push_back(std::string("New Clothes"));
+ mItems.push_back(std::string("New Body Parts"));
+ mItems.push_back(std::string("Change Type"));
+
+ LLViewerInventoryCategory *cat = getCategory();
+ if (cat && LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType()))
+ {
+ mDisabledItems.push_back(std::string("Change Type"));
+ }
+
+ getClipboardEntries(false, mItems, mDisabledItems, flags);
+ }
+ else
{
- mDisabledItems.push_back(std::string("Change Type"));
+ // Want some but not all of the items from getClipboardEntries for outfits.
+ if (cat && cat->getPreferredType()==LLAssetType::AT_OUTFIT)
+ {
+ mItems.push_back(std::string("Rename"));
+ mItems.push_back(std::string("Delete"));
+ }
}
-
- getClipboardEntries(false, mItems, mDisabledItems, flags);
//Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06
mCallingCards = mWearables = FALSE;
-
+
LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
if (checkFolderForContentsOfType(model, is_callingcard))
{
@@ -2350,7 +2413,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
LLFindWearables is_wearable;
LLIsType is_object( LLAssetType::AT_OBJECT );
LLIsType is_gesture( LLAssetType::AT_GESTURE );
-
+
if (checkFolderForContentsOfType(model, is_wearable) ||
checkFolderForContentsOfType(model, is_object) ||
checkFolderForContentsOfType(model, is_gesture) )
@@ -2364,7 +2427,10 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
LLInventoryFetchDescendentsObserver::folder_ref_t folders;
LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
- folders.push_back(category->getUUID());
+ if (category)
+ {
+ folders.push_back(category->getUUID());
+ }
fetch->fetchDescendents(folders);
inc_busy_count();
if(fetch->isEverythingComplete())
@@ -2570,7 +2636,7 @@ void LLFolderBridge::modifyOutfit(BOOL append)
// BAP - was:
// wear_inventory_category_on_avatar( cat, append );
- wear_inventory_category( cat, FALSE, append );
+ LLAppearanceManager::wearInventoryCategory( cat, FALSE, append );
}
// helper stuff
@@ -2650,6 +2716,10 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
+ LLUUID current_outfit_id = model->findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
+ BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+ BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLAssetType::AT_OUTFIT);
+
if(is_movable && move_is_into_trash)
{
switch(inv_item->getType())
@@ -2700,6 +2770,25 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
std::string(),
LLPointer<LLInventoryCallback>(NULL));
}
+ else if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ // BAP - should skip if dup.
+ if (move_is_into_current_outfit)
+ {
+ LLAppearanceManager::wearItem(inv_item);
+ }
+ else
+ {
+ LLPointer<LLInventoryCallback> cb = NULL;
+ link_inventory_item(
+ gAgent.getID(),
+ inv_item->getUUID(),
+ mUUID,
+ std::string(),
+ LLAssetType::AT_LINK,
+ cb);
+ }
+ }
else
{
// restamp if the move is into the trash.
@@ -3856,12 +3945,8 @@ void wear_inventory_item_on_avatar( LLInventoryItem* item )
{
lldebugs << "wear_inventory_item_on_avatar( " << item->getName()
<< " )" << llendl;
-
- LLWearableList::instance().getAsset(item->getAssetUUID(),
- item->getName(),
- item->getType(),
- LLWearableBridge::onWearOnAvatarArrived,
- new LLUUID(item->getUUID()));
+
+ LLAppearanceManager::wearItem(item);
}
}
@@ -3880,667 +3965,6 @@ void wear_add_inventory_item_on_avatar( LLInventoryItem* item )
}
}
-
-struct LLFoundData
-{
- LLFoundData(const LLUUID& item_id,
- const LLUUID& asset_id,
- const std::string& name,
- LLAssetType::EType asset_type) :
- mItemID(item_id),
- mAssetID(asset_id),
- mName(name),
- mAssetType(asset_type),
- mWearable( NULL ) {}
-
- LLUUID mItemID;
- LLUUID mAssetID;
- std::string mName;
- LLAssetType::EType mAssetType;
- LLWearable* mWearable;
-};
-
-struct LLWearableHoldingPattern
-{
- LLWearableHoldingPattern() : mResolved(0) {}
- ~LLWearableHoldingPattern()
- {
- for_each(mFoundList.begin(), mFoundList.end(), DeletePointer());
- mFoundList.clear();
- }
- typedef std::list<LLFoundData*> found_list_t;
- found_list_t mFoundList;
- S32 mResolved;
-};
-
-
-class LLOutfitObserver : public LLInventoryFetchObserver
-{
-public:
- LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) :
- mCatID(cat_id),
- mCopyItems(copy_items),
- mAppend(append)
- {}
- ~LLOutfitObserver() {}
- virtual void done(); //public
-
-protected:
- LLUUID mCatID;
- bool mCopyItems;
- bool mAppend;
-};
-
-class LLWearInventoryCategoryCallback : public LLInventoryCallback
-{
-public:
- LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append)
- {
- mCatID = cat_id;
- mAppend = append;
- }
- void fire(const LLUUID& item_id)
- {
- /*
- * Do nothing. We only care about the destructor
- *
- * The reason for this is that this callback is used in a hack where the
- * same callback is given to dozens of items, and the destructor is called
- * after the last item has fired the event and dereferenced it -- if all
- * the events actually fire!
- */
- }
-
-protected:
- ~LLWearInventoryCategoryCallback()
- {
- // Is the destructor called by ordinary dereference, or because the app's shutting down?
- // If the inventory callback manager goes away, we're shutting down, no longer want the callback.
- if( LLInventoryCallbackManager::is_instantiated() )
- {
- wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend);
- }
- else
- {
- llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl;
- }
- }
-
-private:
- LLUUID mCatID;
- bool mAppend;
-};
-
-void LLOutfitObserver::done()
-{
- // We now have an outfit ready to be copied to agent inventory. Do
- // it, and wear that outfit normally.
- if(mCopyItems)
- {
- LLInventoryCategory* cat = gInventory.getCategory(mCatID);
- std::string name;
- if(!cat)
- {
- // should never happen.
- name = "New Outfit";
- }
- else
- {
- name = cat->getName();
- }
- LLViewerInventoryItem* item = NULL;
- item_ref_t::iterator it = mComplete.begin();
- item_ref_t::iterator end = mComplete.end();
- LLUUID pid;
- for(; it < end; ++it)
- {
- item = (LLViewerInventoryItem*)gInventory.getItem(*it);
- if(item)
- {
- if(LLInventoryType::IT_GESTURE == item->getInventoryType())
- {
- pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE);
- }
- else
- {
- pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING);
- }
- break;
- }
- }
- if(pid.isNull())
- {
- pid = gInventory.getRootFolderID();
- }
-
- LLUUID cat_id = gInventory.createNewCategory(
- pid,
- LLAssetType::AT_NONE,
- name);
- mCatID = cat_id;
- LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(mCatID, mAppend);
- it = mComplete.begin();
- for(; it < end; ++it)
- {
- item = (LLViewerInventoryItem*)gInventory.getItem(*it);
- if(item)
- {
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- cat_id,
- std::string(),
- cb);
- }
- }
- }
- else
- {
- // Wear the inventory category.
- wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend);
- }
-}
-
-class LLOutfitFetch : public LLInventoryFetchDescendentsObserver
-{
-public:
- LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {}
- ~LLOutfitFetch() {}
- virtual void done();
-protected:
- bool mCopyItems;
- bool mAppend;
-};
-
-void LLOutfitFetch::done()
-{
- // What we do here is get the complete information on the items in
- // the library, and set up an observer that will wait for that to
- // happen.
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
- gInventory.collectDescendents(mCompleteFolders.front(),
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH);
- S32 count = item_array.count();
- if(!count)
- {
- llwarns << "Nothing fetched in category " << mCompleteFolders.front()
- << llendl;
- dec_busy_count();
- gInventory.removeObserver(this);
- delete this;
- return;
- }
-
- LLOutfitObserver* outfit;
- outfit = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend);
- LLInventoryFetchObserver::item_ref_t ids;
- for(S32 i = 0; i < count; ++i)
- {
- ids.push_back(item_array.get(i)->getUUID());
- }
-
- // clean up, and remove this as an observer since the call to the
- // outfit could notify observers and throw us into an infinite
- // loop.
- dec_busy_count();
- gInventory.removeObserver(this);
- delete this;
-
- // increment busy count and either tell the inventory to check &
- // call done, or add this object to the inventory for observation.
- inc_busy_count();
-
- // do the fetch
- outfit->fetchItems(ids);
- if(outfit->isEverythingComplete())
- {
- // everything is already here - call done.
- outfit->done();
- }
- else
- {
- // it's all on it's way - add an observer, and the inventory
- // will call done for us when everything is here.
- gInventory.addObserver(outfit);
- }
-}
-
-void wear_outfit_by_name(const std::string& name)
-{
- llinfos << "Wearing category " << name << llendl;
- inc_busy_count();
-
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
- LLNameCategoryCollector has_name(name);
- gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- has_name);
- bool copy_items = false;
- LLInventoryCategory* cat = NULL;
- if (cat_array.count() > 0)
- {
- // Just wear the first one that matches
- cat = cat_array.get(0);
- }
- else
- {
- gInventory.collectDescendentsIf(LLUUID::null,
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- has_name);
- if(cat_array.count() > 0)
- {
- cat = cat_array.get(0);
- copy_items = true;
- }
- }
-
- if(cat)
- {
- wear_inventory_category(cat, copy_items, false);
- }
- else
- {
- llwarns << "Couldn't find outfit " <<name<< " in wear_outfit_by_name()"
- << llendl;
- }
-
- dec_busy_count();
-}
-
-void wear_inventory_category(LLInventoryCategory* category, bool copy, bool append)
-{
- if(!category) return;
-
- lldebugs << "wear_inventory_category( " << category->getName()
- << " )" << llendl;
- // What we do here is get the complete information on the items in
- // the inventory, and set up an observer that will wait for that to
- // happen.
- LLOutfitFetch* outfit;
- outfit = new LLOutfitFetch(copy, append);
- LLInventoryFetchDescendentsObserver::folder_ref_t folders;
- folders.push_back(category->getUUID());
- outfit->fetchDescendents(folders);
- inc_busy_count();
- if(outfit->isEverythingComplete())
- {
- // everything is already here - call done.
- outfit->done();
- }
- else
- {
- // it's all on it's way - add an observer, and the inventory
- // will call done for us when everything is here.
- gInventory.addObserver(outfit);
- }
-}
-
-// *NOTE: hack to get from avatar inventory to avatar
-void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL append )
-{
- // Avoid unintentionally overwriting old wearables. We have to do
- // this up front to avoid having to deal with the case of multiple
- // wearables being dirty.
- if(!category) return;
- lldebugs << "wear_inventory_category_on_avatar( " << category->getName()
- << " )" << llendl;
-
- BOOL follow_folder_links = (category->getPreferredType() == LLAssetType::AT_CURRENT_OUTFIT || category->getPreferredType() == LLAssetType::AT_OUTFIT );
- if( gFloaterCustomize )
- {
- gFloaterCustomize->askToSaveIfDirty(boost::bind(wear_inventory_category_on_avatar_step2, _1, category->getUUID(), append, follow_folder_links));
- }
- else
- {
- wear_inventory_category_on_avatar_step2(TRUE, category->getUUID(), append, follow_folder_links );
- }
-}
-
-void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src)
-{
- LLInventoryModel::item_array_t new_dst;
- std::set<LLUUID> mark_inventory;
- std::set<LLUUID> mark_asset;
-
- S32 inventory_dups = 0;
- S32 asset_dups = 0;
-
- for (LLInventoryModel::item_array_t::const_iterator src_pos = src.begin();
- src_pos != src.end();
- ++src_pos)
- {
- LLUUID src_item_id = (*src_pos)->getLinkedUUID();
- mark_inventory.insert(src_item_id);
- LLUUID src_asset_id = (*src_pos)->getAssetUUID();
- mark_asset.insert(src_asset_id);
- }
-
- for (LLInventoryModel::item_array_t::const_iterator dst_pos = dst.begin();
- dst_pos != dst.end();
- ++dst_pos)
- {
- LLUUID dst_item_id = (*dst_pos)->getLinkedUUID();
-
- if (mark_inventory.find(dst_item_id) == mark_inventory.end())
- {
- }
- else
- {
- inventory_dups++;
- }
-
- LLUUID dst_asset_id = (*dst_pos)->getAssetUUID();
-
- if (mark_asset.find(dst_asset_id) == mark_asset.end())
- {
- // Item is not already present in COF.
- new_dst.put(*dst_pos);
- mark_asset.insert(dst_item_id);
- }
- else
- {
- asset_dups++;
- }
- }
- llinfos << "removeDups, original " << dst.count() << " final " << new_dst.count()
- << " inventory dups " << inventory_dups << " asset_dups " << asset_dups << llendl;
-
- dst = new_dst;
-}
-
-void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links )
-{
- // Find all the wearables that are in the category's subtree.
- lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl;
- if(proceed)
- {
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
- LLFindWearables is_wearable;
- gInventory.collectDescendentsIf(category,
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- is_wearable,
- follow_folder_links);
- S32 i;
- S32 wearable_count = item_array.count();
-
- LLInventoryModel::cat_array_t obj_cat_array;
- LLInventoryModel::item_array_t obj_item_array;
- LLIsType is_object( LLAssetType::AT_OBJECT );
- gInventory.collectDescendentsIf(category,
- obj_cat_array,
- obj_item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- is_object,
- follow_folder_links);
- S32 obj_count = obj_item_array.count();
-
- // Find all gestures in this folder
- LLInventoryModel::cat_array_t gest_cat_array;
- LLInventoryModel::item_array_t gest_item_array;
- LLIsType is_gesture( LLAssetType::AT_GESTURE );
- gInventory.collectDescendentsIf(category,
- gest_cat_array,
- gest_item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- is_gesture,
- follow_folder_links);
- S32 gest_count = gest_item_array.count();
-
- if( !wearable_count && !obj_count && !gest_count)
- {
- LLNotifications::instance().add("CouldNotPutOnOutfit");
- return;
- }
-
- const LLUUID &current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
- // Processes that take time should show the busy cursor
- inc_busy_count();
-
- LLInventoryModel::cat_array_t co_cat_array;
- LLInventoryModel::item_array_t co_item_array;
- gInventory.collectDescendents(current_outfit_id, co_cat_array, co_item_array,
- LLInventoryModel::EXCLUDE_TRASH);
- if (append)
- {
- // Remove duplicates and update counts.
- removeDuplicateItems(item_array,co_item_array);
- wearable_count = item_array.count();
-
- removeDuplicateItems(obj_item_array,co_item_array);
- obj_count = obj_item_array.count();
-
- removeDuplicateItems(gest_item_array,co_item_array);
- gest_count = gest_item_array.count();
- }
-
-
- if (wearable_count > 0 || obj_count > 0)
- {
- if (!append)
- {
- // Remove all current outfit folder links if we're now replacing the contents.
- for (i = 0; i < co_item_array.count(); ++i)
- {
- gInventory.purgeObject(co_item_array.get(i)->getUUID());
- }
- }
- }
-
- // Activate all gestures in this folder
- if (gest_count > 0)
- {
- llinfos << "Activating " << gest_count << " gestures" << llendl;
-
- LLGestureManager::instance().activateGestures(gest_item_array);
-
- // Update the inventory item labels to reflect the fact
- // they are active.
- LLViewerInventoryCategory* catp = gInventory.getCategory(category);
- if (catp)
- {
- gInventory.updateCategory(catp);
- gInventory.notifyObservers();
- }
- }
-
- if(wearable_count > 0)
- {
- // Note: can't do normal iteration, because if all the
- // wearables can be resolved immediately, then the
- // callback will be called (and this object deleted)
- // before the final getNextData().
- LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
- LLFoundData* found;
- LLDynamicArray<LLFoundData*> found_container;
- for(i = 0; i < wearable_count; ++i)
- {
- found = new LLFoundData(item_array.get(i)->getUUID(),
- item_array.get(i)->getAssetUUID(),
- item_array.get(i)->getName(),
- item_array.get(i)->getType());
- holder->mFoundList.push_front(found);
- found_container.put(found);
- }
- for(i = 0; i < wearable_count; ++i)
- {
- gAddToOutfit = append;
- found = found_container.get(i);
-
- // Populate the current outfit folder with links to the newly added wearables
- std::string link_name = "WearableLink";
- link_inventory_item(gAgent.getID(), found->mItemID, current_outfit_id, link_name,
- LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));
-
- // Fetch the wearables about to be worn.
- LLWearableList::instance().getAsset(found->mAssetID,
- found->mName,
- found->mAssetType,
- wear_inventory_category_on_avatar_loop,
- (void*)holder);
- }
- }
-
-
- //If not appending and the folder doesn't contain only gestures, take off all attachments.
- if (!append
- && !(wearable_count == 0 && obj_count == 0 && gest_count > 0) )
- {
- LLAgentWearables::userRemoveAllAttachments(NULL);
- }
-
- if( obj_count > 0 )
- {
- // We've found some attachements. Add these.
-
- LLVOAvatar* avatar = gAgent.getAvatarObject();
- if( avatar )
- {
- // Build a compound message to send all the objects that need to be rezzed.
-
- // Limit number of packets to send
- const S32 MAX_PACKETS_TO_SEND = 10;
- const S32 OBJECTS_PER_PACKET = 4;
- const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
- if( obj_count > MAX_OBJECTS_TO_SEND )
- {
- obj_count = MAX_OBJECTS_TO_SEND;
- }
-
- // Create an id to keep the parts of the compound message together
- LLUUID compound_msg_id;
- compound_msg_id.generate();
- LLMessageSystem* msg = gMessageSystem;
-
- for(i = 0; i < obj_count; ++i)
- {
- if( 0 == (i % OBJECTS_PER_PACKET) )
- {
- // Start a new message chunk
- msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_HeaderData);
- msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id );
- msg->addU8Fast(_PREHASH_TotalObjects, obj_count );
- msg->addBOOLFast(_PREHASH_FirstDetachAll, !append );
- }
-
- const LLInventoryItem* item = obj_item_array.get(i).get();
- msg->nextBlockFast(_PREHASH_ObjectData );
- msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
- msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
- msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point
- pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
- msg->addStringFast(_PREHASH_Name, item->getName());
- msg->addStringFast(_PREHASH_Description, item->getDescription());
-
- if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
- {
- // End of message chunk
- msg->sendReliable( gAgent.getRegion()->getHost() );
- }
-
- }
-
- for(i = 0; i < obj_count; ++i)
- {
- const std::string link_name = "AttachmentLink";
- const LLInventoryItem* item = obj_item_array.get(i).get();
- link_inventory_item(gAgent.getID(), item->getLinkedUUID(), current_outfit_id, link_name,
- LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));
- }
- }
- }
-
- // In the particular case that we're switching to a different outfit,
- // create a link to the folder that we wore.
- LLViewerInventoryCategory* catp = gInventory.getCategory(category);
- if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT)
- {
- link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(),
- LLAssetType::AT_LINK_FOLDER, LLPointer<LLInventoryCallback>(NULL));
- }
- }
-}
-
-void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void* data)
-{
- LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
- BOOL append= gAddToOutfit;
-
- if(wearable)
- {
- for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
- iter != holder->mFoundList.end(); ++iter)
- {
- LLFoundData* data = *iter;
- if(wearable->getAssetID() == data->mAssetID)
- {
- data->mWearable = wearable;
- break;
- }
- }
- }
- holder->mResolved += 1;
- if(holder->mResolved >= (S32)holder->mFoundList.size())
- {
- wear_inventory_category_on_avatar_step3(holder, append);
- }
-}
-
-void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append)
-{
- lldebugs << "wear_inventory_category_on_avatar_step3()" << llendl;
- LLInventoryItem::item_array_t items;
- LLDynamicArray< LLWearable* > wearables;
-
- // For each wearable type, find the first instance in the category
- // that we recursed through.
- for( S32 i = 0; i < WT_COUNT; i++ )
- {
- for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
- iter != holder->mFoundList.end(); ++iter)
- {
- LLFoundData* data = *iter;
- LLWearable* wearable = data->mWearable;
- if( wearable && ((S32)wearable->getType() == i) )
- {
- LLViewerInventoryItem* item;
- item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID);
- if( item && (item->getAssetUUID() == wearable->getAssetID()) )
- {
- items.put(item);
- wearables.put(wearable);
- }
- break;
- }
- }
- }
-
- if(wearables.count() > 0)
- {
- gAgentWearables.setWearableOutfit(items, wearables, !append);
- gInventory.notifyObservers();
- }
-
- delete holder;
-
- dec_busy_count();
-}
-
void remove_inventory_category_from_avatar( LLInventoryCategory* category )
{
if(!category) return;
@@ -4945,6 +4369,7 @@ void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userda
}
// static
+// BAP remove the "add" code path once everything is fully COF-ified.
void LLWearableBridge::onWearAddOnAvatarArrived( LLWearable* wearable, void* userdata )
{
LLUUID* item_id = (LLUUID*) userdata;
@@ -5304,15 +4729,15 @@ void LLWearableBridgeAction::wearOnAvatar()
}
//virtual
-void LLWearableBridgeAction::doIt()
+void LLWearableBridgeAction::doIt()
{
- if( isInTrash() )
+ if(isInTrash())
{
LLNotifications::instance().add("CannotWearTrash");
}
else if(isAgentInventory())
{
- if( !gAgentWearables.isWearingItem( mUUID ) )
+ if(!gAgentWearables.isWearingItem(mUUID))
{
wearOnAvatar();
}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 25859b7f73..bc950520aa 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -200,9 +200,8 @@ protected:
BOOL isInTrash() const;
BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash?
- // return true if the item is in agent inventory. if false, it
- // must be lost or in the inventory library.
- BOOL isAgentInventory() const;
+ BOOL isAgentInventory() const; // false if lost or in the inventory library
+ BOOL isCOFFolder() const; // true if COF or descendent of.
virtual BOOL isItemPermissive() const;
static void changeItemParent(LLInventoryModel* model,
LLViewerInventoryItem* item,
@@ -295,6 +294,7 @@ public:
virtual BOOL isItemMovable();
virtual BOOL isUpToDate() const;
virtual BOOL isItemCopyable() const;
+ virtual BOOL isClipboardPasteableAsLink() const;
virtual BOOL copyToClipboard() const;
static void createWearable(LLFolderBridge* bridge, EWearableType type);
@@ -769,8 +769,6 @@ protected:
};
void wear_inventory_item_on_avatar(LLInventoryItem* item);
-void wear_outfit_by_name(const std::string& name);
-void wear_inventory_category(LLInventoryCategory* category, bool copy, bool append);
class LLViewerJointAttachment;
void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment);
@@ -787,4 +785,5 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id,
void teleport_via_landmark(const LLUUID& asset_id);
+
#endif // LL_LLINVENTORYBRIDGE_H
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index 670b1f000b..b803df110b 100644
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -94,6 +94,7 @@ public:
BOOL isModified();
BOOL isModifiedAndClear();
BOOL isSinceLogoff();
+ bool hasFilterString() { return mFilterSubString.size() > 0; }
void clearModified() { mModified = FALSE; mFilterBehavior = FILTER_NONE; }
const std::string getName() const { return mName; }
std::string getFilterText();
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 8062da0dfe..4cbf3e169b 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -187,9 +187,9 @@ LLInventoryModel::~LLInventoryModel()
// This is a convenience function to check if one object has a parent
// chain up to the category specified by UUID.
BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id,
- const LLUUID& cat_id)
+ const LLUUID& cat_id) const
{
- LLInventoryObject* obj = getObject(obj_id);
+ const LLInventoryObject* obj = getObject(obj_id);
while(obj)
{
const LLUUID& parent_id = obj->getParentUUID();
@@ -307,13 +307,13 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id)
// inventory category on the fly if one does not exist.
LLUUID LLInventoryModel::findCategoryUUIDForType(LLAssetType::EType t, bool create_folder)
{
- LLUUID rv = findCatUUID(t);
+ const LLUUID &rv = findCatUUID(t);
if(rv.isNull() && isInventoryUsable() && create_folder)
{
- LLUUID root_id = gInventory.getRootFolderID();
+ const LLUUID &root_id = gInventory.getRootFolderID();
if(root_id.notNull())
{
- rv = createNewCategory(root_id, t, LLStringUtil::null);
+ return createNewCategory(root_id, t, LLStringUtil::null);
}
}
return rv;
@@ -321,9 +321,9 @@ LLUUID LLInventoryModel::findCategoryUUIDForType(LLAssetType::EType t, bool crea
// Internal method which looks for a category with the specified
// preferred type. Returns LLUUID::null if not found.
-LLUUID LLInventoryModel::findCatUUID(LLAssetType::EType preferred_type)
+const LLUUID &LLInventoryModel::findCatUUID(LLAssetType::EType preferred_type) const
{
- LLUUID root_id = gInventory.getRootFolderID();
+ const LLUUID &root_id = gInventory.getRootFolderID();
if(LLAssetType::AT_CATEGORY == preferred_type)
{
return root_id;
@@ -440,7 +440,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
// Start with categories
if(!include_trash)
{
- LLUUID trash_id(findCatUUID(LLAssetType::AT_TRASH));
+ const LLUUID trash_id = findCategoryUUIDForType(LLAssetType::AT_TRASH);
if(trash_id.notNull() && (trash_id == id))
return;
}
@@ -473,8 +473,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
item = item_array->get(i);
if (item->getActualType() == LLAssetType::AT_LINK_FOLDER)
{
- // BAP either getLinkedCategory() should return non-const, or the functor should take const.
- LLViewerInventoryCategory *linked_cat = const_cast<LLViewerInventoryCategory*>(item->getLinkedCategory());
+ LLViewerInventoryCategory *linked_cat = item->getLinkedCategory();
if (linked_cat)
{
if(add(linked_cat,NULL))
@@ -548,10 +547,10 @@ void LLInventoryModel::collectLinkedItems(const LLUUID& id,
// Generates a string containing the path to the item specified by
// item_id.
-void LLInventoryModel::appendPath(const LLUUID& id, std::string& path)
+void LLInventoryModel::appendPath(const LLUUID& id, std::string& path) const
{
std::string temp;
- LLInventoryObject* obj = getObject(id);
+ const LLInventoryObject* obj = getObject(id);
LLUUID parent_id;
if(obj) parent_id = obj->getParentUUID();
std::string forward_slash("/");
@@ -567,7 +566,7 @@ void LLInventoryModel::appendPath(const LLUUID& id, std::string& path)
path.append(temp);
}
-bool LLInventoryModel::isInventoryUsable()
+bool LLInventoryModel::isInventoryUsable() const
{
bool result = false;
if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable)
@@ -1086,7 +1085,7 @@ void LLInventoryModel::removeObserver(LLInventoryObserver* observer)
mObservers.erase(observer);
}
-BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer)
+BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const
{
return mObservers.find(observer) != mObservers.end();
}
@@ -1791,6 +1790,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)
if (item->getIsBrokenLink())
{
llwarns << "Add link item without baseobj present ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl;
+// llassert_always(FALSE); // DO NOT MERGE THIS IN. This is an AVP debugging line. If this line triggers, it means that you just loaded in a broken link. Unless that happens because you actually deleted a baseobj without deleting the link, it's indicative of a serious problem (likely with your inventory) and should be diagnosed.
}
mItemMap[item->getUUID()] = item;
//mInventory[item->getUUID()] = item;
@@ -1817,7 +1817,7 @@ void LLInventoryModel::empty()
//mInventory.clear();
}
-void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update)
+void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
{
LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);
if(cat)
@@ -2177,7 +2177,8 @@ bool LLInventoryModel::loadSkeleton(
update_map_t::const_iterator the_count = child_counts.find(cat->getUUID());
if(the_count != no_child_counts)
{
- cat->setDescendentCount((*the_count).second.mValue);
+ const S32 num_descendents = (*the_count).second.mValue;
+ cat->setDescendentCount(num_descendents);
}
else
{
@@ -2481,7 +2482,7 @@ void LLInventoryModel::buildParentChildMap()
}
}
- LLUUID agent_inv_root_id = gInventory.getRootFolderID();
+ const LLUUID &agent_inv_root_id = gInventory.getRootFolderID();
if (agent_inv_root_id.notNull())
{
cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id);
@@ -3324,7 +3325,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLAssetTy
void LLInventoryModel::removeItem(const LLUUID& item_id)
{
LLViewerInventoryItem* item = getItem(item_id);
- const LLUUID& new_parent = findCategoryUUIDForType(LLAssetType::AT_TRASH);
+ const LLUUID new_parent = findCategoryUUIDForType(LLAssetType::AT_TRASH);
if (item && item->getParentUUID() != new_parent)
{
LLInventoryModel::update_list_t update;
@@ -3342,7 +3343,7 @@ void LLInventoryModel::removeItem(const LLUUID& item_id)
}
}
-LLUUID LLInventoryModel::getRootFolderID() const
+const LLUUID &LLInventoryModel::getRootFolderID() const
{
return mRootFolderID;
}
@@ -3352,7 +3353,7 @@ void LLInventoryModel::setRootFolderID(const LLUUID& val)
mRootFolderID = val;
}
-LLUUID LLInventoryModel::getLibraryRootFolderID() const
+const LLUUID &LLInventoryModel::getLibraryRootFolderID() const
{
return mLibraryRootFolderID;
}
@@ -3362,7 +3363,7 @@ void LLInventoryModel::setLibraryRootFolderID(const LLUUID& val)
mLibraryRootFolderID = val;
}
-LLUUID LLInventoryModel::getLibraryOwnerID() const
+const LLUUID &LLInventoryModel::getLibraryOwnerID() const
{
return mLibraryOwnerID;
}
@@ -3375,13 +3376,13 @@ void LLInventoryModel::setLibraryOwnerID(const LLUUID& val)
//----------------------------------------------------------------------------
// *NOTE: DEBUG functionality
-void LLInventoryModel::dumpInventory()
+void LLInventoryModel::dumpInventory() const
{
llinfos << "\nBegin Inventory Dump\n**********************:" << llendl;
- llinfos << "mCategroy[] contains " << mCategoryMap.size() << " items." << llendl;
- for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
+ llinfos << "mCategory[] contains " << mCategoryMap.size() << " items." << llendl;
+ for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
{
- LLViewerInventoryCategory* cat = cit->second;
+ const LLViewerInventoryCategory* cat = cit->second;
if(cat)
{
llinfos << " " << cat->getUUID() << " '" << cat->getName() << "' "
@@ -3394,9 +3395,9 @@ void LLInventoryModel::dumpInventory()
}
}
llinfos << "mItemMap[] contains " << mItemMap.size() << " items." << llendl;
- for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)
+ for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)
{
- LLViewerInventoryItem* item = iit->second;
+ const LLViewerInventoryItem* item = iit->second;
if(item)
{
llinfos << " " << item->getUUID() << " "
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 2ddc35b9ef..e3e4f6aca0 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -99,12 +99,12 @@ class LLInventoryCollectFunctor;
class LLInventoryModel
{
public:
- typedef enum e_has_children
+ enum EHasChildren
{
CHILDREN_NO,
CHILDREN_YES,
CHILDREN_MAYBE
- }EHasChildren;
+ };
// These are used a lot...
typedef LLDynamicArray<LLPointer<LLViewerInventoryCategory> > cat_array_t;
@@ -133,7 +133,7 @@ public:
// This is a convenience function to check if one object has a
// parent chain up to the category specified by UUID.
- BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id);
+ BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const;
// Get the object by id. Returns NULL if not found.
// * WARNING: use the pointer returned for read operations - do
@@ -197,7 +197,7 @@ public:
// The inventory model usage is sensitive to the initial construction of the
// model.
- bool isInventoryUsable();
+ bool isInventoryUsable() const;
//
// Mutators
@@ -261,7 +261,7 @@ public:
// to remove it.
void addObserver(LLInventoryObserver* observer);
void removeObserver(LLInventoryObserver* observer);
- BOOL containsObserver(LLInventoryObserver* observer);
+ BOOL containsObserver(LLInventoryObserver* observer) const;
//
// Misc Methods
@@ -312,7 +312,7 @@ public:
// Generates a string containing the path to the item specified by
// item_id.
- void appendPath(const LLUUID& id, std::string& path);
+ void appendPath(const LLUUID& id, std::string& path) const;
// message handling functionality
static void registerCallbacks(LLMessageSystem* msg);
@@ -370,7 +370,7 @@ public:
// Call these methods when there are category updates, but call
// them *before* the actual update so the method can do descendent
// accounting correctly.
- void accountForUpdate(const LLCategoryUpdate& update);
+ void accountForUpdate(const LLCategoryUpdate& update) const;
void accountForUpdate(const update_list_t& updates);
void accountForUpdate(const update_map_t& updates);
@@ -404,9 +404,9 @@ public:
// gInventory is a singleton and represents the agent's inventory.
// The "library" is actually the inventory of a special agent,
// usually Alexandria Linden.
- LLUUID getRootFolderID() const;
- LLUUID getLibraryOwnerID() const;
- LLUUID getLibraryRootFolderID() const;
+ const LLUUID &getRootFolderID() const;
+ const LLUUID &getLibraryOwnerID() const;
+ const LLUUID &getLibraryRootFolderID() const;
// These are set during login with data from the server
void setRootFolderID(const LLUUID& id);
@@ -422,9 +422,13 @@ protected:
void addCategory(LLViewerInventoryCategory* category);
void addItem(LLViewerInventoryItem* item);
+ // ! DEPRECRATE ! Remove this and add it into findCategoryUUIDForType,
+ // since that's the only function that uses this. It's too confusing
+ // having both methods.
+ //
// Internal method which looks for a category with the specified
// preferred type. Returns LLUUID::null if not found
- LLUUID findCatUUID(LLAssetType::EType preferred_type);
+ const LLUUID &findCatUUID(LLAssetType::EType preferred_type) const;
// Empty the entire contents
void empty();
@@ -515,7 +519,7 @@ protected:
public:
// *NOTE: DEBUG functionality
- void dumpInventory();
+ void dumpInventory() const;
static bool isBulkFetchProcessingComplete();
static void stopBackgroundFetch(); // stop fetch process
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8fb0f201cb..44e76a0bc1 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -188,6 +188,7 @@
#include "llagentlanguage.h"
#include "llwearable.h"
#include "llinventorybridge.h"
+#include "llappearancemgr.h"
#if LL_WINDOWS
#include "llwindebug.h"
@@ -3345,10 +3346,10 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
}
else
{
- wear_outfit_by_name(outfit_folder_name);
+ LLAppearanceManager::wearOutfitByName(outfit_folder_name);
}
- wear_outfit_by_name(gestures);
- wear_outfit_by_name(COMMON_GESTURES_FOLDER);
+ LLAppearanceManager::wearOutfitByName(gestures);
+ LLAppearanceManager::wearOutfitByName(COMMON_GESTURES_FOLDER);
// This is really misnamed -- it means we have started loading
// an outfit/shape that will give the avatar a gender eventually. JC
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index b35208cd03..08040cfaa5 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -73,6 +73,7 @@
#include "llimview.h"
#include "llrootview.h"
#include "llagentui.h"
+#include "llappearancemgr.h"
// MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
// or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
@@ -2508,7 +2509,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
if(drop)
{
BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
- wear_inventory_category(category, false, append);
+ LLAppearanceManager::wearInventoryCategory(category, false, append);
}
return ACCEPT_YES_MULTI;
}
@@ -2516,7 +2517,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
{
if(drop)
{
- wear_inventory_category(category, true, false);
+ LLAppearanceManager::wearInventoryCategory(category, true, false);
}
return ACCEPT_YES_MULTI;
}
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index ec20af46a1..f3557bb8f7 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -53,6 +53,7 @@
#include "llpreviewgesture.h"
#include "llviewerwindow.h"
#include "lltrans.h"
+#include "llappearancemgr.h"
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
@@ -760,6 +761,11 @@ void WearOnAvatarCallback::fire(const LLUUID& inv_item)
}
}
+void ModifiedCOFCallback::fire(const LLUUID& inv_item)
+{
+ LLAppearanceManager::instance().updateAppearanceFromCOF();
+}
+
RezAttachmentCallback::RezAttachmentCallback(LLViewerJointAttachment *attachmentp)
{
mAttach = attachmentp;
@@ -874,6 +880,27 @@ void link_inventory_item(
const LLAssetType::EType asset_type,
LLPointer<LLInventoryCallback> cb)
{
+ const LLInventoryObject *baseobj = gInventory.getObject(item_id);
+ if (!baseobj)
+ {
+ llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl;
+ return;
+ }
+ if (baseobj && baseobj->getIsLinkType())
+ {
+ llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl;
+ return;
+ }
+
+ if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType()))
+ {
+ // Fail if item can be found but is of a type that can't be linked.
+ // Arguably should fail if the item can't be found too, but that could
+ // be a larger behavioral change.
+ llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl;
+ return;
+ }
+
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_LinkInventoryItem);
msg->nextBlockFast(_PREHASH_AgentData);
@@ -1291,21 +1318,26 @@ bool LLViewerInventoryItem::getIsBrokenLink() const
return LLAssetType::lookupIsLinkType(getType());
}
-const LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const
+LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const
{
if (mType == LLAssetType::AT_LINK)
{
- const LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
+ LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID);
+ if (linked_item && linked_item->getIsLinkType())
+ {
+ llwarns << "Warning: Accessing link to link" << llendl;
+ return NULL;
+ }
return linked_item;
}
return NULL;
}
-const LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const
+LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const
{
if (mType == LLAssetType::AT_LINK_FOLDER)
{
- const LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID);
+ LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID);
return linked_category;
}
return NULL;
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index c4ff30bbfc..631f9ac48b 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -149,8 +149,8 @@ public:
LLTransactionID getTransactionID() const { return mTransactionID; }
bool getIsBrokenLink() const; // true if the baseitem this points to doesn't exist in memory.
- const LLViewerInventoryItem *getLinkedItem() const;
- const LLViewerInventoryCategory *getLinkedCategory() const;
+ LLViewerInventoryItem *getLinkedItem() const;
+ LLViewerInventoryCategory *getLinkedCategory() const;
// callback
void onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name);
@@ -234,6 +234,11 @@ class WearOnAvatarCallback : public LLInventoryCallback
void fire(const LLUUID& inv_item);
};
+class ModifiedCOFCallback : public LLInventoryCallback
+{
+ void fire(const LLUUID& inv_item);
+};
+
class LLViewerJointAttachment;
class RezAttachmentCallback : public LLInventoryCallback
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 338bb7ad7c..ac3defef01 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -212,6 +212,7 @@
#include "llfloaternotificationsconsole.h"
#include "lltexlayer.h"
+#include "llappearancemgr.h"
using namespace LLVOAvatarDefines;
@@ -6375,13 +6376,13 @@ void handle_selected_texture_info(void*)
void handle_test_male(void*)
{
- wear_outfit_by_name("Male Shape & Outfit");
+ LLAppearanceManager::wearOutfitByName("Male Shape & Outfit");
//gGestureList.requestResetFromServer( TRUE );
}
void handle_test_female(void*)
{
- wear_outfit_by_name("Female Shape & Outfit");
+ LLAppearanceManager::wearOutfitByName("Female Shape & Outfit");
//gGestureList.requestResetFromServer( FALSE );
}