From 7e74e18548d9b508e3d4c3233044302742942eba Mon Sep 17 00:00:00 2001 From: "Eric M. Tulla (BigPapi)" Date: Wed, 11 Nov 2009 20:27:29 -0500 Subject: Fix for EXT-2244 - Auto fill the My Outfits folder from library/clothing if empty -Reviewed by Seraph --- indra/newview/llagentwearables.cpp | 150 ++++++++++++++++++++++++++++++++++++- indra/newview/llagentwearables.h | 6 +- indra/newview/llinventorymodel.cpp | 10 +-- indra/newview/llinventorymodel.h | 11 ++- 4 files changed, 162 insertions(+), 15 deletions(-) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 3fc1055acd..1b1c65640f 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -84,6 +84,26 @@ protected: void processWearablesMessage(); }; +class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver +{ +public: + enum ELibraryOutfitFetchStep { + LOFS_FOLDER = 0, + LOFS_OUTFITS, + LOFS_CONTENTS + }; + LLLibraryOutfitsFetch() : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false) {} + ~LLLibraryOutfitsFetch() {} + virtual void done(); +protected: + void folderDone(void); + void outfitsDone(void); + void contentsDone(void); + enum ELibraryOutfitFetchStep mCurrFetchStep; + std::vector< std::pair< LLUUID, std::string > > mOutfits; + bool mOutfitsPopulated; +}; + LLAgentWearables gAgentWearables; BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; @@ -904,6 +924,8 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs // will call done for us when everything is here. gInventory.addObserver(outfit); } + + gAgentWearables.populateMyOutfitsFolder(); } } @@ -2003,18 +2025,142 @@ void LLAgentWearables::updateServer() gAgent.sendAgentSetAppearance(); } +void LLAgentWearables::populateMyOutfitsFolder(void) +{ + LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(); + + // 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. + LLInventoryFetchDescendentsObserver::folder_ref_t folders; + const LLUUID my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + + folders.push_back(my_outfits_id); + outfits->fetchDescendents(folders); + if(outfits->isEverythingComplete()) + { + // everything is already here - call done. + outfits->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(outfits); + } +} + +void LLLibraryOutfitsFetch::done() +{ + switch (mCurrFetchStep){ + case LOFS_FOLDER: + mCurrFetchStep = LOFS_OUTFITS; + folderDone(); + break; + case LOFS_OUTFITS: + mCurrFetchStep = LOFS_CONTENTS; + outfitsDone(); + break; + case LOFS_CONTENTS: + // No longer need this observer hanging around. + gInventory.removeObserver(this); + contentsDone(); + break; + default: + gInventory.removeObserver(this); + delete this; + return; + } + if (mOutfitsPopulated) + { + delete this; + } +} + +void LLLibraryOutfitsFetch::folderDone(void) +{ + // Early out if we already have items in My Outfits. + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + gInventory.collectDescendents(mCompleteFolders.front(), cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + if (cat_array.count() > 0 || wearable_array.count() > 0) + { + mOutfitsPopulated = true; + gInventory.removeObserver(this); + return; + } + + // Get the UUID of the library's clothing folder + const LLUUID library_clothing_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true); + + mCompleteFolders.clear(); + + // 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. + LLInventoryFetchDescendentsObserver::folder_ref_t folders; + folders.push_back(library_clothing_id); + fetchDescendents(folders); + if(isEverythingComplete()) + { + // everything is already here - call done. + outfitsDone(); + } +} + +void LLLibraryOutfitsFetch::outfitsDone(void) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + gInventory.collectDescendents(mCompleteFolders.front(), cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + LLInventoryFetchDescendentsObserver::folder_ref_t folders; + for(S32 i = 0; i < cat_array.count(); ++i) + { + if (cat_array.get(i)->getName() != "More Outfits" && cat_array.get(i)->getName() != "Ruth"){ + folders.push_back(cat_array.get(i)->getUUID()); + mOutfits.push_back( std::make_pair(cat_array.get(i)->getUUID(), cat_array.get(i)->getName() )); + } + } + mCompleteFolders.clear(); + fetchDescendents(folders); + if(isEverythingComplete()) + { + // everything is already here - call done. + contentsDone(); + } +} + +void LLLibraryOutfitsFetch::contentsDone(void) +{ + for(S32 i = 0; i < mOutfits.size(); ++i) + { + // First, make a folder in the My Outfits directory. + const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + LLUUID folder_id = gInventory.createNewCategory(parent_id, + LLFolderType::FT_OUTFIT, + mOutfits[i].second); + + LLAppearanceManager::shallowCopyCategory(mOutfits[i].first, folder_id, NULL); + gInventory.notifyObservers(); + } + mOutfitsPopulated = true; +} + void LLInitialWearablesFetch::done() { // 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, wearable_array, LLInventoryModel::EXCLUDE_TRASH, is_wearable); - + LLAppearanceManager::setAttachmentInvLinkEnable(true); if (wearable_array.count() > 0) { diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 317f4a7e4f..9b13cb842c 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -169,9 +169,11 @@ public: const LLDynamicArray& attachments_to_include, BOOL rename_clothing); - // Note: wearables_to_include should be a list of EWearableType types - // attachments_to_include should be a list of attachment points LLUUID makeNewOutfitLinks(const std::string& new_folder_name); + + // Should only be called if we *know* we've never done so before, since users may + // not want the Library outfits to stay in their quick outfit selector and can delete them. + void populateMyOutfitsFolder(void); private: void makeNewOutfitDone(S32 type, U32 index); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 4b7e364cf9..cc7a1ae14e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -321,10 +321,10 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id) // specifies 'type' as what it defaults to containing. The category is // not necessarily only for that type. *NOTE: This will create a new // inventory category on the fly if one does not exist. -const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType t, bool create_folder) +const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType t, bool create_folder, bool find_in_library) { - const LLUUID &rv = findCatUUID(t); - if(rv.isNull() && isInventoryUsable() && create_folder) + const LLUUID &rv = findCatUUID(t, find_in_library); + if(rv.isNull() && isInventoryUsable() && (create_folder && !find_in_library)) { const LLUUID &root_id = gInventory.getRootFolderID(); if(root_id.notNull()) @@ -337,9 +337,9 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType t, bo // Internal method which looks for a category with the specified // preferred type. Returns LLUUID::null if not found. -const LLUUID &LLInventoryModel::findCatUUID(LLFolderType::EType preferred_type) const +const LLUUID &LLInventoryModel::findCatUUID(LLFolderType::EType preferred_type, bool find_in_library) const { - const LLUUID &root_id = gInventory.getRootFolderID(); + const LLUUID &root_id = (find_in_library) ? gInventory.getLibraryRootFolderID() : gInventory.getRootFolderID(); if(LLFolderType::FT_CATEGORY == preferred_type) { return root_id; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index faf026887a..b33237f466 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -275,13 +275,12 @@ public: // findCategoryUUIDForType() returns the uuid of the category that // specifies 'type' as what it defaults to containing. The - // category is not necessarily only for that type. *NOTE: This - // will create a new inventory category on the fly if one does not - // exist. - + // category is not necessarily only for that type. *NOTE: If create_folder is true, this + // will create a new inventory category on the fly if one does not exist. *NOTE: if find_in_library is + // true it will search in the user's library folder instead of "My Inventory" // SDK: Added flag to specify whether the folder should be created if not found. This fixes the horrible // multiple trash can bug. - const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder = true); + const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder = true, bool find_in_library = false); // Call this method when it's time to update everyone on a new // state, by default, the inventory model will not update @@ -432,7 +431,7 @@ protected: // // Internal method which looks for a category with the specified // preferred type. Returns LLUUID::null if not found - const LLUUID &findCatUUID(LLFolderType::EType preferred_type) const; + const LLUUID &findCatUUID(LLFolderType::EType preferred_type, bool find_in_library = false) const; // Empty the entire contents void empty(); -- cgit v1.2.3