477 lines
11 KiB
C++
477 lines
11 KiB
C++
/**
|
|
* @file llinventoryfunctions.cpp
|
|
* @brief Implementation of the inventory view and associated stuff.
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include <utility> // for std::pair<>
|
|
|
|
#include "llinventoryfunctions.h"
|
|
|
|
// library includes
|
|
#include "llagent.h"
|
|
#include "llagentwearables.h"
|
|
#include "llcallingcard.h"
|
|
#include "llinventorydefines.h"
|
|
#include "llsdserialize.h"
|
|
#include "llspinctrl.h"
|
|
#include "llui.h"
|
|
#include "message.h"
|
|
|
|
// newview includes
|
|
#include "llappviewer.h"
|
|
//#include "llfirstuse.h"
|
|
#include "llfocusmgr.h"
|
|
#include "llfolderview.h"
|
|
#include "llgesturemgr.h"
|
|
#include "lliconctrl.h"
|
|
#include "llimview.h"
|
|
#include "llinventorybridge.h"
|
|
#include "llinventoryclipboard.h"
|
|
#include "llinventorymodel.h"
|
|
#include "llinventoryview.h"
|
|
#include "lllineeditor.h"
|
|
#include "llmenugl.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "llpreviewanim.h"
|
|
#include "llpreviewgesture.h"
|
|
#include "llpreviewnotecard.h"
|
|
#include "llpreviewscript.h"
|
|
#include "llpreviewsound.h"
|
|
#include "llpreviewtexture.h"
|
|
#include "llresmgr.h"
|
|
#include "llscrollbar.h"
|
|
#include "llscrollcontainer.h"
|
|
#include "llselectmgr.h"
|
|
#include "lltabcontainer.h"
|
|
#include "lltooldraganddrop.h"
|
|
#include "lluictrlfactory.h"
|
|
#include "llviewermessage.h"
|
|
#include "llviewerobjectlist.h"
|
|
#include "llviewerregion.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llvoavatarself.h"
|
|
#include "llwearablelist.h"
|
|
|
|
#include "cofmgr.h"
|
|
|
|
BOOL LLInventoryState::sWearNewClothing = FALSE;
|
|
LLUUID LLInventoryState::sWearNewClothingTransactionID;
|
|
|
|
// Generates a string containing the path to the item specified by
|
|
// item_id.
|
|
void append_path(const LLUUID& id, std::string& path)
|
|
{
|
|
std::string temp;
|
|
LLInventoryObject* obj = gInventory.getObject(id);
|
|
LLUUID parent_id;
|
|
if(obj) parent_id = obj->getParentUUID();
|
|
std::string forward_slash("/");
|
|
while(obj)
|
|
{
|
|
obj = gInventory.getCategory(parent_id);
|
|
if(obj)
|
|
{
|
|
temp.assign(forward_slash + obj->getName() + temp);
|
|
parent_id = obj->getParentUUID();
|
|
}
|
|
}
|
|
path.append(temp);
|
|
}
|
|
|
|
void change_item_parent(LLInventoryModel* model,
|
|
LLViewerInventoryItem* item,
|
|
const LLUUID& new_parent_id,
|
|
BOOL restamp)
|
|
{
|
|
if (item->getParentUUID() != new_parent_id)
|
|
{
|
|
LLInventoryModel::update_list_t update;
|
|
LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
|
|
update.push_back(old_folder);
|
|
LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
|
|
update.push_back(new_folder);
|
|
gInventory.accountForUpdate(update);
|
|
|
|
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
|
|
new_item->setParent(new_parent_id);
|
|
new_item->updateParentOnServer(restamp);
|
|
model->updateItem(new_item);
|
|
model->notifyObservers();
|
|
}
|
|
}
|
|
|
|
void change_category_parent(LLInventoryModel* model,
|
|
LLViewerInventoryCategory* cat,
|
|
const LLUUID& new_parent_id,
|
|
BOOL restamp)
|
|
{
|
|
if (!model || !cat)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Can't move a folder into a child of itself.
|
|
if (model->isObjectDescendentOf(new_parent_id, cat->getUUID()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLInventoryModel::update_list_t update;
|
|
LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
|
|
update.push_back(old_folder);
|
|
LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
|
|
update.push_back(new_folder);
|
|
model->accountForUpdate(update);
|
|
|
|
LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
|
|
new_cat->setParent(new_parent_id);
|
|
new_cat->updateParentOnServer(restamp);
|
|
model->updateCategory(new_cat);
|
|
model->notifyObservers();
|
|
}
|
|
|
|
class LLInventoryCollectAllItems : public LLInventoryCollectFunctor
|
|
{
|
|
public:
|
|
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
|
|
BOOL get_is_parent_to_worn_item(const LLUUID& id)
|
|
{
|
|
const LLViewerInventoryCategory* cat = gInventory.getCategory(id);
|
|
if (!cat)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LLInventoryModel::cat_array_t cats;
|
|
LLInventoryModel::item_array_t items;
|
|
LLInventoryCollectAllItems collect_all;
|
|
gInventory.collectDescendentsIf(LLCOFMgr::instance().getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH, collect_all);
|
|
|
|
for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it)
|
|
{
|
|
const LLViewerInventoryItem * const item = *it;
|
|
|
|
llassert(item->getIsLinkType());
|
|
|
|
LLUUID linked_id = item->getLinkedUUID();
|
|
const LLViewerInventoryItem * const linked_item = gInventory.getItem(linked_id);
|
|
|
|
if (linked_item)
|
|
{
|
|
LLUUID parent_id = linked_item->getParentUUID();
|
|
|
|
while (!parent_id.isNull())
|
|
{
|
|
LLInventoryCategory * parent_cat = gInventory.getCategory(parent_id);
|
|
|
|
if (cat == parent_cat)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
parent_id = parent_cat->getParentUUID();
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
BOOL get_is_item_worn(const LLInventoryItem *item)
|
|
{
|
|
if (!item)
|
|
return FALSE;
|
|
|
|
// Consider the item as worn if it has links in COF.
|
|
if (LLCOFMgr::instance().isLinkInCOF(item->getUUID()))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
switch(item->getType())
|
|
{
|
|
case LLAssetType::AT_OBJECT:
|
|
{
|
|
if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID()))
|
|
return TRUE;
|
|
break;
|
|
}
|
|
case LLAssetType::AT_BODYPART:
|
|
case LLAssetType::AT_CLOTHING:
|
|
if(gAgentWearables.isWearingItem(item->getLinkedUUID()))
|
|
return TRUE;
|
|
break;
|
|
case LLAssetType::AT_GESTURE:
|
|
if (LLGestureMgr::instance().isGestureActive(item->getLinkedUUID()))
|
|
return TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL get_is_item_worn(const LLUUID& id)
|
|
{
|
|
return get_is_item_worn(gInventory.getItem(id));
|
|
}
|
|
|
|
BOOL get_can_item_be_worn(const LLUUID& id)
|
|
{
|
|
const LLViewerInventoryItem* item = gInventory.getItem(id);
|
|
if (!item)
|
|
return FALSE;
|
|
|
|
if (LLCOFMgr::instance().isLinkInCOF(item->getLinkedUUID()))
|
|
{
|
|
// an item having links in COF (i.e. a worn item)
|
|
return FALSE;
|
|
}
|
|
|
|
if (gInventory.isObjectDescendentOf(id, LLCOFMgr::instance().getCOF()))
|
|
{
|
|
// a non-link object in COF (should not normally happen)
|
|
return FALSE;
|
|
}
|
|
|
|
const LLUUID trash_id = gInventory.findCategoryUUIDForType(
|
|
LLFolderType::FT_TRASH);
|
|
|
|
// item can't be worn if base obj in trash, see EXT-7015
|
|
if (gInventory.isObjectDescendentOf(item->getLinkedUUID(),
|
|
trash_id))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch(item->getType())
|
|
{
|
|
case LLAssetType::AT_OBJECT:
|
|
{
|
|
if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getLinkedUUID()))
|
|
{
|
|
// Already being worn
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Not being worn yet.
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
case LLAssetType::AT_BODYPART:
|
|
case LLAssetType::AT_CLOTHING:
|
|
if(gAgentWearables.isWearingItem(item->getLinkedUUID()))
|
|
{
|
|
// Already being worn
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Not being worn yet.
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
///----------------------------------------------------------------------------
|
|
/// LLInventoryCollectFunctor implementations
|
|
///----------------------------------------------------------------------------
|
|
|
|
// static
|
|
bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryItem* item)
|
|
{
|
|
if (!item)
|
|
return false;
|
|
|
|
switch(item->getType())
|
|
{
|
|
case LLAssetType::AT_OBJECT:
|
|
case LLAssetType::AT_BODYPART:
|
|
case LLAssetType::AT_CLOTHING:
|
|
if (!get_is_item_worn(item->getUUID()))
|
|
return true;
|
|
break;
|
|
default:
|
|
return true;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
if(mType == LLAssetType::AT_CATEGORY)
|
|
{
|
|
if(cat) return TRUE;
|
|
}
|
|
if(item)
|
|
{
|
|
if(item->getType() == mType) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
if(mType == LLAssetType::AT_CATEGORY)
|
|
{
|
|
if(cat) return FALSE;
|
|
}
|
|
if(item)
|
|
{
|
|
if(item->getType() == mType) return FALSE;
|
|
else return TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
if(mType == LLAssetType::AT_CATEGORY)
|
|
{
|
|
if(cat) return TRUE;
|
|
}
|
|
if(item)
|
|
{
|
|
if(item->getActualType() == mType) return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
if(mType == LLAssetType::AT_CATEGORY)
|
|
{
|
|
if(cat)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
if(item)
|
|
{
|
|
if(item->getType() == mType)
|
|
{
|
|
LLPermissions perm = item->getPermissions();
|
|
if ((perm.getMaskBase() & mPerm) == mPerm)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
|
|
LLInventoryItem* item)
|
|
{
|
|
if(item)
|
|
{
|
|
if((LLAssetType::AT_CALLINGCARD == item->getType())
|
|
&& (!item->getCreatorUUID().isNull())
|
|
&& (item->getCreatorUUID() != gAgent.getID()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat,
|
|
LLInventoryItem* item)
|
|
{
|
|
if(item)
|
|
{
|
|
if((LLAssetType::AT_CALLINGCARD == item->getType())
|
|
&& (item->getCreatorUUID().notNull())
|
|
&& (item->getCreatorUUID() != gAgent.getID()))
|
|
{
|
|
mSeen.insert(item->getCreatorUUID());
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat,
|
|
LLInventoryItem* item)
|
|
{
|
|
if(item)
|
|
{
|
|
if((LLAssetType::AT_CALLINGCARD == item->getType())
|
|
&& (item->getCreatorUUID() == mBuddyID))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
bool LLNameCategoryCollector::operator()(
|
|
LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
if(cat)
|
|
{
|
|
if (!LLStringUtil::compareInsensitive(mName, cat->getName()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
///----------------------------------------------------------------------------
|
|
/// LLAssetIDMatches
|
|
///----------------------------------------------------------------------------
|
|
bool LLAssetIDMatches ::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
return (item && item->getAssetUUID() == mAssetID);
|
|
}
|
|
|
|
///----------------------------------------------------------------------------
|
|
/// LLLinkedItemIDMatches
|
|
///----------------------------------------------------------------------------
|
|
bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
|
|
{
|
|
return (item &&
|
|
(item->getIsLinkType()) &&
|
|
(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
|
|
} |