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.cpp1261
1 files changed, 900 insertions, 361 deletions
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index f2d15757c9..a7206095d3 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -32,23 +32,79 @@
#include "llviewerprecompiledheaders.h"
+#include "llaccordionctrltab.h"
#include "llagent.h"
+#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llcommandhandler.h"
-#include "llfloatercustomize.h"
+#include "lleventtimer.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
+#include "lloutfitobserver.h"
+#include "llpaneloutfitsinventory.h"
+#include "llselectmgr.h"
#include "llsidepanelappearance.h"
#include "llsidetray.h"
+#include "llviewerobjectlist.h"
#include "llvoavatar.h"
#include "llvoavatarself.h"
#include "llviewerregion.h"
#include "llwearablelist.h"
-LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name)
+char ORDER_NUMBER_SEPARATOR('@');
+
+class LLOutfitUnLockTimer: public LLEventTimer
+{
+public:
+ LLOutfitUnLockTimer(F32 period) : LLEventTimer(period)
+ {
+ // restart timer on BOF changed event
+ LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(
+ &LLOutfitUnLockTimer::reset, this));
+ stop();
+ }
+
+ /*virtual*/
+ BOOL tick()
+ {
+ if(mEventTimer.hasExpired())
+ {
+ LLAppearanceMgr::instance().setOutfitLocked(false);
+ }
+ return FALSE;
+ }
+ void stop() { mEventTimer.stop(); }
+ void start() { mEventTimer.start(); }
+ void reset() { mEventTimer.reset(); }
+ BOOL getStarted() { return mEventTimer.getStarted(); }
+
+ LLTimer& getEventTimer() { return mEventTimer;}
+};
+
+// support for secondlife:///app/appearance SLapps
+class LLAppearanceHandler : public LLCommandHandler
+{
+public:
+ // requests will be throttled from a non-trusted browser
+ LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {}
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ // support secondlife:///app/appearance/show, but for now we just
+ // make all secondlife:///app/appearance SLapps behave this way
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD());
+ return true;
+ }
+};
+
+LLAppearanceHandler gAppearanceHandler;
+
+
+LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
@@ -73,23 +129,6 @@ LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string&
}
}
-// support for secondlife:///app/appearance SLapps
-class LLAppearanceHandler : public LLCommandHandler
-{
-public:
- // requests will be throttled from a non-trusted browser
- LLAppearanceHandler() : LLCommandHandler("appearance", UNTRUSTED_THROTTLE) {}
-
- bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
- {
- // support secondlife:///app/appearance/show, but for now we just
- // make all secondlife:///app/appearance SLapps behave this way
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD());
- return true;
- }
-};
-LLAppearanceHandler gAppearanceHandler;
-
class LLWearInventoryCategoryCallback : public LLInventoryCallback
{
public:
@@ -119,7 +158,7 @@ protected:
// If the inventory callback manager goes away, we're shutting down, no longer want the callback.
if( LLInventoryCallbackManager::is_instantiated() )
{
- LLAppearanceManager::instance().wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
+ LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
}
else
{
@@ -132,174 +171,16 @@ private:
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();
- void doWearCategory();
-
-protected:
- LLUUID mCatID;
- bool mCopyItems;
- bool mAppend;
-};
-void LLOutfitObserver::done()
-{
- llinfos << "done 2nd stage fetch" << llendl;
- gInventory.removeObserver(this);
- doOnIdle(boost::bind(&LLOutfitObserver::doWearCategory,this));
-}
-
-void LLOutfitObserver::doWearCategory()
-{
- llinfos << "starting" << llendl;
-
- // 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(LLFolderType::FT_GESTURE);
- }
- else
- {
- pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
- }
- break;
- }
- }
- if(pid.isNull())
- {
- pid = gInventory.getRootFolderID();
- }
-
- LLUUID cat_id = gInventory.createNewCategory(
- pid,
- LLFolderType::FT_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);
- }
- }
- // BAP fixes a lag in display of created dir.
- gInventory.notifyObservers();
- }
- else
- {
- // Wear the inventory category.
- LLAppearanceManager::instance().wearInventoryCategoryOnAvatar(gInventory.getCategory(mCatID), mAppend);
- }
- delete this;
-}
-
-class LLOutfitFetch : public LLInventoryFetchDescendentsObserver
+//Inventory callback updating "dirty" state when destroyed
+class LLUpdateDirtyState: public LLInventoryCallback
{
public:
- LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {}
- ~LLOutfitFetch() {}
- virtual void done();
-protected:
- bool mCopyItems;
- bool mAppend;
+ LLUpdateDirtyState() {}
+ virtual ~LLUpdateDirtyState(){ LLAppearanceMgr::getInstance()->updateIsDirty(); }
+ virtual void fire(const LLUUID&) {}
};
-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.
- llinfos << "done first stage fetch" << llendl;
-
- 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);
-
- // 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);
- }
- delete this;
-}
LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy():
mFireCount(0)
@@ -312,13 +193,15 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
if (!LLApp::isExiting())
{
- LLAppearanceManager::instance().updateAppearanceFromCOF();
+ LLAppearanceMgr::instance().updateAppearanceFromCOF();
}
}
void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item)
{
- llinfos << "callback fired" << llendl;
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item);
+ const std::string item_name = item ? item->getName() : "ITEM NOT FOUND";
+ llinfos << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << llendl;
mFireCount++;
}
@@ -326,14 +209,14 @@ struct LLFoundData
{
LLFoundData() :
mAssetType(LLAssetType::AT_NONE),
- mWearableType(WT_INVALID),
+ mWearableType(LLWearableType::WT_INVALID),
mWearable(NULL) {}
LLFoundData(const LLUUID& item_id,
const LLUUID& asset_id,
const std::string& name,
const LLAssetType::EType& asset_type,
- const EWearableType& wearable_type
+ const LLWearableType::EType& wearable_type
) :
mItemID(item_id),
mAssetID(asset_id),
@@ -346,7 +229,7 @@ struct LLFoundData
LLUUID mAssetID;
std::string mName;
LLAssetType::EType mAssetType;
- EWearableType mWearableType;
+ LLWearableType::EType mWearableType;
LLWearable* mWearable;
};
@@ -365,9 +248,10 @@ public:
void checkMissingWearables();
bool pollMissingWearables();
bool isMissingCompleted();
- void recoverMissingWearable(EWearableType type);
+ void recoverMissingWearable(LLWearableType::EType type);
void clearCOFLinksForMissingWearables();
+ void onWearableAssetFetch(LLWearable *wearable);
void onAllComplete();
typedef std::list<LLFoundData> found_list_t;
@@ -399,39 +283,41 @@ bool LLWearableHoldingPattern::isFetchCompleted()
bool LLWearableHoldingPattern::isTimedOut()
{
- static F32 max_wait_time = 20.0; // give up if wearable fetches haven't completed in max_wait_time seconds.
+ static F32 max_wait_time = 60.0; // give up if wearable fetches haven't completed in max_wait_time seconds.
return mWaitTime.getElapsedTimeF32() > max_wait_time;
}
void LLWearableHoldingPattern::checkMissingWearables()
{
- std::vector<S32> found_by_type(WT_COUNT,0);
- std::vector<S32> requested_by_type(WT_COUNT,0);
+ std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0);
+ std::vector<S32> requested_by_type(LLWearableType::WT_COUNT,0);
for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it)
{
LLFoundData &data = *it;
- if (data.mWearableType < WT_COUNT)
+ if (data.mWearableType < LLWearableType::WT_COUNT)
requested_by_type[data.mWearableType]++;
if (data.mWearable)
found_by_type[data.mWearableType]++;
}
- for (S32 type = 0; type < WT_COUNT; ++type)
+ for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type)
{
llinfos << "type " << type << " requested " << requested_by_type[type] << " found " << found_by_type[type] << llendl;
if (found_by_type[type] > 0)
continue;
if (
- // Need to recover if at least one wearable of that type
- // was requested but none was found (prevent missing
- // pants)
- (requested_by_type[type] > 0) ||
- // or if type is a body part and no wearables were found.
- ((type == WT_SHAPE) || (type == WT_SKIN) || (type == WT_HAIR) || (type == WT_EYES)))
+ // If at least one wearable of certain types (pants/shirt/skirt)
+ // was requested but none was found, create a default asset as a replacement.
+ // In all other cases, don't do anything.
+ // For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud
+ // due to logic in LLVOAvatarSelf::getIsCloud().
+ // For non-critical types (tatoo, socks, etc.) the wearable will just be missing.
+ (requested_by_type[type] > 0) &&
+ ((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT)))
{
mTypesToRecover.insert(type);
mTypesToLink.insert(type);
- recoverMissingWearable((EWearableType)type);
+ recoverMissingWearable((LLWearableType::EType)type);
llwarns << "need to replace " << type << llendl;
}
}
@@ -450,12 +336,12 @@ void LLWearableHoldingPattern::onAllComplete()
{
llinfos << "Activating " << mGestItems.count() << " gestures" << llendl;
- LLGestureManager::instance().activateGestures(mGestItems);
+ LLGestureMgr::instance().activateGestures(mGestItems);
// Update the inventory item labels to reflect the fact
// they are active.
LLViewerInventoryCategory* catp =
- gInventory.getCategory(LLAppearanceManager::instance().getCOF());
+ gInventory.getCategory(LLAppearanceMgr::instance().getCOF());
if (catp)
{
@@ -466,11 +352,10 @@ void LLWearableHoldingPattern::onAllComplete()
// Update wearables.
llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl;
- LLAppearanceManager::instance().updateAgentWearables(this, false);
+ LLAppearanceMgr::instance().updateAgentWearables(this, false);
// Update attachments to match those requested.
- LLVOAvatar* avatar = gAgent.getAvatarObject();
- if( avatar )
+ if (isAgentAvatarValid())
{
llinfos << "Updating " << mObjItems.count() << " attachments" << llendl;
LLAgentWearables::userUpdateAttachments(mObjItems);
@@ -515,7 +400,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
class RecoveredItemLinkCB: public LLInventoryCallback
{
public:
- RecoveredItemLinkCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
+ RecoveredItemLinkCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
mHolder(holder),
mWearable(wearable),
mType(type)
@@ -539,7 +424,7 @@ public:
linked_item->getAssetUUID(),
linked_item->getName(),
linked_item->getType(),
- linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID
+ linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID
);
found.mWearable = mWearable;
mHolder->mFoundList.push_front(found);
@@ -557,13 +442,13 @@ public:
private:
LLWearableHoldingPattern* mHolder;
LLWearable *mWearable;
- EWearableType mType;
+ LLWearableType::EType mType;
};
class RecoveredItemCB: public LLInventoryCallback
{
public:
- RecoveredItemCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
+ RecoveredItemCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
mHolder(holder),
mWearable(wearable),
mType(type)
@@ -581,8 +466,9 @@ public:
{
link_inventory_item( gAgent.getID(),
item_id,
- LLAppearanceManager::instance().getCOF(),
+ LLAppearanceMgr::instance().getCOF(),
itemp->getName(),
+ itemp->getDescription(),
LLAssetType::AT_LINK,
cb);
}
@@ -590,14 +476,14 @@ public:
private:
LLWearableHoldingPattern* mHolder;
LLWearable *mWearable;
- EWearableType mType;
+ LLWearableType::EType mType;
};
-void LLWearableHoldingPattern::recoverMissingWearable(EWearableType type)
+void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type)
{
// Try to recover by replacing missing wearable with a new one.
LLNotificationsUtil::add("ReplacedMissingWearable");
- lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type)
+ lldebugs << "Wearable " << LLWearableType::getTypeLabel(type)
<< " could not be downloaded. Replaced inventory item with default wearable." << llendl;
LLWearable* wearable = LLWearableList::instance().createNewWearable(type);
@@ -628,11 +514,11 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it)
{
LLFoundData &data = *it;
- if ((data.mWearableType < WT_COUNT) && (!data.mWearable))
+ if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable))
{
// Wearable link that was never resolved; remove links to it from COF
llinfos << "removing link for unresolved item " << data.mItemID.asString() << llendl;
- LLAppearanceManager::instance().removeCOFItemLinks(data.mItemID,false);
+ LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID,false);
}
}
}
@@ -651,17 +537,17 @@ bool LLWearableHoldingPattern::pollMissingWearables()
if (done)
{
+ gAgentAvatarp->debugWearablesLoaded();
clearCOFLinksForMissingWearables();
onAllComplete();
}
return done;
}
-static void onWearableAssetFetch(LLWearable* wearable, void* data)
+void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable)
{
- LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
- holder->mResolved += 1; // just counting callbacks, not successes.
- llinfos << "onWearableAssetFetch, resolved count " << holder->mResolved << " of requested " << holder->mFoundList.size() << llendl;
+ mResolved += 1; // just counting callbacks, not successes.
+ llinfos << "onWearableAssetFetch, resolved count " << mResolved << " of requested " << mFoundList.size() << llendl;
if (wearable)
{
llinfos << "wearable found, type " << wearable->getType() << " asset " << wearable->getAssetID() << llendl;
@@ -671,7 +557,7 @@ static void onWearableAssetFetch(LLWearable* wearable, void* data)
llwarns << "no wearable found" << llendl;
}
- if (holder->mFired)
+ if (mFired)
{
llwarns << "called after holder fired" << llendl;
return;
@@ -682,20 +568,26 @@ static void onWearableAssetFetch(LLWearable* wearable, void* data)
return;
}
- for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
- iter != holder->mFoundList.end(); ++iter)
+ for (LLWearableHoldingPattern::found_list_t::iterator iter = mFoundList.begin();
+ iter != mFoundList.end(); ++iter)
{
LLFoundData& data = *iter;
if(wearable->getAssetID() == data.mAssetID)
{
data.mWearable = wearable;
// Failing this means inventory or asset server are corrupted in a way we don't handle.
- llassert((data.mWearableType < WT_COUNT) && (wearable->getType() == data.mWearableType));
+ llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType));
break;
}
}
}
+static void onWearableAssetFetch(LLWearable* wearable, void* data)
+{
+ LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
+ holder->onWearableAssetFetch(wearable);
+}
+
static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
{
@@ -724,13 +616,13 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
items = new_items;
}
-const LLUUID LLAppearanceManager::getCOF() const
+const LLUUID LLAppearanceMgr::getCOF() const
{
return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
}
-const LLViewerInventoryItem* LLAppearanceManager::getBaseOutfitLink()
+const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()
{
const LLUUID& current_outfit_cat = getCOF();
LLInventoryModel::cat_array_t cat_array;
@@ -752,13 +644,20 @@ const LLViewerInventoryItem* LLAppearanceManager::getBaseOutfitLink()
const LLViewerInventoryCategory *cat = item->getLinkedCategory();
if (cat && cat->getPreferredType() == LLFolderType::FT_OUTFIT)
{
+ const LLUUID parent_id = cat->getParentUUID();
+ LLViewerInventoryCategory* parent_cat = gInventory.getCategory(parent_id);
+ // if base outfit moved to trash it means that we don't have base outfit
+ if (parent_cat != NULL && parent_cat->getPreferredType() == LLFolderType::FT_TRASH)
+ {
+ return NULL;
+ }
return item;
}
}
return NULL;
}
-bool LLAppearanceManager::getBaseOutfitName(std::string& name)
+bool LLAppearanceMgr::getBaseOutfitName(std::string& name)
{
const LLViewerInventoryItem* outfit_link = getBaseOutfitLink();
if(outfit_link)
@@ -773,16 +672,179 @@ bool LLAppearanceManager::getBaseOutfitName(std::string& name)
return false;
}
+const LLUUID LLAppearanceMgr::getBaseOutfitUUID()
+{
+ const LLViewerInventoryItem* outfit_link = getBaseOutfitLink();
+ if (!outfit_link || !outfit_link->getIsLinkType()) return LLUUID::null;
+
+ const LLViewerInventoryCategory* outfit_cat = outfit_link->getLinkedCategory();
+ if (!outfit_cat) return LLUUID::null;
+
+ if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT)
+ {
+ llwarns << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << llendl;
+ return LLUUID::null;
+ }
+
+ return outfit_cat->getUUID();
+}
+
+bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace)
+{
+ if (item_id_to_wear.isNull()) return false;
+
+ LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear);
+ if (!item_to_wear) return false;
+
+ if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
+ {
+ LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback(replace);
+ copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb);
+ return false;
+ }
+ else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
+ {
+ return false; // not in library and not in agent's inventory
+ }
+ else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)))
+ {
+ LLNotificationsUtil::add("CannotWearTrash");
+ return false;
+ }
+
+ switch (item_to_wear->getType())
+ {
+ case LLAssetType::AT_CLOTHING:
+ if (gAgentWearables.areWearablesLoaded())
+ {
+ S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType());
+ if ((replace && wearable_count != 0) ||
+ (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) )
+ {
+ removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1), false);
+ }
+ }
+ case LLAssetType::AT_BODYPART:
+ // Don't wear anything until initial wearables are loaded, can
+ // destroy clothing items.
+ if (!gAgentWearables.areWearablesLoaded())
+ {
+ LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded");
+ return false;
+ }
+
+ // Remove the existing wearables of the same type.
+ // Remove existing body parts anyway because we must not be able to wear e.g. two skins.
+ if (item_to_wear->getType() == LLAssetType::AT_BODYPART)
+ {
+ removeCOFLinksOfType(item_to_wear->getWearableType(), false);
+ }
+
+ addCOFItemLink(item_to_wear, do_update);
+ break;
+ case LLAssetType::AT_OBJECT:
+ rez_attachment(item_to_wear, NULL);
+ break;
+ default: return false;;
+ }
+
+ return true;
+}
+
// Update appearance from outfit folder.
-void LLAppearanceManager::changeOutfit(bool proceed, const LLUUID& category, bool append)
+void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append)
{
if (!proceed)
return;
- LLAppearanceManager::instance().updateCOF(category,append);
+ LLAppearanceMgr::instance().updateCOF(category,append);
+}
+
+void LLAppearanceMgr::replaceCurrentOutfit(const LLUUID& new_outfit)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(new_outfit);
+ wearInventoryCategory(cat, false, false);
+}
+
+// Open outfit renaming dialog.
+void LLAppearanceMgr::renameOutfit(const LLUUID& outfit_id)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_id);
+ if (!cat)
+ {
+ return;
+ }
+
+ LLSD args;
+ args["NAME"] = cat->getName();
+
+ LLSD payload;
+ payload["cat_id"] = outfit_id;
+
+ LLNotificationsUtil::add("RenameOutfit", args, payload, boost::bind(onOutfitRename, _1, _2));
+}
+
+// User typed new outfit name.
+// static
+void LLAppearanceMgr::onOutfitRename(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return; // canceled
+
+ std::string outfit_name = response["new_name"].asString();
+ LLStringUtil::trim(outfit_name);
+ if (!outfit_name.empty())
+ {
+ LLUUID cat_id = notification["payload"]["cat_id"].asUUID();
+ rename_category(&gInventory, cat_id, outfit_name);
+ }
+}
+
+void LLAppearanceMgr::setOutfitLocked(bool locked)
+{
+ if (mOutfitLocked == locked)
+ {
+ return;
+ }
+
+ mOutfitLocked = locked;
+ if (locked)
+ {
+ mUnlockOutfitTimer->reset();
+ mUnlockOutfitTimer->start();
+ }
+ else
+ {
+ mUnlockOutfitTimer->stop();
+ }
+
+ LLOutfitObserver::instance().notifyOutfitLockChanged();
+}
+
+void LLAppearanceMgr::addCategoryToCurrentOutfit(const LLUUID& cat_id)
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ wearInventoryCategory(cat, false, true);
+}
+
+void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id)
+{
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWorn collector;
+
+ gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector);
+
+ LLInventoryModel::item_array_t::const_iterator it = items.begin();
+ const LLInventoryModel::item_array_t::const_iterator it_end = items.end();
+ for( ; it_end != it; ++it)
+ {
+ LLViewerInventoryItem* item = *it;
+ removeItemFromAvatar(item->getUUID());
+ }
}
// Create a copy of src_id + contents as a subfolder of dst_id.
-void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
+void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb)
{
LLInventoryCategory *src_cat = gInventory.getCategory(src_id);
@@ -805,7 +867,7 @@ void LLAppearanceManager::shallowCopyCategory(const LLUUID& src_id, const LLUUID
}
// Copy contents of src_id to dst_id.
-void LLAppearanceManager::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
+void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb)
{
LLInventoryModel::cat_array_t* cats;
@@ -820,10 +882,13 @@ void LLAppearanceManager::shallowCopyCategoryContents(const LLUUID& src_id, cons
{
case LLAssetType::AT_LINK:
{
+ //LLInventoryItem::getDescription() is used for a new description
+ //to propagate ordering information saved in descriptions of links
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
dst_id,
item->getName(),
+ item->LLInventoryItem::getDescription(),
LLAssetType::AT_LINK, cb);
break;
}
@@ -837,6 +902,7 @@ void LLAppearanceManager::shallowCopyCategoryContents(const LLUUID& src_id, cons
item->getLinkedUUID(),
dst_id,
item->getName(),
+ item->getDescription(),
LLAssetType::AT_LINK_FOLDER, cb);
}
break;
@@ -861,15 +927,15 @@ void LLAppearanceManager::shallowCopyCategoryContents(const LLUUID& src_id, cons
}
}
-BOOL LLAppearanceManager::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
+BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
{
// These are the wearable items that are required for considering this
// folder as containing a complete outfit.
U32 required_wearables = 0;
- required_wearables |= 1LL << WT_SHAPE;
- required_wearables |= 1LL << WT_SKIN;
- required_wearables |= 1LL << WT_HAIR;
- required_wearables |= 1LL << WT_EYES;
+ required_wearables |= 1LL << LLWearableType::WT_SHAPE;
+ required_wearables |= 1LL << LLWearableType::WT_SKIN;
+ required_wearables |= 1LL << LLWearableType::WT_HAIR;
+ required_wearables |= 1LL << LLWearableType::WT_EYES;
// These are the wearables that the folder actually contains.
U32 folder_wearables = 0;
@@ -883,7 +949,7 @@ BOOL LLAppearanceManager::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
const LLViewerInventoryItem* item = (*iter);
if (item->isWearableType())
{
- const EWearableType wearable_type = item->getWearableType();
+ const LLWearableType::EType wearable_type = item->getWearableType();
folder_wearables |= 1LL << wearable_type;
}
}
@@ -892,8 +958,35 @@ BOOL LLAppearanceManager::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
return ((required_wearables & folder_wearables) == required_wearables);
}
+bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id)
+{
+ // Disallow removing the base outfit.
+ if (outfit_cat_id == getBaseOutfitUUID())
+ {
+ return false;
+ }
+
+ // Check if the outfit folder itself is removable.
+ if (!get_is_category_removable(&gInventory, outfit_cat_id))
+ {
+ return false;
+ }
+
+ // Check for the folder's non-removable descendants.
+ LLFindNonRemovableObjects filter_non_removable;
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::item_array_t::const_iterator it;
+ gInventory.collectDescendentsIf(outfit_cat_id, cats, items, false, filter_non_removable);
+ if (!cats.empty() || !items.empty())
+ {
+ return false;
+ }
+
+ return true;
+}
-void LLAppearanceManager::purgeBaseOutfitLink(const LLUUID& category)
+void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
{
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
@@ -915,7 +1008,7 @@ void LLAppearanceManager::purgeBaseOutfitLink(const LLUUID& category)
}
}
-void LLAppearanceManager::purgeCategory(const LLUUID& category, bool keep_outfit_links)
+void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links)
{
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
@@ -935,29 +1028,16 @@ void LLAppearanceManager::purgeCategory(const LLUUID& category, bool keep_outfit
// Keep the last N wearables of each type. For viewer 2.0, N is 1 for
// both body parts and clothing items.
-void LLAppearanceManager::filterWearableItems(
+void LLAppearanceMgr::filterWearableItems(
LLInventoryModel::item_array_t& items, S32 max_per_type)
{
// Divvy items into arrays by wearable type.
- std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT);
- for (S32 i=0; i<items.count(); i++)
- {
- LLViewerInventoryItem *item = items.get(i);
- // Ignore non-wearables.
- if (!item->isWearableType())
- continue;
- EWearableType type = item->getWearableType();
- if(type < 0 || type >= WT_COUNT)
- {
- LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
- continue;
- }
- items_by_type[type].push_back(item);
- }
+ std::vector<LLInventoryModel::item_array_t> items_by_type(LLWearableType::WT_COUNT);
+ divvyWearablesByType(items, items_by_type);
// rebuild items list, retaining the last max_per_type of each array
items.clear();
- for (S32 i=0; i<WT_COUNT; i++)
+ for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
{
S32 size = items_by_type[i].size();
if (size <= 0)
@@ -971,7 +1051,7 @@ void LLAppearanceManager::filterWearableItems(
}
// Create links to all listed items.
-void LLAppearanceManager::linkAll(const LLUUID& category,
+void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
LLInventoryModel::item_array_t& items,
LLPointer<LLInventoryCallback> cb)
{
@@ -980,14 +1060,20 @@ void LLAppearanceManager::linkAll(const LLUUID& category,
const LLInventoryItem* item = items.get(i).get();
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
- category,
+ cat_uuid,
item->getName(),
+ item->LLInventoryItem::getDescription(),
LLAssetType::AT_LINK,
cb);
+
+ const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid);
+ const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND";
+
+ llinfos << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << llendl; // Seraph remove for 2.1
}
}
-void LLAppearanceManager::updateCOF(const LLUUID& category, bool append)
+void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
{
LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl;
@@ -1002,9 +1088,9 @@ void LLAppearanceManager::updateCOF(const LLUUID& category, bool append)
for(S32 i = 0; i < gest_items.count(); ++i)
{
LLViewerInventoryItem *gest_item = gest_items.get(i);
- if ( LLGestureManager::instance().isGestureActive( gest_item->getLinkedUUID()) )
+ if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) )
{
- LLGestureManager::instance().deactivateGesture( gest_item->getLinkedUUID() );
+ LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() );
}
}
}
@@ -1027,7 +1113,7 @@ void LLAppearanceManager::updateCOF(const LLUUID& category, bool append)
getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);
// Reduce wearables to max of one per type.
removeDuplicateItems(wear_items);
- filterWearableItems(wear_items, 1);
+ filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
// - Attachments: include COF contents only if appending.
LLInventoryModel::item_array_t obj_items;
@@ -1052,9 +1138,13 @@ void LLAppearanceManager::updateCOF(const LLUUID& category, bool append)
llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl;
LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
+ llinfos << "Linking body items" << llendl; // Seraph remove for 2.1
linkAll(cof, body_items, link_waiter);
+ llinfos << "Linking wear items" << llendl; // Seraph remove for 2.1
linkAll(cof, wear_items, link_waiter);
+ llinfos << "Linking obj items" << llendl; // Seraph remove for 2.1
linkAll(cof, obj_items, link_waiter);
+ llinfos << "Linking gesture items" << llendl; // Seraph remove for 2.1
linkAll(cof, gest_items, link_waiter);
// Add link to outfit if category is an outfit.
@@ -1065,7 +1155,7 @@ void LLAppearanceManager::updateCOF(const LLUUID& category, bool append)
llinfos << "waiting for LLUpdateAppearanceOnDestroy" << llendl;
}
-void LLAppearanceManager::updatePanelOutfitName(const std::string& name)
+void LLAppearanceMgr::updatePanelOutfitName(const std::string& name)
{
LLSidepanelAppearance* panel_appearance =
dynamic_cast<LLSidepanelAppearance *>(LLSideTray::getInstance()->getPanel("sidepanel_appearance"));
@@ -1075,7 +1165,7 @@ void LLAppearanceManager::updatePanelOutfitName(const std::string& name)
}
}
-void LLAppearanceManager::createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter)
+void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter)
{
const LLUUID cof = getCOF();
LLViewerInventoryCategory* catp = gInventory.getCategory(category);
@@ -1085,7 +1175,7 @@ void LLAppearanceManager::createBaseOutfitLink(const LLUUID& category, LLPointer
if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
{
- link_inventory_item(gAgent.getID(), category, cof, catp->getName(),
+ link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "",
LLAssetType::AT_LINK_FOLDER, link_waiter);
new_outfit_name = catp->getName();
}
@@ -1093,7 +1183,7 @@ void LLAppearanceManager::createBaseOutfitLink(const LLUUID& category, LLPointer
updatePanelOutfitName(new_outfit_name);
}
-void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder, bool append)
+void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, bool append)
{
lldebugs << "updateAgentWearables()" << llendl;
LLInventoryItem::item_array_t items;
@@ -1101,7 +1191,7 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder,
// For each wearable type, find the first instance in the category
// that we recursed through.
- for( S32 i = 0; i < WT_COUNT; i++ )
+ for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ )
{
for (LLWearableHoldingPattern::found_list_t::iterator iter = holder->mFoundList.begin();
iter != holder->mFoundList.end(); ++iter)
@@ -1110,14 +1200,12 @@ void LLAppearanceManager::updateAgentWearables(LLWearableHoldingPattern* holder,
LLWearable* wearable = data.mWearable;
if( wearable && ((S32)wearable->getType() == i) )
{
- LLViewerInventoryItem* item;
- item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
if( item && (item->getAssetUUID() == wearable->getAssetID()) )
{
items.put(item);
wearables.put(wearable);
}
- break;
}
}
}
@@ -1146,8 +1234,24 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items)
items = pruned_items;
}
-void LLAppearanceManager::updateAppearanceFromCOF()
+//a predicate for sorting inventory items by actual descriptions
+bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2)
+{
+ if (!item1 || !item2)
+ {
+ llwarning("either item1 or item2 is NULL", 0);
+ return true;
+ }
+
+ return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription();
+}
+
+void LLAppearanceMgr::updateAppearanceFromCOF()
{
+ //checking integrity of the COF in terms of ordering of wearables,
+ //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
+ updateClothingOrderingInfo();
+
// update dirty flag to see if the state of the COF matches
// the saved outfit stored as a folder link
llinfos << "starting" << llendl;
@@ -1160,7 +1264,7 @@ void LLAppearanceManager::updateAppearanceFromCOF()
LLUUID current_outfit_id = getCOF();
// Find all the wearables that are in the COF's subtree.
- lldebugs << "LLAppearanceManager::updateFromCOF()" << llendl;
+ lldebugs << "LLAppearanceMgr::updateFromCOF()" << llendl;
LLInventoryModel::item_array_t wear_items;
LLInventoryModel::item_array_t obj_items;
LLInventoryModel::item_array_t gest_items;
@@ -1176,6 +1280,10 @@ void LLAppearanceManager::updateAppearanceFromCOF()
return;
}
+ //preparing the list of wearables in the correct order for LLAgentWearables
+ sortItemsByActualDescription(wear_items);
+
+
LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
holder->mObjItems = obj_items;
@@ -1186,9 +1294,6 @@ void LLAppearanceManager::updateAppearanceFromCOF()
// callback will be called (and this object deleted)
// before the final getNextData().
- // BAP future cleanup - no point having found_container when
- // mFoundList already has all the info.
- LLDynamicArray<LLFoundData> found_container;
for(S32 i = 0; i < wear_items.count(); ++i)
{
LLViewerInventoryItem *item = wear_items.get(i);
@@ -1199,22 +1304,21 @@ void LLAppearanceManager::updateAppearanceFromCOF()
linked_item->getAssetUUID(),
linked_item->getName(),
linked_item->getType(),
- linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID
+ linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID
);
#if 0
// Fault injection: uncomment this block to test asset
// fetch failures (should be replaced by new defaults in
// lost&found).
- if (found.mWearableType == WT_SHAPE || found.mWearableType == WT_JACKET)
+ if (found.mWearableType == LLWearableType::WT_SHAPE || found.mWearableType == LLWearableType::WT_JACKET)
{
found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB
}
#endif
-
- holder->mFoundList.push_front(found);
- found_container.put(found);
+ //pushing back, not front, to preserve order of wearables for LLAgentWearables
+ holder->mFoundList.push_back(found);
}
else
{
@@ -1229,9 +1333,10 @@ void LLAppearanceManager::updateAppearanceFromCOF()
}
}
- for(S32 i = 0; i < found_container.count(); ++i)
+ for (LLWearableHoldingPattern::found_list_t::iterator it = holder->mFoundList.begin();
+ it != holder->mFoundList.end(); ++it)
{
- LLFoundData& found = found_container.get(i);
+ LLFoundData& found = *it;
llinfos << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl;
@@ -1248,10 +1353,9 @@ void LLAppearanceManager::updateAppearanceFromCOF()
{
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder));
}
-
}
-void LLAppearanceManager::getDescendentsOfAssetType(const LLUUID& category,
+void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,
LLInventoryModel::item_array_t& items,
LLAssetType::EType type,
bool follow_folder_links)
@@ -1266,7 +1370,7 @@ void LLAppearanceManager::getDescendentsOfAssetType(const LLUUID& category,
follow_folder_links);
}
-void LLAppearanceManager::getUserDescendents(const LLUUID& category,
+void LLAppearanceMgr::getUserDescendents(const LLUUID& category,
LLInventoryModel::item_array_t& wear_items,
LLInventoryModel::item_array_t& obj_items,
LLInventoryModel::item_array_t& gest_items,
@@ -1301,36 +1405,98 @@ void LLAppearanceManager::getUserDescendents(const LLUUID& category,
follow_folder_links);
}
-void LLAppearanceManager::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
+void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
{
+ gAgentWearables.notifyLoadingStarted();
if(!category) return;
llinfos << "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())
+ callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
+ &LLAppearanceMgr::instance(),
+ category->getUUID(), copy, append));
+}
+
+void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append)
+{
+ llinfos << "starting" << llendl;
+
+ // We now have an outfit ready to be copied to agent inventory. Do
+ // it, and wear that outfit normally.
+ LLInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if(copy_items)
{
- // everything is already here - call done.
- outfit_fetcher->done();
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(cat_id, cats, items);
+ std::string name;
+ if(!cat)
+ {
+ // should never happen.
+ name = "New Outfit";
+ }
+ else
+ {
+ name = cat->getName();
+ }
+ LLViewerInventoryItem* item = NULL;
+ LLInventoryModel::item_array_t::const_iterator it = items->begin();
+ LLInventoryModel::item_array_t::const_iterator end = items->end();
+ LLUUID pid;
+ for(; it < end; ++it)
+ {
+ item = *it;
+ if(item)
+ {
+ if(LLInventoryType::IT_GESTURE == item->getInventoryType())
+ {
+ pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
+ }
+ else
+ {
+ pid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
+ }
+ break;
+ }
+ }
+ if(pid.isNull())
+ {
+ pid = gInventory.getRootFolderID();
+ }
+
+ LLUUID new_cat_id = gInventory.createNewCategory(
+ pid,
+ LLFolderType::FT_NONE,
+ name);
+ LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(new_cat_id, append);
+ it = items->begin();
+ for(; it < end; ++it)
+ {
+ item = *it;
+ if(item)
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ new_cat_id,
+ std::string(),
+ cb);
+ }
+ }
+ // BAP fixes a lag in display of created dir.
+ gInventory.notifyObservers();
}
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);
+ // Wear the inventory category.
+ LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, append);
}
}
// *NOTE: hack to get from avatar inventory to avatar
-void LLAppearanceManager::wearInventoryCategoryOnAvatar( LLInventoryCategory* category, bool append )
+void LLAppearanceMgr::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
@@ -1340,19 +1506,16 @@ void LLAppearanceManager::wearInventoryCategoryOnAvatar( LLInventoryCategory* ca
llinfos << "wearInventoryCategoryOnAvatar( " << category->getName()
<< " )" << llendl;
- if( gFloaterCustomize )
- {
- gFloaterCustomize->askToSaveIfDirty(boost::bind(&LLAppearanceManager::changeOutfit,
- &LLAppearanceManager::instance(),
- _1, category->getUUID(), append));
- }
- else
+ if (gAgentCamera.cameraCustomizeAvatar())
{
- LLAppearanceManager::changeOutfit(TRUE, category->getUUID(), append);
+ // switching to outfit editor should automagically save any currently edited wearable
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
}
+
+ LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);
}
-void LLAppearanceManager::wearOutfitByName(const std::string& name)
+void LLAppearanceMgr::wearOutfitByName(const std::string& name)
{
llinfos << "Wearing category " << name << llendl;
//inc_busy_count();
@@ -1388,7 +1551,7 @@ void LLAppearanceManager::wearOutfitByName(const std::string& name)
if(cat)
{
- LLAppearanceManager::wearInventoryCategory(cat, copy_items, false);
+ LLAppearanceMgr::wearInventoryCategory(cat, copy_items, false);
}
else
{
@@ -1424,7 +1587,7 @@ public:
if (item)
{
gInventory.removeObserver(this);
- LLAppearanceManager::instance().addCOFItemLink(item,mDoUpdate);
+ LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate);
delete this;
}
}
@@ -1435,7 +1598,9 @@ private:
};
-void LLAppearanceManager::addCOFItemLink(const LLUUID &item_id, bool do_update )
+// BAP - note that this runs asynchronously if the item is not already loaded from inventory.
+// Dangerous if caller assumes link will exist after calling the function.
+void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update )
{
const LLInventoryItem *item = gInventory.getItem(item_id);
if (!item)
@@ -1449,7 +1614,7 @@ void LLAppearanceManager::addCOFItemLink(const LLUUID &item_id, bool do_update )
}
}
-void LLAppearanceManager::addCOFItemLink(const LLInventoryItem *item, bool do_update )
+void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update )
{
const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);
if (!vitem)
@@ -1462,52 +1627,69 @@ void LLAppearanceManager::addCOFItemLink(const LLInventoryItem *item, bool do_up
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
- gInventory.collectDescendents(LLAppearanceManager::getCOF(),
+ gInventory.collectDescendents(LLAppearanceMgr::getCOF(),
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH);
bool linked_already = false;
+ U32 count = 0;
for (S32 i=0; i<item_array.count(); i++)
{
// Are these links to the same object?
const LLViewerInventoryItem* inv_item = item_array.get(i).get();
+ const LLWearableType::EType wearable_type = inv_item->getWearableType();
+
+ const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE)
+ || (wearable_type == LLWearableType::WT_HAIR)
+ || (wearable_type == LLWearableType::WT_EYES)
+ || (wearable_type == LLWearableType::WT_SKIN);
+
if (inv_item->getLinkedUUID() == vitem->getLinkedUUID())
{
linked_already = true;
}
- // Are these links to different items of the same wearable
+ // Are these links to different items of the same body part
// type? If so, new item will replace old.
- // MULTI-WEARABLES: revisit if more than one per type is allowed.
- else if (areMatchingWearables(vitem,inv_item))
+ else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type))
{
- if (inv_item->getIsLinkType())
+ ++count;
+ if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type))
+ {
+ gInventory.purgeObject(inv_item->getUUID());
+ }
+ else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
{
+ // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE
gInventory.purgeObject(inv_item->getUUID());
}
}
}
+
if (linked_already)
{
if (do_update)
{
- LLAppearanceManager::updateAppearanceFromCOF();
+ LLAppearanceMgr::updateAppearanceFromCOF();
}
return;
}
else
{
LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
+ const std::string description = vitem->getIsLinkType() ? vitem->getDescription() : "";
link_inventory_item( gAgent.getID(),
vitem->getLinkedUUID(),
getCOF(),
vitem->getName(),
+ description,
LLAssetType::AT_LINK,
cb);
}
return;
}
-void LLAppearanceManager::addEnsembleLink( LLInventoryCategory* cat, bool do_update )
+// BAP remove ensemble code for 2.1?
+void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update )
{
#if SUPPORT_ENSEMBLES
// BAP add check for already in COF.
@@ -1516,18 +1698,19 @@ void LLAppearanceManager::addEnsembleLink( LLInventoryCategory* cat, bool do_upd
cat->getLinkedUUID(),
getCOF(),
cat->getName(),
+ cat->getDescription(),
LLAssetType::AT_LINK_FOLDER,
cb);
#endif
}
-void LLAppearanceManager::removeCOFItemLinks(const LLUUID& item_id, bool do_update)
+void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, bool do_update)
{
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
- gInventory.collectDescendents(LLAppearanceManager::getCOF(),
+ gInventory.collectDescendents(LLAppearanceMgr::getCOF(),
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH);
@@ -1541,11 +1724,45 @@ void LLAppearanceManager::removeCOFItemLinks(const LLUUID& item_id, bool do_upda
}
if (do_update)
{
- LLAppearanceManager::updateAppearanceFromCOF();
+ LLAppearanceMgr::updateAppearanceFromCOF();
}
}
-void LLAppearanceManager::updateIsDirty()
+void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, bool do_update)
+{
+ LLFindWearablesOfType filter_wearables_of_type(type);
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLInventoryModel::item_array_t::const_iterator it;
+
+ gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type);
+ for (it = items.begin(); it != items.end(); ++it)
+ {
+ const LLViewerInventoryItem* item = *it;
+ if (item->getIsLinkType()) // we must operate on links only
+ {
+ gInventory.purgeObject(item->getUUID());
+ }
+ }
+
+ if (do_update)
+ {
+ updateAppearanceFromCOF();
+ }
+}
+
+bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInventoryItem* item2)
+{
+ if (!item1 || !item2)
+ {
+ llwarning("item1, item2 cannot be null, something is very wrong", 0);
+ return true;
+ }
+
+ return item1->getLinkedUUID() < item2->getLinkedUUID();
+}
+
+void LLAppearanceMgr::updateIsDirty()
{
LLUUID cof = getCOF();
LLUUID base_outfit;
@@ -1584,37 +1801,41 @@ void LLAppearanceManager::updateIsDirty()
// Current outfit folder should have one more item than the outfit folder.
// this one item is the link back to the outfit folder itself.
mOutfitIsDirty = true;
+ return;
}
- else
- {
- typedef std::set<LLUUID> item_set_t;
- item_set_t cof_set;
- item_set_t outfit_set;
- // sort COF items by UUID
- for (S32 i = 0; i < cof_items.count(); ++i)
+ //getting rid of base outfit folder link to simplify comparison
+ for (LLInventoryModel::item_array_t::iterator it = cof_items.begin(); it != cof_items.end(); ++it)
+ {
+ if (*it == base_outfit_item)
{
- LLViewerInventoryItem *item = cof_items.get(i);
- // don't add the base outfit link to the list of objects we're comparing
- if(item != base_outfit_item)
- {
- cof_set.insert(item->getLinkedUUID());
- }
+ cof_items.erase(it);
+ break;
}
+ }
- // sort outfit folder by UUID
- for (S32 i = 0; i < outfit_items.count(); ++i)
+ //"dirty" - also means a difference in linked UUIDs and/or a difference in wearables order (links' descriptions)
+ std::sort(cof_items.begin(), cof_items.end(), sort_by_linked_uuid);
+ std::sort(outfit_items.begin(), outfit_items.end(), sort_by_linked_uuid);
+
+ for (U32 i = 0; i < cof_items.size(); ++i)
+ {
+ LLViewerInventoryItem *item1 = cof_items.get(i);
+ LLViewerInventoryItem *item2 = outfit_items.get(i);
+
+ if (item1->getLinkedUUID() != item2->getLinkedUUID() ||
+ item1->LLInventoryItem::getDescription() != item2->LLInventoryItem::getDescription())
{
- LLViewerInventoryItem *item = outfit_items.get(i);
- outfit_set.insert(item->getLinkedUUID());
+ mOutfitIsDirty = true;
+ return;
}
-
- mOutfitIsDirty = (outfit_set != cof_set);
}
+
+ mOutfitIsDirty = false;
}
}
-void LLAppearanceManager::onFirstFullyVisible()
+void LLAppearanceMgr::autopopulateOutfits()
{
// If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account)
// then auto-populate outfits from the library into the My Outfits folder.
@@ -1631,9 +1852,322 @@ void LLAppearanceManager::onFirstFullyVisible()
check_populate_my_outfits = false;
}
+// Handler for anything that's deferred until avatar de-clouds.
+void LLAppearanceMgr::onFirstFullyVisible()
+{
+ gAgentAvatarp->debugAvatarVisible();
+ autopopulateOutfits();
+}
+
+bool LLAppearanceMgr::updateBaseOutfit()
+{
+ if (isOutfitLocked())
+ {
+ // don't allow modify locked outfit
+ llassert(!isOutfitLocked());
+ return false;
+ }
+ setOutfitLocked(true);
+
+ const LLUUID base_outfit_id = getBaseOutfitUUID();
+ if (base_outfit_id.isNull()) return false;
+
+ updateClothingOrderingInfo();
+
+ // in a Base Outfit we do not remove items, only links
+ purgeCategory(base_outfit_id, false);
+
+
+ LLPointer<LLInventoryCallback> dirty_state_updater = new LLUpdateDirtyState();
+
+ //COF contains only links so we copy to the Base Outfit only links
+ shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater);
+
+ return true;
+}
+
+void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type)
+{
+ items_by_type.reserve(LLWearableType::WT_COUNT);
+ if (items.empty()) return;
+
+ for (S32 i=0; i<items.count(); i++)
+ {
+ LLViewerInventoryItem *item = items.get(i);
+ // Ignore non-wearables.
+ if (!item->isWearableType())
+ continue;
+ LLWearableType::EType type = item->getWearableType();
+ if(type < 0 || type >= LLWearableType::WT_COUNT)
+ {
+ LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL;
+ continue;
+ }
+ items_by_type[type].push_back(item);
+ }
+}
+
+std::string build_order_string(LLWearableType::EType type, U32 i)
+{
+ std::ostringstream order_num;
+ order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i;
+ return order_num.str();
+}
+
+struct WearablesOrderComparator
+{
+ WearablesOrderComparator(const LLWearableType::EType type)
+ {
+ mControlSize = build_order_string(type, 0).size();
+ };
+
+ bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)
+ {
+ if (!item1 || !item2)
+ {
+ llwarning("either item1 or item2 is NULL", 0);
+ return true;
+ }
+
+ const std::string& desc1 = item1->LLInventoryItem::getDescription();
+ const std::string& desc2 = item2->LLInventoryItem::getDescription();
+
+ bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]);
+ bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]);
+
+ if (item1_valid && item2_valid)
+ return desc1 < desc2;
+
+ //we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions,
+ //items with ordering information but not for the associated wearables type
+ if (!item1_valid && item2_valid)
+ return false;
+
+ return true;
+ }
+
+ U32 mControlSize;
+};
+
+void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id)
+{
+ if (cat_id.isNull())
+ {
+ cat_id = getCOF();
+ }
+
+ // COF is processed if cat_id is not specified
+ LLInventoryModel::item_array_t wear_items;
+ getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false);
+
+ wearables_by_type_t items_by_type(LLWearableType::WT_COUNT);
+ divvyWearablesByType(wear_items, items_by_type);
+
+ bool inventory_changed = false;
+ for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)
+ {
+
+ U32 size = items_by_type[type].size();
+ if (!size) continue;
+
+ //sinking down invalid items which need reordering
+ std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type));
+
+ //requesting updates only for those links which don't have "valid" descriptions
+ for (U32 i = 0; i < size; i++)
+ {
+ LLViewerInventoryItem* item = items_by_type[type][i];
+ if (!item) continue;
+
+ std::string new_order_str = build_order_string((LLWearableType::EType)type, i);
+ if (new_order_str == item->LLInventoryItem::getDescription()) continue;
+
+ item->setDescription(new_order_str);
+ item->setComplete(TRUE);
+ item->updateServer(FALSE);
+ gInventory.updateItem(item);
+ inventory_changed = true;
+ }
+ }
+
+ //*TODO do we really need to notify observers?
+ if (inventory_changed) gInventory.notifyObservers();
+}
+
+
+
+
+class LLShowCreatedOutfit: public LLInventoryCallback
+{
+public:
+ LLShowCreatedOutfit(LLUUID& folder_id, bool show_panel = true): mFolderID(folder_id), mShowPanel(show_panel)
+ {}
+
+ virtual ~LLShowCreatedOutfit()
+ {
+ LLSD key;
+
+ //EXT-7727. For new accounts LLShowCreatedOutfit is created during login process
+ // add may be processed after login process is finished
+ if (mShowPanel)
+ {
+ LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key);
+ }
+ LLPanelOutfitsInventory *outfit_panel =
+ dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
+ if (outfit_panel)
+ {
+ outfit_panel->getRootFolder()->clearSelection();
+ outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE);
+ }
+
+ LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0;
+ if (tab_outfits && !tab_outfits->getDisplayChildren())
+ {
+ tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren());
+ }
+
+ LLAppearanceMgr::getInstance()->updateIsDirty();
+ LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
+ }
+
+ virtual void fire(const LLUUID&)
+ {}
+
+private:
+ LLUUID mFolderID;
+ bool mShowPanel;
+};
+
+LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel)
+{
+ if (!isAgentAvatarValid()) return LLUUID::null;
+
+ // 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,
+ new_folder_name);
+
+ updateClothingOrderingInfo();
+
+ LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id,show_panel);
+ shallowCopyCategoryContents(getCOF(),folder_id, cb);
+ createBaseOutfitLink(folder_id, cb);
+
+ dumpCat(folder_id,"COF, new outfit");
+
+ return folder_id;
+}
+
+void LLAppearanceMgr::wearBaseOutfit()
+{
+ const LLUUID& base_outfit_id = getBaseOutfitUUID();
+ if (base_outfit_id.isNull()) return;
+
+ updateCOF(base_outfit_id);
+}
+
+void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
+{
+ LLViewerInventoryItem * item_to_remove = gInventory.getItem(id_to_remove);
+ if (!item_to_remove) return;
+
+ switch (item_to_remove->getType())
+ {
+ case LLAssetType::AT_CLOTHING:
+ if (get_is_item_worn(id_to_remove))
+ {
+ //*TODO move here the exact removing code from LLWearableBridge::removeItemFromAvatar in the future
+ LLWearableBridge::removeItemFromAvatar(item_to_remove);
+ }
+ break;
+ case LLAssetType::AT_OBJECT:
+ gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
+ gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_to_remove->getLinkedUUID());
+ gMessageSystem->sendReliable( gAgent.getRegion()->getHost());
+
+ {
+ // this object might have been selected, so let the selection manager know it's gone now
+ LLViewerObject *found_obj = gObjectList.findObject(item_to_remove->getLinkedUUID());
+ if (found_obj)
+ {
+ LLSelectMgr::getInstance()->remove(found_obj);
+ };
+ }
+ default: break;
+ }
+}
+
+bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
+{
+ if (!item || !item->isWearableType()) return false;
+ if (item->getType() != LLAssetType::AT_CLOTHING) return false;
+ if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false;
+
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWearablesOfType filter_wearables_of_type(item->getWearableType());
+ gInventory.collectDescendentsIf(getCOF(), cats, items, true, filter_wearables_of_type);
+ if (items.empty()) return false;
+
+ // We assume that the items have valid descriptions.
+ std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType()));
+
+ if (closer_to_body && items.front() == item) return false;
+ if (!closer_to_body && items.back() == item) return false;
+
+ LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item);
+ if (items.end() == it) return false;
+
+
+ //swapping descriptions
+ closer_to_body ? --it : ++it;
+ LLViewerInventoryItem* swap_item = *it;
+ if (!swap_item) return false;
+ std::string tmp = swap_item->LLInventoryItem::getDescription();
+ swap_item->setDescription(item->LLInventoryItem::getDescription());
+ item->setDescription(tmp);
+
+
+ //items need to be updated on a dataserver
+ item->setComplete(TRUE);
+ item->updateServer(FALSE);
+ gInventory.updateItem(item);
+
+ swap_item->setComplete(TRUE);
+ swap_item->updateServer(FALSE);
+ gInventory.updateItem(swap_item);
+
+ //to cause appearance of the agent to be updated
+ bool result = false;
+ if (result = gAgentWearables.moveWearable(item, closer_to_body))
+ {
+ gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE);
+ }
+
+ setOutfitDirty(true);
+
+ //*TODO do we need to notify observers here in such a way?
+ gInventory.notifyObservers();
+
+ return result;
+}
+
+//static
+void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items)
+{
+ if (items.size() < 2) return;
+
+ std::sort(items.begin(), items.end(), sort_by_description);
+}
+
//#define DUMP_CAT_VERBOSE
-void LLAppearanceManager::dumpCat(const LLUUID& cat_id, const std::string& msg)
+void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg)
{
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
@@ -1654,7 +2188,7 @@ void LLAppearanceManager::dumpCat(const LLUUID& cat_id, const std::string& msg)
llinfos << msg << " count " << items.count() << llendl;
}
-void LLAppearanceManager::dumpItemArray(const LLInventoryModel::item_array_t& items,
+void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,
const std::string& msg)
{
llinfos << msg << llendl;
@@ -1666,22 +2200,31 @@ void LLAppearanceManager::dumpItemArray(const LLInventoryModel::item_array_t& it
llinfos << llendl;
}
-LLAppearanceManager::LLAppearanceManager():
+LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
mOutfitIsDirty(false)
{
+ LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
+
+ // unlock outfit on save operation completed
+ outfit_observer.addCOFSavedCallback(boost::bind(
+ &LLAppearanceMgr::setOutfitLocked, this, false));
+
+ mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
+ "OutfitOperationsTimeout")));
}
-LLAppearanceManager::~LLAppearanceManager()
+LLAppearanceMgr::~LLAppearanceMgr()
{
}
-void LLAppearanceManager::setAttachmentInvLinkEnable(bool val)
+void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
{
llinfos << "setAttachmentInvLinkEnable => " << (int) val << llendl;
mAttachmentInvLinkEnabled = val;
}
+// BAP TODO - mRegisteredAttachments is currently maintained but not used for anything. Consider yanking.
void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
{
llinfos << msg << llendl;
@@ -1699,15 +2242,14 @@ void dumpAttachmentSet(const std::set<LLUUID>& atts, const std::string& msg)
llinfos << llendl;
}
-void LLAppearanceManager::registerAttachment(const LLUUID& item_id)
+void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
{
mRegisteredAttachments.insert(item_id);
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
- //dumpAttachmentSet(mRegisteredAttachments,"after register:");
if (mAttachmentInvLinkEnabled)
{
- LLAppearanceManager::addCOFItemLink(item_id, false); // Add COF link for item.
+ LLAppearanceMgr::addCOFItemLink(item_id, false); // Add COF link for item.
}
else
{
@@ -1715,17 +2257,14 @@ void LLAppearanceManager::registerAttachment(const LLUUID& item_id)
}
}
-void LLAppearanceManager::unregisterAttachment(const LLUUID& item_id)
+void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
{
mRegisteredAttachments.erase(item_id);
gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
- //dumpAttachmentSet(mRegisteredAttachments,"after unregister:");
-
if (mAttachmentInvLinkEnabled)
{
- //LLAppearanceManager::dumpCat(LLAppearanceManager::getCOF(),"Removing attachment link:");
- LLAppearanceManager::removeCOFItemLinks(item_id, false);
+ LLAppearanceMgr::removeCOFItemLinks(item_id, false);
}
else
{
@@ -1733,7 +2272,7 @@ void LLAppearanceManager::unregisterAttachment(const LLUUID& item_id)
}
}
-void LLAppearanceManager::linkRegisteredAttachments()
+void LLAppearanceMgr::linkRegisteredAttachments()
{
for (std::set<LLUUID>::iterator it = mRegisteredAttachments.begin();
it != mRegisteredAttachments.end();
@@ -1745,12 +2284,12 @@ void LLAppearanceManager::linkRegisteredAttachments()
mRegisteredAttachments.clear();
}
-BOOL LLAppearanceManager::getIsInCOF(const LLUUID& obj_id) const
+BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
{
return gInventory.isObjectDescendentOf(obj_id, getCOF());
}
-BOOL LLAppearanceManager::getIsProtectedCOFItem(const LLUUID& obj_id) const
+BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
{
if (!getIsInCOF(obj_id)) return FALSE;