diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llcommon/llassettype.cpp | 26 | ||||
-rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/llagentwearables.cpp | 138 | ||||
-rw-r--r-- | indra/newview/llagentwearables.h | 1 | ||||
-rw-r--r-- | indra/newview/llappearancemgr.cpp | 793 | ||||
-rw-r--r-- | indra/newview/llappearancemgr.h | 70 | ||||
-rw-r--r-- | indra/newview/llfolderviewitem.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llinventorybridge.cpp | 879 | ||||
-rw-r--r-- | indra/newview/llinventorybridge.h | 9 | ||||
-rw-r--r-- | indra/newview/llinventoryfilter.h | 1 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 55 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.h | 28 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 7 | ||||
-rw-r--r-- | indra/newview/lltooldraganddrop.cpp | 5 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.cpp | 40 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.h | 9 | ||||
-rw-r--r-- | indra/newview/llviewermenu.cpp | 5 |
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 ¤t_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 ¤t_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 ¤t_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 ); } |