summaryrefslogtreecommitdiff
path: root/indra/newview/llappearancemgr.cpp
diff options
context:
space:
mode:
authorTofu Linden <tofu.linden@lindenlab.com>2010-04-07 13:37:37 +0100
committerTofu Linden <tofu.linden@lindenlab.com>2010-04-07 13:37:37 +0100
commit4533d1b59b2e8fc534ad3de7a896aaa8514fe653 (patch)
tree38b4d2398d66a0e18cd8e4dcd47efba0ad5326a1 /indra/newview/llappearancemgr.cpp
parent92f630871386bafc4548eb9beb45063e40b6139c (diff)
parentadce2ecdf8f3a0efcd4907699d286012124ac496 (diff)
merge from viewer-trunk
Diffstat (limited to 'indra/newview/llappearancemgr.cpp')
-rw-r--r--indra/newview/llappearancemgr.cpp1674
1 files changed, 187 insertions, 1487 deletions
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 04a5bcc256..e0f1d5348d 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2,122 +2,54 @@
* @file llappearancemgr.cpp
* @brief Manager for initiating appearance changes on the viewer
*
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2009, Linden Research, Inc.
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
+ * 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
*
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * 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
*
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * 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.
*
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * 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 "llaccordionctrltab.h"
#include "llagent.h"
-#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llcommandhandler.h"
-#include "lleventtimer.h"
+#include "llfloatercustomize.h"
#include "llgesturemgr.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
-#include "lloutfitobserver.h"
-#include "lloutfitslist.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"
-// RAII thingy to guarantee that a variable gets reset when the Setter
-// goes out of scope. More general utility would be handy - TODO:
-// check boost.
-class BoolSetter
-{
-public:
- BoolSetter(bool& var):
- mVar(var)
- {
- mVar = true;
- }
- ~BoolSetter()
- {
- mVar = false;
- }
-private:
- bool& mVar;
-};
-
-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)
+LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
@@ -184,26 +116,8 @@ private:
bool mAppend;
};
-
-//Inventory callback updating "dirty" state when destroyed
-class LLUpdateDirtyState: public LLInventoryCallback
-{
-public:
- LLUpdateDirtyState() {}
- virtual ~LLUpdateDirtyState()
- {
- if (LLAppearanceMgr::instanceExists())
- {
- LLAppearanceMgr::getInstance()->updateIsDirty();
- }
- }
- virtual void fire(const LLUUID&) {}
-};
-
-
-LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering):
- mFireCount(0),
- mUpdateBaseOrder(update_base_outfit_ordering)
+LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy():
+ mFireCount(0)
{
}
@@ -213,17 +127,13 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
if (!LLApp::isExiting())
{
- LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder);
+ LLAppearanceMgr::instance().updateAppearanceFromCOF();
}
}
void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item)
{
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item);
- const std::string item_name = item ? item->getName() : "ITEM NOT FOUND";
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << llendl;
-#endif
+ llinfos << "callback fired" << llendl;
mFireCount++;
}
@@ -231,31 +141,28 @@ struct LLFoundData
{
LLFoundData() :
mAssetType(LLAssetType::AT_NONE),
- mWearableType(LLWearableType::WT_INVALID),
+ mWearableType(WT_INVALID),
mWearable(NULL) {}
LLFoundData(const LLUUID& item_id,
const LLUUID& asset_id,
const std::string& name,
const LLAssetType::EType& asset_type,
- const LLWearableType::EType& wearable_type,
- const bool is_replacement = false
+ const EWearableType& wearable_type
) :
mItemID(item_id),
mAssetID(asset_id),
mName(name),
mAssetType(asset_type),
mWearableType(wearable_type),
- mIsReplacement(is_replacement),
mWearable( NULL ) {}
LLUUID mItemID;
LLUUID mAssetID;
std::string mName;
LLAssetType::EType mAssetType;
- LLWearableType::EType mWearableType;
+ EWearableType mWearableType;
LLWearable* mWearable;
- bool mIsReplacement;
};
@@ -273,23 +180,13 @@ public:
void checkMissingWearables();
bool pollMissingWearables();
bool isMissingCompleted();
- void recoverMissingWearable(LLWearableType::EType type);
+ void recoverMissingWearable(EWearableType type);
void clearCOFLinksForMissingWearables();
void onWearableAssetFetch(LLWearable *wearable);
void onAllComplete();
-
- typedef std::list<LLFoundData> found_list_t;
- found_list_t& getFoundList();
- void eraseTypeToLink(LLWearableType::EType type);
- void eraseTypeToRecover(LLWearableType::EType type);
- void setObjItems(const LLInventoryModel::item_array_t& items);
- void setGestItems(const LLInventoryModel::item_array_t& items);
- bool isMostRecent();
- void handleLateArrivals();
- void resetTime(F32 timeout);
-private:
+ typedef std::list<LLFoundData> found_list_t;
found_list_t mFoundList;
LLInventoryModel::item_array_t mObjItems;
LLInventoryModel::item_array_t mGestItems;
@@ -299,128 +196,63 @@ private:
S32 mResolved;
LLTimer mWaitTime;
bool mFired;
- typedef std::set<LLWearableHoldingPattern*> type_set_hp;
- static type_set_hp sActiveHoldingPatterns;
- bool mIsMostRecent;
- std::set<LLWearable*> mLateArrivals;
- bool mIsAllComplete;
};
-LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns;
-
LLWearableHoldingPattern::LLWearableHoldingPattern():
mResolved(0),
- mFired(false),
- mIsMostRecent(true),
- mIsAllComplete(false)
+ mFired(false)
{
- if (sActiveHoldingPatterns.size()>0)
- {
- llinfos << "Creating LLWearableHoldingPattern when "
- << sActiveHoldingPatterns.size()
- << " other attempts are active."
- << " Flagging others as invalid."
- << llendl;
- for (type_set_hp::iterator it = sActiveHoldingPatterns.begin();
- it != sActiveHoldingPatterns.end();
- ++it)
- {
- (*it)->mIsMostRecent = false;
- }
-
- }
- sActiveHoldingPatterns.insert(this);
}
LLWearableHoldingPattern::~LLWearableHoldingPattern()
{
- sActiveHoldingPatterns.erase(this);
-}
-
-bool LLWearableHoldingPattern::isMostRecent()
-{
- return mIsMostRecent;
-}
-
-LLWearableHoldingPattern::found_list_t& LLWearableHoldingPattern::getFoundList()
-{
- return mFoundList;
-}
-
-void LLWearableHoldingPattern::eraseTypeToLink(LLWearableType::EType type)
-{
- mTypesToLink.erase(type);
-}
-
-void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type)
-{
- mTypesToRecover.erase(type);
-}
-
-void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items)
-{
- mObjItems = items;
-}
-
-void LLWearableHoldingPattern::setGestItems(const LLInventoryModel::item_array_t& items)
-{
- mGestItems = items;
}
bool LLWearableHoldingPattern::isFetchCompleted()
{
- return (mResolved >= (S32)getFoundList().size()); // have everything we were waiting for?
+ return (mResolved >= (S32)mFoundList.size()); // have everything we were waiting for?
}
bool LLWearableHoldingPattern::isTimedOut()
{
- return mWaitTime.hasExpired();
+ 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()
{
- if (!isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
- 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 = getFoundList().begin(); it != getFoundList().end(); ++it)
+ std::vector<S32> found_by_type(WT_COUNT,0);
+ std::vector<S32> requested_by_type(WT_COUNT,0);
+ for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it)
{
LLFoundData &data = *it;
- if (data.mWearableType < LLWearableType::WT_COUNT)
+ if (data.mWearableType < WT_COUNT)
requested_by_type[data.mWearableType]++;
if (data.mWearable)
found_by_type[data.mWearableType]++;
}
- for (S32 type = 0; type < LLWearableType::WT_COUNT; ++type)
+ for (S32 type = 0; type < WT_COUNT; ++type)
{
- if (requested_by_type[type] > found_by_type[type])
- {
- llwarns << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl;
- }
+ llinfos << "type " << type << " requested " << requested_by_type[type] << " found " << found_by_type[type] << llendl;
if (found_by_type[type] > 0)
continue;
if (
- // 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)))
+ // 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)))
{
mTypesToRecover.insert(type);
mTypesToLink.insert(type);
- recoverMissingWearable((LLWearableType::EType)type);
+ recoverMissingWearable((EWearableType)type);
llwarns << "need to replace " << type << llendl;
}
}
- resetTime(60.0F);
+ mWaitTime.reset();
if (!pollMissingWearables())
{
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this));
@@ -429,11 +261,6 @@ void LLWearableHoldingPattern::checkMissingWearables()
void LLWearableHoldingPattern::onAllComplete()
{
- if (!isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
// Activate all gestures in this folder
if (mGestItems.count() > 0)
{
@@ -469,31 +296,16 @@ void LLWearableHoldingPattern::onAllComplete()
// Only safe to delete if all wearable callbacks and all missing wearables completed.
delete this;
}
- else
- {
- mIsAllComplete = true;
- handleLateArrivals();
- }
}
void LLWearableHoldingPattern::onFetchCompletion()
{
- if (!isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
checkMissingWearables();
}
// Runs as an idle callback until all wearables are fetched (or we time out).
bool LLWearableHoldingPattern::pollFetchCompletion()
{
- if (!isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
bool completed = isFetchCompleted();
bool timed_out = isTimedOut();
bool done = completed || timed_out;
@@ -518,7 +330,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
class RecoveredItemLinkCB: public LLInventoryCallback
{
public:
- RecoveredItemLinkCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
+ RecoveredItemLinkCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
mHolder(holder),
mWearable(wearable),
mType(type)
@@ -526,13 +338,8 @@ public:
}
void fire(const LLUUID& item_id)
{
- if (!mHolder->isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
llinfos << "Recovered item link for type " << mType << llendl;
- mHolder->eraseTypeToLink(mType);
+ mHolder->mTypesToLink.erase(mType);
// Add wearable to FoundData for actual wearing
LLViewerInventoryItem *item = gInventory.getItem(item_id);
LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
@@ -544,14 +351,13 @@ public:
if (item)
{
LLFoundData found(linked_item->getUUID(),
- linked_item->getAssetUUID(),
- linked_item->getName(),
- linked_item->getType(),
- linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID,
- true // is replacement
- );
+ linked_item->getAssetUUID(),
+ linked_item->getName(),
+ linked_item->getType(),
+ linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID
+ );
found.mWearable = mWearable;
- mHolder->getFoundList().push_front(found);
+ mHolder->mFoundList.push_front(found);
}
else
{
@@ -566,13 +372,13 @@ public:
private:
LLWearableHoldingPattern* mHolder;
LLWearable *mWearable;
- LLWearableType::EType mType;
+ EWearableType mType;
};
class RecoveredItemCB: public LLInventoryCallback
{
public:
- RecoveredItemCB(LLWearableType::EType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
+ RecoveredItemCB(EWearableType type, LLWearable *wearable, LLWearableHoldingPattern* holder):
mHolder(holder),
mWearable(wearable),
mType(type)
@@ -580,16 +386,11 @@ public:
}
void fire(const LLUUID& item_id)
{
- if (!mHolder->isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
llinfos << "Recovered item for type " << mType << llendl;
LLViewerInventoryItem *itemp = gInventory.getItem(item_id);
mWearable->setItemID(item_id);
LLPointer<LLInventoryCallback> cb = new RecoveredItemLinkCB(mType,mWearable,mHolder);
- mHolder->eraseTypeToRecover(mType);
+ mHolder->mTypesToRecover.erase(mType);
llassert(itemp);
if (itemp)
{
@@ -597,7 +398,6 @@ public:
item_id,
LLAppearanceMgr::instance().getCOF(),
itemp->getName(),
- itemp->getDescription(),
LLAssetType::AT_LINK,
cb);
}
@@ -605,19 +405,14 @@ public:
private:
LLWearableHoldingPattern* mHolder;
LLWearable *mWearable;
- LLWearableType::EType mType;
+ EWearableType mType;
};
-void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type)
+void LLWearableHoldingPattern::recoverMissingWearable(EWearableType type)
{
- if (!isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
// Try to recover by replacing missing wearable with a new one.
LLNotificationsUtil::add("ReplacedMissingWearable");
- lldebugs << "Wearable " << LLWearableType::getTypeLabel(type)
+ lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type)
<< " could not be downloaded. Replaced inventory item with default wearable." << llendl;
LLWearable* wearable = LLWearableList::instance().createNewWearable(type);
@@ -645,10 +440,10 @@ bool LLWearableHoldingPattern::isMissingCompleted()
void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
{
- for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it)
+ for (found_list_t::iterator it = mFoundList.begin(); it != mFoundList.end(); ++it)
{
LLFoundData &data = *it;
- if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable))
+ if ((data.mWearableType < 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;
@@ -659,144 +454,33 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
bool LLWearableHoldingPattern::pollMissingWearables()
{
- if (!isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
-
bool timed_out = isTimedOut();
bool missing_completed = isMissingCompleted();
bool done = timed_out || missing_completed;
-
- if (!done)
- {
- llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size()
- << " links " << mTypesToLink.size()
- << " wearables, timed out " << timed_out
- << " elapsed " << mWaitTime.getElapsedTimeF32()
- << " done " << done << llendl;
- }
+
+ llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size()
+ << " links " << mTypesToLink.size()
+ << " wearables, timed out " << timed_out
+ << " elapsed " << mWaitTime.getElapsedTimeF32()
+ << " done " << done << llendl;
if (done)
{
- gAgentAvatarp->debugWearablesLoaded();
-
- // BAP - if we don't call clearCOFLinksForMissingWearables()
- // here, we won't have to add the link back in later if the
- // wearable arrives late. This is to avoid corruption of
- // wearable ordering info. Also has the effect of making
- // unworn item links visible in the COF under some
- // circumstances.
-
- //clearCOFLinksForMissingWearables();
+ clearCOFLinksForMissingWearables();
onAllComplete();
}
return done;
}
-// Handle wearables that arrived after the timeout period expired.
-void LLWearableHoldingPattern::handleLateArrivals()
-{
- // Only safe to run if we have previously finished the missing
- // wearables and other processing - otherwise we could be in some
- // intermediate state - but have not been superceded by a later
- // outfit change request.
- if (mLateArrivals.size() == 0)
- {
- // Nothing to process.
- return;
- }
- if (!isMostRecent())
- {
- llwarns << "Late arrivals not handled - outfit change no longer valid" << llendl;
- }
- if (!mIsAllComplete)
- {
- llwarns << "Late arrivals not handled - in middle of missing wearables processing" << llendl;
- }
-
- llinfos << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << llendl;
-
- // Update mFoundList using late-arriving wearables.
- std::set<LLWearableType::EType> replaced_types;
- for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin();
- iter != getFoundList().end(); ++iter)
- {
- LLFoundData& data = *iter;
- for (std::set<LLWearable*>::iterator wear_it = mLateArrivals.begin();
- wear_it != mLateArrivals.end();
- ++wear_it)
- {
- LLWearable *wearable = *wear_it;
-
- if(wearable->getAssetID() == data.mAssetID)
- {
- data.mWearable = wearable;
-
- replaced_types.insert(data.mWearableType);
-
- // BAP - if we didn't call
- // clearCOFLinksForMissingWearables() earlier, we
- // don't need to restore the link here. Fixes
- // wearable ordering problems.
-
- // LLAppearanceMgr::instance().addCOFItemLink(data.mItemID,false);
-
- // BAP failing this means inventory or asset server
- // are corrupted in a way we don't handle.
- llassert((data.mWearableType < LLWearableType::WT_COUNT) && (wearable->getType() == data.mWearableType));
- break;
- }
- }
- }
-
- // Remove COF links for any default wearables previously used to replace the late arrivals.
- // All this pussyfooting around with a while loop and explicit
- // iterator incrementing is to allow removing items from the list
- // without clobbering the iterator we're using to navigate.
- LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin();
- while (iter != getFoundList().end())
- {
- LLFoundData& data = *iter;
-
- // If an item of this type has recently shown up, removed the corresponding replacement wearable from COF.
- if (data.mWearable && data.mIsReplacement &&
- replaced_types.find(data.mWearableType) != replaced_types.end())
- {
- LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID,false);
- std::list<LLFoundData>::iterator clobber_ator = iter;
- ++iter;
- getFoundList().erase(clobber_ator);
- }
- else
- {
- ++iter;
- }
- }
-
- // Clear contents of late arrivals.
- mLateArrivals.clear();
-
- // Update appearance based on mFoundList
- LLAppearanceMgr::instance().updateAgentWearables(this, false);
-}
-
-void LLWearableHoldingPattern::resetTime(F32 timeout)
-{
- mWaitTime.reset();
- mWaitTime.setTimerExpirySec(timeout);
-}
-
void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable)
{
- if (!isMostRecent())
+ mResolved += 1; // just counting callbacks, not successes.
+ llinfos << "onWearableAssetFetch, resolved count " << mResolved << " of requested " << mFoundList.size() << llendl;
+ if (wearable)
{
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llinfos << "wearable found, type " << wearable->getType() << " asset " << wearable->getAssetID() << llendl;
}
-
- mResolved += 1; // just counting callbacks, not successes.
- llinfos << "resolved " << mResolved << "/" << getFoundList().size() << llendl;
- if (!wearable)
+ else
{
llwarns << "no wearable found" << llendl;
}
@@ -804,14 +488,6 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable)
if (mFired)
{
llwarns << "called after holder fired" << llendl;
- if (wearable)
- {
- mLateArrivals.insert(wearable);
- if (mIsAllComplete)
- {
- handleLateArrivals();
- }
- }
return;
}
@@ -820,20 +496,16 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable)
return;
}
- for (LLWearableHoldingPattern::found_list_t::iterator iter = getFoundList().begin();
- iter != getFoundList().end(); ++iter)
+ for (LLWearableHoldingPattern::found_list_t::iterator iter = mFoundList.begin();
+ iter != mFoundList.end(); ++iter)
{
LLFoundData& data = *iter;
if(wearable->getAssetID() == data.mAssetID)
{
- // Failing this means inventory or asset server are corrupted in a way we don't handle.
- if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType))
- {
- llwarns << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl;
- break;
- }
-
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));
+ break;
}
}
}
@@ -900,13 +572,6 @@ const LLViewerInventoryItem* LLAppearanceMgr::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;
}
}
@@ -928,92 +593,6 @@ bool LLAppearanceMgr::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, LLPointer<LLInventoryCallback> cb)
-{
- if (item_id_to_wear.isNull()) return false;
-
- // *TODO: issue with multi-wearable should be fixed:
- // in this case this method will be called N times - loading started for each item
- // and than N times will be called - loading completed for each item.
- // That means subscribers will be notified that loading is done after first item in a batch is worn.
- // (loading indicator disappears for example before all selected items are worn)
- // Have not fix this issue for 2.1 because of stability reason. EXT-7777.
-
- // Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times
-// gAgentWearables.notifyLoadingStarted();
-
- 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;
- }
- else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), LLAppearanceMgr::instance().getCOF())) // EXT-84911
- {
- 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);
- }
- addCOFItemLink(item_to_wear, do_update, cb);
- }
- break;
- case LLAssetType::AT_BODYPART:
- // TODO: investigate wearables may not be loaded at this point EXT-8231
-
- // 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.
- removeCOFLinksOfType(item_to_wear->getWearableType(), false);
-
- addCOFItemLink(item_to_wear, do_update, cb);
- break;
- case LLAssetType::AT_OBJECT:
- rez_attachment(item_to_wear, NULL);
- break;
- default: return false;;
- }
-
- return true;
-}
-
// Update appearance from outfit folder.
void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool append)
{
@@ -1022,90 +601,6 @@ void LLAppearanceMgr::changeOutfit(bool proceed, const LLUUID& category, bool ap
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;
- LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false);
-
- 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 LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb)
@@ -1116,7 +611,6 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds
llwarns << "folder not found for src " << src_id.asString() << llendl;
return;
}
- llinfos << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << llendl;
LLUUID parent_id = dst_id;
if(parent_id.isNull())
{
@@ -1137,7 +631,6 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
LLInventoryModel::cat_array_t* cats;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(src_id, cats, items);
- llinfos << "copying " << items->count() << " items" << llendl;
for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();
iter != items->end();
++iter)
@@ -1147,13 +640,10 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
{
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;
}
@@ -1167,7 +657,6 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
item->getLinkedUUID(),
dst_id,
item->getName(),
- item->getDescription(),
LLAssetType::AT_LINK_FOLDER, cb);
}
break;
@@ -1177,7 +666,6 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_GESTURE:
{
- llinfos << "copying inventory item " << item->getName() << llendl;
copy_inventory_item(gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
@@ -1198,10 +686,10 @@ 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 << LLWearableType::WT_SHAPE;
- required_wearables |= 1LL << LLWearableType::WT_SKIN;
- required_wearables |= 1LL << LLWearableType::WT_HAIR;
- required_wearables |= 1LL << LLWearableType::WT_EYES;
+ required_wearables |= 1LL << WT_SHAPE;
+ required_wearables |= 1LL << WT_SKIN;
+ required_wearables |= 1LL << WT_HAIR;
+ required_wearables |= 1LL << WT_EYES;
// These are the wearables that the folder actually contains.
U32 folder_wearables = 0;
@@ -1215,7 +703,7 @@ BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
const LLViewerInventoryItem* item = (*iter);
if (item->isWearableType())
{
- const LLWearableType::EType wearable_type = item->getWearableType();
+ const EWearableType wearable_type = item->getWearableType();
folder_wearables |= 1LL << wearable_type;
}
}
@@ -1224,92 +712,6 @@ BOOL LLAppearanceMgr::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;
-}
-
-// static
-bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)
-{
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false);
- gInventory.collectDescendentsIf(outfit_cat_id,
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_worn);
- return items.size() > 0;
-}
-
-// static
-bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)
-{
- if (gAgentWearables.isCOFChangeInProgress())
- {
- return false;
- }
-
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
- gInventory.collectDescendentsIf(outfit_cat_id,
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- not_worn);
- return items.size() > 0;
-}
-
-bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
-{
- // Don't allow wearing anything while we're changing appearance.
- if (gAgentWearables.isCOFChangeInProgress())
- {
- return false;
- }
-
- // Check whether it's the base outfit.
- if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID())
- {
- return false;
- }
-
- // Check whether the outfit contains any non-worn wearables.
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ true);
- gInventory.collectDescendentsIf(outfit_cat_id,
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- not_worn);
- return items.size() > 0;
-}
void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
{
@@ -1357,12 +759,25 @@ 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(LLWearableType::WT_COUNT);
- divvyWearablesByType(items, items_by_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);
+ }
// rebuild items list, retaining the last max_per_type of each array
items.clear();
- for (S32 i=0; i<LLWearableType::WT_COUNT; i++)
+ for (S32 i=0; i<WT_COUNT; i++)
{
S32 size = items_by_type[i].size();
if (size <= 0)
@@ -1376,7 +791,7 @@ void LLAppearanceMgr::filterWearableItems(
}
// Create links to all listed items.
-void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
+void LLAppearanceMgr::linkAll(const LLUUID& category,
LLInventoryModel::item_array_t& items,
LLPointer<LLInventoryCallback> cb)
{
@@ -1385,17 +800,10 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
const LLInventoryItem* item = items.get(i).get();
link_inventory_item(gAgent.getID(),
item->getLinkedUUID(),
- cat_uuid,
+ category,
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";
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << llendl;
-#endif
}
}
@@ -1425,12 +833,9 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
// - Body parts: always include COF contents as a fallback in case any
// required parts are missing.
- // Preserve body parts from COF if appending.
LLInventoryModel::item_array_t body_items;
getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false);
getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false);
- if (append)
- reverse(body_items.begin(), body_items.end());
// Reduce body items to max of one per type.
removeDuplicateItems(body_items);
filterWearableItems(body_items, 1);
@@ -1442,7 +847,7 @@ void LLAppearanceMgr::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, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
+ filterWearableItems(wear_items, 5);
// - Attachments: include COF contents only if appending.
LLInventoryModel::item_array_t obj_items;
@@ -1465,26 +870,11 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
// Create links to new COF contents.
llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl;
- LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(!append);
+ LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "Linking body items" << llendl;
-#endif
linkAll(cof, body_items, link_waiter);
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "Linking wear items" << llendl;
-#endif
linkAll(cof, wear_items, link_waiter);
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "Linking obj items" << llendl;
-#endif
linkAll(cof, obj_items, link_waiter);
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "Linking gesture items" << llendl;
-#endif
linkAll(cof, gest_items, link_waiter);
// Add link to outfit if category is an outfit.
@@ -1515,7 +905,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI
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();
}
@@ -1529,17 +919,19 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
LLInventoryItem::item_array_t items;
LLDynamicArray< LLWearable* > wearables;
- // For each wearable type, find the wearables of that type.
- for( S32 i = 0; i < LLWearableType::WT_COUNT; i++ )
+ // 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->getFoundList().begin();
- iter != holder->getFoundList().end(); ++iter)
+ 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 = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
+ LLViewerInventoryItem* item;
+ item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
if( item && (item->getAssetUUID() == wearable->getAssetID()) )
{
items.put(item);
@@ -1573,104 +965,15 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items)
items = pruned_items;
}
-//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 item_array_diff(LLInventoryModel::item_array_t& full_list,
- LLInventoryModel::item_array_t& keep_list,
- LLInventoryModel::item_array_t& kill_list)
-
-{
- for (LLInventoryModel::item_array_t::iterator it = full_list.begin();
- it != full_list.end();
- ++it)
- {
- LLViewerInventoryItem *item = *it;
- if (keep_list.find(item) < 0) // Why on earth does LLDynamicArray need to redefine find()?
- {
- kill_list.push_back(item);
- }
- }
-}
-
-void LLAppearanceMgr::enforceItemCountLimits()
-{
- S32 purge_count = 0;
-
- LLInventoryModel::item_array_t body_items;
- getDescendentsOfAssetType(getCOF(), body_items, LLAssetType::AT_BODYPART, false);
- LLInventoryModel::item_array_t curr_body_items = body_items;
- removeDuplicateItems(body_items);
- filterWearableItems(body_items, 1);
- LLInventoryModel::item_array_t kill_body_items;
- item_array_diff(curr_body_items,body_items,kill_body_items);
- for (LLInventoryModel::item_array_t::iterator it = kill_body_items.begin();
- it != kill_body_items.end();
- ++it)
- {
- LLViewerInventoryItem *item = *it;
- llinfos << "purging dup body part " << item->getName() << llendl;
- gInventory.purgeObject(item->getUUID());
- purge_count++;
- }
-
- LLInventoryModel::item_array_t wear_items;
- getDescendentsOfAssetType(getCOF(), wear_items, LLAssetType::AT_CLOTHING, false);
- LLInventoryModel::item_array_t curr_wear_items = wear_items;
- removeDuplicateItems(wear_items);
- filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
- LLInventoryModel::item_array_t kill_wear_items;
- item_array_diff(curr_wear_items,wear_items,kill_wear_items);
- for (LLInventoryModel::item_array_t::iterator it = kill_wear_items.begin();
- it != kill_wear_items.end();
- ++it)
- {
- LLViewerInventoryItem *item = *it;
- llinfos << "purging excess clothing item " << item->getName() << llendl;
- gInventory.purgeObject(item->getUUID());
- purge_count++;
- }
-
- if (purge_count>0)
- {
- gInventory.notifyObservers();
- }
-}
-
-void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
+void LLAppearanceMgr::updateAppearanceFromCOF()
{
- if (mIsInUpdateAppearanceFromCOF)
- {
- llwarns << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << llendl;
- return;
- }
-
- BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF);
-
- llinfos << "starting" << llendl;
-
- //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(LLUUID::null, update_base_outfit_ordering);
-
- // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
- // this should catch anything that gets through.
- enforceItemCountLimits();
-
// update dirty flag to see if the state of the COF matches
// the saved outfit stored as a folder link
+ llinfos << "starting" << llendl;
+
updateIsDirty();
- //dumpCat(getCOF(),"COF, start");
+ dumpCat(getCOF(),"COF, start");
bool follow_folder_links = true;
LLUUID current_outfit_id = getCOF();
@@ -1686,23 +989,16 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
remove_non_link_items(obj_items);
remove_non_link_items(gest_items);
- dumpItemArray(wear_items,"asset_dump: wear_item");
- dumpItemArray(obj_items,"asset_dump: obj_item");
-
if(!wear_items.count())
{
LLNotificationsUtil::add("CouldNotPutOnOutfit");
return;
}
- //preparing the list of wearables in the correct order for LLAgentWearables
- sortItemsByActualDescription(wear_items);
-
-
LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
- holder->setObjItems(obj_items);
- holder->setGestItems(gest_items);
+ holder->mObjItems = obj_items;
+ holder->mGestItems = gest_items;
// Note: can't do normal iteration, because if all the
// wearables can be resolved immediately, then the
@@ -1713,27 +1009,27 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
{
LLViewerInventoryItem *item = wear_items.get(i);
LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
-
- // Fault injection: use debug setting to test asset
- // fetch failures (should be replaced by new defaults in
- // lost&found).
- U32 skip_type = gSavedSettings.getU32("ForceAssetFail");
-
if (item && item->getIsLinkType() && linked_item)
{
LLFoundData found(linked_item->getUUID(),
linked_item->getAssetUUID(),
linked_item->getName(),
linked_item->getType(),
- linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID
+ linked_item->isWearableType() ? linked_item->getWearableType() : WT_INVALID
);
- if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType)
+#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)
{
found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB
+
}
- //pushing back, not front, to preserve order of wearables for LLAgentWearables
- holder->getFoundList().push_back(found);
+#endif
+
+ holder->mFoundList.push_front(found);
}
else
{
@@ -1748,12 +1044,12 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
}
}
- for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin();
- it != holder->getFoundList().end(); ++it)
+ for (LLWearableHoldingPattern::found_list_t::iterator it = holder->mFoundList.begin();
+ it != holder->mFoundList.end(); ++it)
{
LLFoundData& found = *it;
- lldebugs << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl;
+ llinfos << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl;
// Fetch the wearables about to be worn.
LLWearableList::instance().getAsset(found.mAssetID,
@@ -1764,7 +1060,6 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
}
- holder->resetTime(gSavedSettings.getF32("MaxWearableWaitTime"));
if (!holder->pollFetchCompletion())
{
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder));
@@ -1825,14 +1120,12 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
{
if(!category) return;
- gAgentWearables.notifyLoadingStarted();
-
llinfos << "wearInventoryCategory( " << category->getName()
<< " )" << llendl;
- callAfterCategoryFetch(category->getUUID(), boost::bind(&LLAppearanceMgr::wearCategoryFinal,
- &LLAppearanceMgr::instance(),
- category->getUUID(), copy, append));
+ callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
+ &LLAppearanceMgr::instance(),
+ category->getUUID(), copy, append));
}
void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append)
@@ -1923,13 +1216,16 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
llinfos << "wearInventoryCategoryOnAvatar( " << category->getName()
<< " )" << llendl;
- if (gAgentCamera.cameraCustomizeAvatar())
+ if( gFloaterCustomize )
{
- // switching to outfit editor should automagically save any currently edited wearable
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
+ gFloaterCustomize->askToSaveIfDirty(boost::bind(&LLAppearanceMgr::changeOutfit,
+ &LLAppearanceMgr::instance(),
+ _1, category->getUUID(), append));
+ }
+ else
+ {
+ LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);
}
-
- LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);
}
void LLAppearanceMgr::wearOutfitByName(const std::string& name)
@@ -1988,10 +1284,9 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor
class LLDeferredCOFLinkObserver: public LLInventoryObserver
{
public:
- LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL):
+ LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update):
mItemID(item_id),
- mDoUpdate(do_update),
- mCallback(cb)
+ mDoUpdate(do_update)
{
}
@@ -2005,7 +1300,7 @@ public:
if (item)
{
gInventory.removeObserver(this);
- LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback);
+ LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate);
delete this;
}
}
@@ -2013,27 +1308,26 @@ public:
private:
const LLUUID mItemID;
bool mDoUpdate;
- LLPointer<LLInventoryCallback> mCallback;
};
// 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, LLPointer<LLInventoryCallback> cb)
+void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update )
{
const LLInventoryItem *item = gInventory.getItem(item_id);
if (!item)
{
- LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb);
+ LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update);
gInventory.addObserver(observer);
}
else
{
- addCOFItemLink(item, do_update, cb);
+ addCOFItemLink(item, do_update);
}
}
-void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb)
+void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update )
{
const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);
if (!vitem)
@@ -2051,39 +1345,25 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
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 body part
+ // Are these links to different items of the same wearable
// type? If so, new item will replace old.
- else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type))
+ // MULTI-WEARABLES: revisit if more than one per type is allowed.
+ else if (areMatchingWearables(vitem,inv_item))
{
- ++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)
+ if (inv_item->getIsLinkType())
{
- // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE
gInventory.purgeObject(inv_item->getUUID());
}
}
}
-
if (linked_already)
{
if (do_update)
@@ -2094,16 +1374,11 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
}
else
{
- if(do_update && cb.isNull())
- {
- cb = new ModifiedCOFCallback;
- }
- const std::string description = vitem->getIsLinkType() ? vitem->getDescription() : "";
+ LLPointer<LLInventoryCallback> cb = do_update ? new ModifiedCOFCallback : 0;
link_inventory_item( gAgent.getID(),
vitem->getLinkedUUID(),
getCOF(),
vitem->getName(),
- description,
LLAssetType::AT_LINK,
cb);
}
@@ -2120,7 +1395,6 @@ void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update
cat->getLinkedUUID(),
getCOF(),
cat->getName(),
- cat->getDescription(),
LLAssetType::AT_LINK_FOLDER,
cb);
#endif
@@ -2150,40 +1424,6 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, bool do_update)
}
}
-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();
@@ -2208,45 +1448,48 @@ void LLAppearanceMgr::updateIsDirty()
}
else
{
- LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK);
-
LLInventoryModel::cat_array_t cof_cats;
LLInventoryModel::item_array_t cof_items;
- gInventory.collectDescendentsIf(cof, cof_cats, cof_items,
- LLInventoryModel::EXCLUDE_TRASH, collector);
+ gInventory.collectDescendents(cof, cof_cats, cof_items,
+ LLInventoryModel::EXCLUDE_TRASH);
LLInventoryModel::cat_array_t outfit_cats;
LLInventoryModel::item_array_t outfit_items;
- gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items,
- LLInventoryModel::EXCLUDE_TRASH, collector);
+ gInventory.collectDescendents(base_outfit, outfit_cats, outfit_items,
+ LLInventoryModel::EXCLUDE_TRASH);
- if(outfit_items.count() != cof_items.count())
+ if(outfit_items.count() != cof_items.count() -1)
{
// 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;
}
-
- //"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)
+ else
{
- LLViewerInventoryItem *item1 = cof_items.get(i);
- LLViewerInventoryItem *item2 = outfit_items.get(i);
+ typedef std::set<LLUUID> item_set_t;
+ item_set_t cof_set;
+ item_set_t outfit_set;
- if (item1->getLinkedUUID() != item2->getLinkedUUID() ||
- item1->getName() != item2->getName() ||
- item1->LLInventoryItem::getDescription() != item2->LLInventoryItem::getDescription())
+ // sort COF items by UUID
+ for (S32 i = 0; i < cof_items.count(); ++i)
{
- mOutfitIsDirty = true;
- return;
+ 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());
+ }
}
- }
- mOutfitIsDirty = false;
+ // sort outfit folder by UUID
+ for (S32 i = 0; i < outfit_items.count(); ++i)
+ {
+ LLViewerInventoryItem *item = outfit_items.get(i);
+ outfit_set.insert(item->getLinkedUUID());
+ }
+
+ mOutfitIsDirty = (outfit_set != cof_set);
+ }
}
}
@@ -2270,331 +1513,9 @@ void LLAppearanceMgr::autopopulateOutfits()
// 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);
-
- gAgentWearables.notifyLoadingStarted();
-
- 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, bool update_base_outfit_ordering)
-{
- if (cat_id.isNull())
- {
- cat_id = getCOF();
- if (update_base_outfit_ordering)
- {
- const LLUUID base_outfit_id = getBaseOutfitUUID();
- if (base_outfit_id.notNull())
- {
- updateClothingOrderingInfo(base_outfit_id,false);
- }
- }
- }
-
- // 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);
- }
- LLOutfitsList *outfits_list =
- dynamic_cast<LLOutfitsList*>(LLSideTray::getInstance()->getPanel("outfitslist_tab"));
- if (outfits_list)
- {
- outfits_list->setSelectedOutfitByUUID(mFolderID);
- }
-
- LLAppearanceMgr::getInstance()->updateIsDirty();
- gAgentWearables.notifyLoadingFinished(); // New outfit is saved.
- 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;
-
- gAgentWearables.notifyLoadingStarted();
-
- // 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;
- }
-
- // *HACK: Force to remove garbage from COF.
- // Unworn links or objects can't be processed by existed removing functionality
- // since it is not designed for such cases. As example attachment object can't be removed
- // since sever don't sends message _PREHASH_KillObject in that case.
- // Also we can't check is link was successfully removed from COF since in case
- // deleting attachment link removing performs asynchronously in process_kill_object callback.
- removeCOFItemLinks(id_to_remove,false);
-}
-
-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 LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg)
@@ -2621,33 +1542,19 @@ void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg)
void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,
const std::string& msg)
{
+ llinfos << msg << llendl;
for (S32 i=0; i<items.count(); i++)
{
LLViewerInventoryItem *item = items.get(i);
- LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
- LLUUID asset_id;
- if (linked_item)
- {
- asset_id = linked_item->getAssetUUID();
- }
- llinfos << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << llendl;
+ llinfos << i <<" " << item->getName() << llendl;
}
llinfos << llendl;
}
LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
- mOutfitIsDirty(false),
- mIsInUpdateAppearanceFromCOF(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")));
}
LLAppearanceMgr::~LLAppearanceMgr()
@@ -2685,9 +1592,6 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
if (mAttachmentInvLinkEnabled)
{
- // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF.
- // it will trigger gAgentWariables.notifyLoadingFinished()
- // But it is not acceptable solution. See EXT-7777
LLAppearanceMgr::addCOFItemLink(item_id, false); // Add COF link for item.
}
else
@@ -2728,21 +1632,6 @@ BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
return gInventory.isObjectDescendentOf(obj_id, getCOF());
}
-// static
-bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id)
-{
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id));
- gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(),
- cats,
- items,
- LLInventoryModel::EXCLUDE_TRASH,
- find_links);
-
- return !items.empty();
-}
-
BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
{
if (!getIsInCOF(obj_id)) return FALSE;
@@ -2770,192 +1659,3 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
return FALSE;
*/
}
-
-// Shim class to allow arbitrary boost::bind
-// expressions to be run as one-time idle callbacks.
-//
-// TODO: rework idle function spec to take a boost::function in the first place.
-class OnIdleCallbackOneTime
-{
-public:
- OnIdleCallbackOneTime(nullary_func_t callable):
- mCallable(callable)
- {
- }
- static void onIdle(void *data)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data);
- self->call();
- delete self;
- }
- void call()
- {
- mCallable();
- }
-private:
- nullary_func_t mCallable;
-};
-
-void doOnIdleOneTime(nullary_func_t callable)
-{
- OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor);
-}
-
-// Shim class to allow generic boost functions to be run as
-// recurring idle callbacks. Callable should return true when done,
-// false to continue getting called.
-//
-// TODO: rework idle function spec to take a boost::function in the first place.
-class OnIdleCallbackRepeating
-{
-public:
- OnIdleCallbackRepeating(bool_func_t callable):
- mCallable(callable)
- {
- }
- // Will keep getting called until the callable returns true.
- static void onIdle(void *data)
- {
- OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data);
- bool done = self->call();
- if (done)
- {
- gIdleCallbacks.deleteFunction(onIdle, data);
- delete self;
- }
- }
- bool call()
- {
- return mCallable();
- }
-private:
- bool_func_t mCallable;
-};
-
-void doOnIdleRepeating(bool_func_t callable)
-{
- OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable);
- gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
-}
-
-class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver
-{
-public:
- CallAfterCategoryFetchStage2(const uuid_vec_t& ids,
- nullary_func_t callable) :
- LLInventoryFetchItemsObserver(ids),
- mCallable(callable)
- {
- }
- ~CallAfterCategoryFetchStage2()
- {
- }
- virtual void done()
- {
- llinfos << this << " done with incomplete " << mIncomplete.size()
- << " complete " << mComplete.size() << " calling callable" << llendl;
-
- gInventory.removeObserver(this);
- doOnIdleOneTime(mCallable);
- delete this;
- }
-protected:
- nullary_func_t mCallable;
-};
-
-class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver
-{
-public:
- CallAfterCategoryFetchStage1(const LLUUID& cat_id, nullary_func_t callable) :
- LLInventoryFetchDescendentsObserver(cat_id),
- mCallable(callable)
- {
- }
- ~CallAfterCategoryFetchStage1()
- {
- }
- virtual void 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(mComplete.front(),
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH);
- S32 count = item_array.count();
- if(!count)
- {
- llwarns << "Nothing fetched in category " << mComplete.front()
- << llendl;
- //dec_busy_count();
- gInventory.removeObserver(this);
-
- // lets notify observers that loading is finished.
- gAgentWearables.notifyLoadingFinished();
- delete this;
- return;
- }
-
- llinfos << "stage1 got " << item_array.count() << " items, passing to stage2 " << llendl;
- uuid_vec_t ids;
- for(S32 i = 0; i < count; ++i)
- {
- ids.push_back(item_array.get(i)->getUUID());
- }
-
- gInventory.removeObserver(this);
-
- // do the fetch
- CallAfterCategoryFetchStage2 *stage2 = new CallAfterCategoryFetchStage2(ids, mCallable);
- stage2->startFetch();
- if(stage2->isFinished())
- {
- // everything is already here - call done.
- stage2->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(stage2);
- }
- delete this;
- }
-protected:
- nullary_func_t mCallable;
-};
-
-void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb)
-{
- CallAfterCategoryFetchStage1 *stage1 = new CallAfterCategoryFetchStage1(cat_id, cb);
- stage1->startFetch();
- if (stage1->isFinished())
- {
- stage1->done();
- }
- else
- {
- gInventory.addObserver(stage1);
- }
-}
-
-void wear_multiple(const uuid_vec_t& ids, bool replace)
-{
- LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
-
- bool first = true;
- uuid_vec_t::const_iterator it;
- for (it = ids.begin(); it != ids.end(); ++it)
- {
- // if replace is requested, the first item worn will replace the current top
- // item, and others will be added.
- LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb);
- first = false;
- }
-}
-