summaryrefslogtreecommitdiff
path: root/indra/newview/llappearancemgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llappearancemgr.cpp')
-rw-r--r--indra/newview/llappearancemgr.cpp793
1 files changed, 793 insertions, 0 deletions
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
new file mode 100644
index 0000000000..6c234f23fe
--- /dev/null
+++ b/indra/newview/llappearancemgr.cpp
@@ -0,0 +1,793 @@
+/**
+ * @file llappearancemgr.cpp
+ * @brief Manager for initiating appearance changes on the viewer
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappearancemgr.h"
+#include "llinventorymodel.h"
+#include "llnotifications.h"
+#include "llgesturemgr.h"
+#include "llinventorybridge.h"
+#include "llwearablelist.h"
+#include "llagentwearables.h"
+#include "llagent.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
+#include "llviewerregion.h"
+#include "llfloatercustomize.h"
+
+class LLWearInventoryCategoryCallback : public LLInventoryCallback
+{
+public:
+ LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append)
+ {
+ mCatID = cat_id;
+ mAppend = append;
+ }
+ void fire(const LLUUID& item_id)
+ {
+ /*
+ * Do nothing. We only care about the destructor
+ *
+ * The reason for this is that this callback is used in a hack where the
+ * same callback is given to dozens of items, and the destructor is called
+ * after the last item has fired the event and dereferenced it -- if all
+ * the events actually fire!
+ */
+ }
+
+protected:
+ ~LLWearInventoryCategoryCallback()
+ {
+ // Is the destructor called by ordinary dereference, or because the app's shutting down?
+ // If the inventory callback manager goes away, we're shutting down, no longer want the callback.
+ if( LLInventoryCallbackManager::is_instantiated() )
+ {
+ LLAppearanceManager::wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
+ }
+ else
+ {
+ llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl;
+ }
+ }
+
+private:
+ LLUUID mCatID;
+ bool mAppend;
+};
+
+class LLOutfitObserver : public LLInventoryFetchObserver
+{
+public:
+ LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) :
+ mCatID(cat_id),
+ mCopyItems(copy_items),
+ mAppend(append)
+ {}
+ ~LLOutfitObserver() {}
+ virtual void done(); //public
+
+protected:
+ LLUUID mCatID;
+ bool mCopyItems;
+ bool mAppend;
+};
+
+void LLOutfitObserver::done()
+{
+ // We now have an outfit ready to be copied to agent inventory. Do
+ // it, and wear that outfit normally.
+ if(mCopyItems)
+ {
+ LLInventoryCategory* cat = gInventory.getCategory(mCatID);
+ std::string name;
+ if(!cat)
+ {
+ // should never happen.
+ name = "New Outfit";
+ }
+ else
+ {
+ name = cat->getName();
+ }
+ LLViewerInventoryItem* item = NULL;
+ item_ref_t::iterator it = mComplete.begin();
+ item_ref_t::iterator end = mComplete.end();
+ LLUUID pid;
+ for(; it < end; ++it)
+ {
+ item = (LLViewerInventoryItem*)gInventory.getItem(*it);
+ if(item)
+ {
+ if(LLInventoryType::IT_GESTURE == item->getInventoryType())
+ {
+ pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE);
+ }
+ else
+ {
+ pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING);
+ }
+ break;
+ }
+ }
+ if(pid.isNull())
+ {
+ pid = gInventory.getRootFolderID();
+ }
+
+ LLUUID cat_id = gInventory.createNewCategory(
+ pid,
+ LLAssetType::AT_NONE,
+ name);
+ mCatID = cat_id;
+ LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(mCatID, mAppend);
+ it = mComplete.begin();
+ for(; it < end; ++it)
+ {
+ item = (LLViewerInventoryItem*)gInventory.getItem(*it);
+ if(item)
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ cat_id,
+ std::string(),
+ cb);
+ }
+ }
+ }
+ else
+ {
+ // Wear the inventory category.
+ LLAppearanceManager::wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
+ }
+}
+
+class LLOutfitFetch : public LLInventoryFetchDescendentsObserver
+{
+public:
+ LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {}
+ ~LLOutfitFetch() {}
+ virtual void done();
+protected:
+ bool mCopyItems;
+ bool mAppend;
+};
+
+void LLOutfitFetch::done()
+{
+ // What we do here is get the complete information on the items in
+ // the library, and set up an observer that will wait for that to
+ // happen.
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectDescendents(mCompleteFolders.front(),
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH);
+ S32 count = item_array.count();
+ if(!count)
+ {
+ llwarns << "Nothing fetched in category " << mCompleteFolders.front()
+ << llendl;
+ //dec_busy_count();
+ gInventory.removeObserver(this);
+ delete this;
+ return;
+ }
+
+ LLOutfitObserver* outfit_observer = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend);
+ LLInventoryFetchObserver::item_ref_t ids;
+ for(S32 i = 0; i < count; ++i)
+ {
+ ids.push_back(item_array.get(i)->getUUID());
+ }
+
+ // clean up, and remove this as an observer since the call to the
+ // outfit could notify observers and throw us into an infinite
+ // loop.
+ //dec_busy_count();
+ gInventory.removeObserver(this);
+ delete this;
+
+ // increment busy count and either tell the inventory to check &
+ // call done, or add this object to the inventory for observation.
+ //inc_busy_count();
+
+ // do the fetch
+ outfit_observer->fetchItems(ids);
+ if(outfit_observer->isEverythingComplete())
+ {
+ // everything is already here - call done.
+ outfit_observer->done();
+ }
+ else
+ {
+ // it's all on it's way - add an observer, and the inventory
+ // will call done for us when everything is here.
+ gInventory.addObserver(outfit_observer);
+ }
+}
+
+class LLUpdateAppearanceOnCount: public LLInventoryCallback
+{
+public:
+ LLUpdateAppearanceOnCount(S32 count):
+ mCount(count)
+ {
+ }
+
+ virtual ~LLUpdateAppearanceOnCount()
+ {
+ }
+
+ /* virtual */ void fire(const LLUUID& inv_item)
+ {
+ mCount--;
+ if (mCount==0)
+ {
+ done();
+ }
+ }
+
+ void done()
+ {
+ LLAppearanceManager::updateAppearanceFromCOF();
+ }
+private:
+ S32 mCount;
+};
+
+struct LLFoundData
+{
+ LLFoundData(const LLUUID& item_id,
+ const LLUUID& asset_id,
+ const std::string& name,
+ LLAssetType::EType asset_type) :
+ mItemID(item_id),
+ mAssetID(asset_id),
+ mName(name),
+ mAssetType(asset_type),
+ mWearable( NULL ) {}
+
+ LLUUID mItemID;
+ LLUUID mAssetID;
+ std::string mName;
+ LLAssetType::EType mAssetType;
+ LLWearable* mWearable;
+};
+
+
+struct LLWearableHoldingPattern
+{
+ LLWearableHoldingPattern() : mResolved(0) {}
+ ~LLWearableHoldingPattern()
+ {
+ for_each(mFoundList.begin(), mFoundList.end(), DeletePointer());
+ mFoundList.clear();
+ }
+ typedef std::list<LLFoundData*> found_list_t;
+ found_list_t mFoundList;
+ S32 mResolved;
+ bool append;
+};
+
+
+void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src)
+{
+ LLInventoryModel::item_array_t new_dst;
+ std::set<LLUUID> mark_inventory;
+ std::set<LLUUID> mark_asset;
+
+ S32 inventory_dups = 0;
+ S32 asset_dups = 0;
+
+ for (LLInventoryModel::item_array_t::const_iterator src_pos = src.begin();
+ src_pos != src.end();
+ ++src_pos)
+ {
+ LLUUID src_item_id = (*src_pos)->getLinkedUUID();
+ mark_inventory.insert(src_item_id);
+ LLUUID src_asset_id = (*src_pos)->getAssetUUID();
+ mark_asset.insert(src_asset_id);
+ }
+
+ for (LLInventoryModel::item_array_t::const_iterator dst_pos = dst.begin();
+ dst_pos != dst.end();
+ ++dst_pos)
+ {
+ LLUUID dst_item_id = (*dst_pos)->getLinkedUUID();
+
+ if (mark_inventory.find(dst_item_id) == mark_inventory.end())
+ {
+ }
+ else
+ {
+ inventory_dups++;
+ }
+
+ LLUUID dst_asset_id = (*dst_pos)->getAssetUUID();
+
+ if (mark_asset.find(dst_asset_id) == mark_asset.end())
+ {
+ // Item is not already present in COF.
+ new_dst.put(*dst_pos);
+ mark_asset.insert(dst_item_id);
+ }
+ else
+ {
+ asset_dups++;
+ }
+ }
+ llinfos << "removeDups, original " << dst.count() << " final " << new_dst.count()
+ << " inventory dups " << inventory_dups << " asset_dups " << asset_dups << llendl;
+
+ dst = new_dst;
+}
+
+
+/* static */ LLUUID LLAppearanceManager::getCOF()
+{
+ return gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
+}
+
+// Update appearance from outfit folder.
+/* static */ void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, bool append, bool follow_folder_links)
+{
+ if (!proceed)
+ return;
+
+ updateCOFFromOutfit(category, append, follow_folder_links);
+}
+
+// Update COF contents from outfit folder.
+/* static */ void LLAppearanceManager::updateCOFFromOutfit(const LLUUID& category, bool append, bool follow_folder_links)
+{
+ // BAP consolidate into one "get all 3 types of descendents" function, use both places.
+ LLInventoryModel::item_array_t wear_items;
+ LLInventoryModel::item_array_t obj_items;
+ LLInventoryModel::item_array_t gest_items;
+ getUserDescendents(category, wear_items, obj_items, gest_items, follow_folder_links);
+
+ // Find all the wearables that are in the category's subtree.
+ lldebugs << "updateCOFFromOutfit()" << llendl;
+ if( !wear_items.count() && !obj_items.count() && !gest_items.count())
+ {
+ LLNotifications::instance().add("CouldNotPutOnOutfit");
+ return;
+ }
+
+ const LLUUID &current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
+ // Processes that take time should show the busy cursor
+ //inc_busy_count();
+
+ LLInventoryModel::cat_array_t cof_cats;
+ LLInventoryModel::item_array_t cof_items;
+ gInventory.collectDescendents(current_outfit_id, cof_cats, cof_items,
+ LLInventoryModel::EXCLUDE_TRASH);
+ if (append)
+ {
+ // Remove duplicates
+ removeDuplicateItems(wear_items, cof_items);
+ removeDuplicateItems(obj_items, cof_items);
+ removeDuplicateItems(gest_items, cof_items);
+ }
+
+
+ if (wear_items.count() > 0 || obj_items.count() > 0)
+ {
+ if (!append)
+ {
+ // Remove all current outfit folder links if we're now replacing the contents.
+ for (S32 i = 0; i < cof_items.count(); ++i)
+ {
+ gInventory.purgeObject(cof_items.get(i)->getUUID());
+ }
+ }
+ }
+
+ // BAP should we just link all contents, rather than restricting to these 3 types?
+
+ S32 total_links = gest_items.count() + wear_items.count() + obj_items.count();
+ LLPointer<LLUpdateAppearanceOnCount> link_waiter = new LLUpdateAppearanceOnCount(total_links);
+
+ // Link all gestures in this folder
+ if (gest_items.count() > 0)
+ {
+ llinfos << "Linking " << gest_items.count() << " gestures" << llendl;
+ for (S32 i = 0; i < gest_items.count(); ++i)
+ {
+ const LLInventoryItem* gest_item = gest_items.get(i).get();
+ link_inventory_item(gAgent.getID(), gest_item->getLinkedUUID(), current_outfit_id,
+ gest_item->getName(),
+ LLAssetType::AT_LINK, link_waiter);
+ }
+ }
+
+ // Link all wearables
+ if(wear_items.count() > 0)
+ {
+ llinfos << "Linking " << wear_items.count() << " wearables" << llendl;
+ for(S32 i = 0; i < wear_items.count(); ++i)
+ {
+ // Populate the current outfit folder with links to the newly added wearables
+ const LLInventoryItem* wear_item = wear_items.get(i).get();
+ link_inventory_item(gAgent.getID(),
+ wear_item->getLinkedUUID(), // If this item is a link, then we'll use the linked item's UUID.
+ current_outfit_id,
+ wear_item->getName(),
+ LLAssetType::AT_LINK,
+ link_waiter);
+ }
+ }
+
+ // Link all attachments.
+ if( obj_items.count() > 0 )
+ {
+ llinfos << "Linking " << obj_items.count() << " attachments" << llendl;
+ LLVOAvatar* avatar = gAgent.getAvatarObject();
+ if( avatar )
+ {
+ for(S32 i = 0; i < obj_items.count(); ++i)
+ {
+ const LLInventoryItem* obj_item = obj_items.get(i).get();
+ link_inventory_item(gAgent.getID(),
+ obj_item->getLinkedUUID(), // If this item is a link, then we'll use the linked item's UUID.
+ current_outfit_id,
+ obj_item->getName(),
+ LLAssetType::AT_LINK, link_waiter);
+ }
+ }
+ }
+
+ // In the particular case that we're switching to a different outfit,
+ // create a link to the folder that we wore.
+ LLViewerInventoryCategory* catp = gInventory.getCategory(category);
+ if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT)
+ {
+ link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(),
+ LLAssetType::AT_LINK_FOLDER, LLPointer<LLInventoryCallback>(NULL));
+ }
+}
+
+/* static */
+void LLAppearanceManager::onWearableAssetFetch(LLWearable* wearable, void* data)
+{
+ LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
+ bool append = holder->append;
+
+ if(wearable)
+ {
+ for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
+ iter != holder->mFoundList.end(); ++iter)
+ {
+ LLFoundData* data = *iter;
+ if(wearable->getAssetID() == data->mAssetID)
+ {
+ data->mWearable = wearable;
+ break;
+ }
+ }
+ }
+ holder->mResolved += 1;
+ if(holder->mResolved >= (S32)holder->mFoundList.size())
+ {
+ LLAppearanceManager::updateAgentWearables(holder, append);
+ }
+}
+
+/* static */
+void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder, bool append)
+{
+ lldebugs << "updateAgentWearables()" << llendl;
+ LLInventoryItem::item_array_t items;
+ LLDynamicArray< LLWearable* > wearables;
+
+ // For each wearable type, find the first instance in the category
+ // that we recursed through.
+ for( S32 i = 0; i < WT_COUNT; i++ )
+ {
+ for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
+ iter != holder->mFoundList.end(); ++iter)
+ {
+ LLFoundData* data = *iter;
+ LLWearable* wearable = data->mWearable;
+ if( wearable && ((S32)wearable->getType() == i) )
+ {
+ LLViewerInventoryItem* item;
+ item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID);
+ if( item && (item->getAssetUUID() == wearable->getAssetID()) )
+ {
+ items.put(item);
+ wearables.put(wearable);
+ }
+ break;
+ }
+ }
+ }
+
+ if(wearables.count() > 0)
+ {
+ gAgentWearables.setWearableOutfit(items, wearables, !append);
+ gInventory.notifyObservers();
+ }
+
+ delete holder;
+
+// dec_busy_count();
+}
+
+/* static */ void LLAppearanceManager::updateAppearanceFromCOF()
+{
+ bool follow_folder_links = true;
+ LLUUID current_outfit_id = getCOF();
+
+ // Find all the wearables that are in the COF's subtree.
+ lldebugs << "LLAppearanceManager::updateFromCOF()" << llendl;
+ LLInventoryModel::item_array_t wear_items;
+ LLInventoryModel::item_array_t obj_items;
+ LLInventoryModel::item_array_t gest_items;
+ getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links);
+
+ if( !wear_items.count() && !obj_items.count() && !gest_items.count())
+ {
+ LLNotifications::instance().add("CouldNotPutOnOutfit");
+ return;
+ }
+
+ // Processes that take time should show the busy cursor
+ //inc_busy_count(); // BAP this is currently a no-op in llinventorybridge.cpp - do we need it?
+
+ // Activate all gestures in this folder
+ if (gest_items.count() > 0)
+ {
+ llinfos << "Activating " << gest_items.count() << " gestures" << llendl;
+
+ LLGestureManager::instance().activateGestures(gest_items);
+
+ // Update the inventory item labels to reflect the fact
+ // they are active.
+ LLViewerInventoryCategory* catp = gInventory.getCategory(current_outfit_id);
+ if (catp)
+ {
+ gInventory.updateCategory(catp);
+ gInventory.notifyObservers();
+ }
+ }
+
+ if(wear_items.count() > 0)
+ {
+ // Note: can't do normal iteration, because if all the
+ // wearables can be resolved immediately, then the
+ // callback will be called (and this object deleted)
+ // before the final getNextData().
+ LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
+ LLFoundData* found;
+ LLDynamicArray<LLFoundData*> found_container;
+ for(S32 i = 0; i < wear_items.count(); ++i)
+ {
+ found = new LLFoundData(wear_items.get(i)->getUUID(),
+ wear_items.get(i)->getAssetUUID(),
+ wear_items.get(i)->getName(),
+ wear_items.get(i)->getType());
+ holder->mFoundList.push_front(found);
+ found_container.put(found);
+ }
+ for(S32 i = 0; i < wear_items.count(); ++i)
+ {
+ holder->append = false;
+ found = found_container.get(i);
+
+ // Fetch the wearables about to be worn.
+ LLWearableList::instance().getAsset(found->mAssetID,
+ found->mName,
+ found->mAssetType,
+ LLAppearanceManager::onWearableAssetFetch,
+ (void*)holder);
+ }
+ }
+
+
+ //If the folder doesn't contain only gestures, take off all attachments.
+ if (!(wear_items.count() == 0 && obj_items.count() == 0 && gest_items.count() > 0) )
+ {
+ LLAgentWearables::userRemoveAllAttachments(NULL);
+ }
+
+ if( obj_items.count() > 0 )
+ {
+ // We've found some attachments. Add these.
+ LLVOAvatar* avatar = gAgent.getAvatarObject();
+ if( avatar )
+ {
+ LLAgentWearables::userAttachMultipleAttachments(obj_items);
+ }
+ }
+}
+
+/* static */ void LLAppearanceManager::getUserDescendents(const LLUUID& category,
+ LLInventoryModel::item_array_t& wear_items,
+ LLInventoryModel::item_array_t& obj_items,
+ LLInventoryModel::item_array_t& gest_items,
+ bool follow_folder_links)
+{
+ LLInventoryModel::cat_array_t wear_cats;
+ LLFindWearables is_wearable;
+ gInventory.collectDescendentsIf(category,
+ wear_cats,
+ wear_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_wearable,
+ follow_folder_links);
+
+ LLInventoryModel::cat_array_t obj_cats;
+ LLIsType is_object( LLAssetType::AT_OBJECT );
+ gInventory.collectDescendentsIf(category,
+ obj_cats,
+ obj_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_object,
+ follow_folder_links);
+
+ // Find all gestures in this folder
+ LLInventoryModel::cat_array_t gest_cats;
+ LLIsType is_gesture( LLAssetType::AT_GESTURE );
+ gInventory.collectDescendentsIf(category,
+ gest_cats,
+ gest_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_gesture,
+ follow_folder_links);
+}
+
+void LLAppearanceManager::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
+{
+ if(!category) return;
+
+ lldebugs << "wearInventoryCategory( " << category->getName()
+ << " )" << llendl;
+ // What we do here is get the complete information on the items in
+ // the inventory, and set up an observer that will wait for that to
+ // happen.
+ LLOutfitFetch* outfit_fetcher = new LLOutfitFetch(copy, append);
+ LLInventoryFetchDescendentsObserver::folder_ref_t folders;
+ folders.push_back(category->getUUID());
+ outfit_fetcher->fetchDescendents(folders);
+ //inc_busy_count();
+ if(outfit_fetcher->isEverythingComplete())
+ {
+ // everything is already here - call done.
+ outfit_fetcher->done();
+ }
+ else
+ {
+ // it's all on it's way - add an observer, and the inventory
+ // will call done for us when everything is here.
+ gInventory.addObserver(outfit_fetcher);
+ }
+}
+
+// *NOTE: hack to get from avatar inventory to avatar
+/* static */
+void LLAppearanceManager::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append )
+{
+ // Avoid unintentionally overwriting old wearables. We have to do
+ // this up front to avoid having to deal with the case of multiple
+ // wearables being dirty.
+ if(!category) return;
+ lldebugs << "wearInventoryCategoryOnAvatar( " << category->getName()
+ << " )" << llendl;
+
+ bool follow_folder_links = (category->getPreferredType() == LLAssetType::AT_CURRENT_OUTFIT || category->getPreferredType() == LLAssetType::AT_OUTFIT );
+ if( gFloaterCustomize )
+ {
+ gFloaterCustomize->askToSaveIfDirty(boost::bind(LLAppearanceManager::changeOutfit, _1, category->getUUID(), append, follow_folder_links));
+ }
+ else
+ {
+ LLAppearanceManager::changeOutfit(TRUE, category->getUUID(), append, follow_folder_links );
+ }
+}
+
+/* static */
+void LLAppearanceManager::wearOutfitByName(const std::string& name)
+{
+ llinfos << "Wearing category " << name << llendl;
+ //inc_busy_count();
+
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ LLNameCategoryCollector has_name(name);
+ gInventory.collectDescendentsIf(gInventory.getRootFolderID(),
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ has_name);
+ bool copy_items = false;
+ LLInventoryCategory* cat = NULL;
+ if (cat_array.count() > 0)
+ {
+ // Just wear the first one that matches
+ cat = cat_array.get(0);
+ }
+ else
+ {
+ gInventory.collectDescendentsIf(LLUUID::null,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ has_name);
+ if(cat_array.count() > 0)
+ {
+ cat = cat_array.get(0);
+ copy_items = true;
+ }
+ }
+
+ if(cat)
+ {
+ LLAppearanceManager::wearInventoryCategory(cat, copy_items, false);
+ }
+ else
+ {
+ llwarns << "Couldn't find outfit " <<name<< " in wearOutfitByName()"
+ << llendl;
+ }
+
+ //dec_busy_count();
+}
+
+void LLAppearanceManager::wearItem( LLInventoryItem* item, bool do_update )
+{
+ // BAP add check for already in COF.
+ LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
+ link_inventory_item( gAgent.getID(),
+ item->getLinkedUUID(),
+ getCOF(),
+ item->getName(),
+ LLAssetType::AT_LINK,
+ cb);
+}
+
+void LLAppearanceManager::wearEnsemble( LLInventoryCategory* cat, bool do_update )
+{
+ // BAP add check for already in COF.
+ LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
+ link_inventory_item( gAgent.getID(),
+ cat->getLinkedUUID(),
+ getCOF(),
+ cat->getName(),
+ LLAssetType::AT_LINK_FOLDER,
+ cb);
+}
+