diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index fc402c862..7c927fd12 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -290,8 +290,10 @@ set(viewer_SOURCE_FILES llinventorybackup.cpp llinventorybridge.cpp llinventoryclipboard.cpp + llinventoryfunctions.cpp llinventoryicon.cpp llinventorymodel.cpp + llinventoryobserver.cpp llinventoryview.cpp lljoystickbutton.cpp lllandmarklist.cpp @@ -759,8 +761,10 @@ set(viewer_HEADER_FILES llinventorybackup.h llinventorybridge.h llinventoryclipboard.h + llinventoryfunctions.h llinventoryicon.h llinventorymodel.h + llinventoryobserver.h llinventoryview.h lljoystickbutton.h lllandmarklist.h diff --git a/indra/newview/cofmgr.cpp b/indra/newview/cofmgr.cpp index 9de7025f9..bac05e2ff 100644 --- a/indra/newview/cofmgr.cpp +++ b/indra/newview/cofmgr.cpp @@ -20,6 +20,8 @@ #include "llagentwearables.h" #include "llcommonutils.h" #include "llerror.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" #include "llvoavatarself.h" #include "rlvviewer2.h" diff --git a/indra/newview/floaterao.cpp b/indra/newview/floaterao.cpp index 083891fe8..3d3ee5847 100644 --- a/indra/newview/floaterao.cpp +++ b/indra/newview/floaterao.cpp @@ -25,6 +25,7 @@ #include "llfirstuse.h" #include "llinventory.h" +#include "llinventoryfunctions.h" #include "llinventoryview.h" #include "roles_constants.h" #include "llviewerregion.h" diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index ac42bfce2..9fdb2bea4 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -52,7 +52,8 @@ #include "llsliderctrl.h" #include "lltabcontainervertical.h" #include "llviewerwindow.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" #include "llinventoryicon.h" #include "lltextbox.h" #include "lllineeditor.h" @@ -1041,7 +1042,7 @@ void LLPanelEditWearable::draw() std::string path; const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType() ); - gInventory.appendPath(item_id, path); + append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -1054,7 +1055,7 @@ void LLPanelEditWearable::draw() std::string path; const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType() ); - gInventory.appendPath(item_id, path); + append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -2785,7 +2786,7 @@ public: void LLFloaterCustomize::fetchInventory() { // Fetch currently worn items - LLInventoryFetchObserver::item_ref_t ids; + uuid_vec_t ids; LLUUID item_id; for(S32 type = (S32)LLWearableType::WT_SHAPE; type < (S32)LLWearableType::WT_COUNT; ++type) { diff --git a/indra/newview/llfloaterlandmark.cpp b/indra/newview/llfloaterlandmark.cpp index 581ee481d..f9b81bbe5 100644 --- a/indra/newview/llfloaterlandmark.cpp +++ b/indra/newview/llfloaterlandmark.cpp @@ -40,7 +40,7 @@ #include "llviewerparcelmgr.h" #include "llfolderview.h" #include "llinventory.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryview.h" #include "llviewerinventory.h" #include "llpermissions.h" diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index fb66019d8..6e1db8a0a 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -70,6 +70,7 @@ #include "llappviewer.h" #include "llmapimagetype.h" #include "llweb.h" +#include "llinventoryfunctions.h" #include "llglheaders.h" diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 5dac19b4c..f136c144e 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -53,7 +53,7 @@ #include "llagent.h" #include "llchatbar.h" #include "lldelayedgestureerror.h" -#include "llinventorymodel.h" +#include "llinventoryobserver.h" #include "llviewermessage.h" #include "llvoavatarself.h" #include "llviewerstats.h" diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 5eb1fb036..3f83c92f2 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -53,7 +53,7 @@ #include "llfloatergroupinfo.h" #include "llimview.h" #include "llinventory.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryview.h" #include "llfloateractivespeakers.h" #include "llfloateravatarinfo.h" diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 35ef86598..304d8d5b3 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -60,7 +60,7 @@ #include "llfolderview.h" #include "llgesturemgr.h" #include "lliconctrl.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryclipboard.h" #include "lllineeditor.h" #include "llmenugl.h" diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 9d4edc275..37172bd71 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -37,6 +37,7 @@ #include "llinventoryview.h" #include "llinventorybridge.h" #include "llinventorydefines.h" +#include "llinventoryfunctions.h" #include "llinventoryicon.h" #include "message.h" @@ -182,39 +183,6 @@ struct LLWearInfo BOOL mReplace; }; -BOOL get_is_item_worn(const LLInventoryItem *item) -{ - if (!item) - return FALSE; - - 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)); -} - // [RLVa:KB] - Made this part of LLWearableHoldingPattern //BOOL gAddToOutfit = FALSE; // [/RLVa:KB] @@ -4664,7 +4632,7 @@ void LLOutfitFetch::done() LLOutfitObserver* outfit; outfit = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend); - LLInventoryFetchObserver::item_ref_t ids; + uuid_vec_t ids; for(S32 i = 0; i < count; ++i) { ids.push_back(item_array.get(i)->getUUID()); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index f9f99d176..8806c466a 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -37,6 +37,7 @@ #include "llfloaterproperties.h" #include "llfolderview.h" #include "llinventorymodel.h" +#include "llinventoryobserver.h" //#include "llinventoryview.h" #include "llviewercontrol.h" #include "llwearable.h" diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp new file mode 100644 index 000000000..5cd8e7a41 --- /dev/null +++ b/indra/newview/llinventoryfunctions.cpp @@ -0,0 +1,477 @@ +/** + * @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 // 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 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 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. +} \ No newline at end of file diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h new file mode 100644 index 000000000..7cd944cad --- /dev/null +++ b/indra/newview/llinventoryfunctions.h @@ -0,0 +1,267 @@ +/** + * @file llinventoryfunctions.h + * @brief Miscellaneous inventory-related functions and classes + * class definition + * + * $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$ + */ + +#ifndef LL_LLINVENTORYFUNCTIONS_H +#define LL_LLINVENTORYFUNCTIONS_H + +#include "llinventorymodel.h" +#include "llinventory.h" +#include "llwearabletype.h" + +/******************************************************************************** + ** ** + ** MISCELLANEOUS GLOBAL FUNCTIONS + **/ + +// Is this a parent folder to a worn item +BOOL get_is_parent_to_worn_item(const LLUUID& id); + +// Is this item or its baseitem is worn, attached, etc... +BOOL get_is_item_worn(const LLInventoryItem *item); +BOOL get_is_item_worn(const LLUUID& id); + +// Could this item be worn (correct type + not already being worn) +BOOL get_can_item_be_worn(const LLUUID& id); + + +void change_item_parent(LLInventoryModel* model, + LLViewerInventoryItem* item, + const LLUUID& new_parent_id, + BOOL restamp); + +void change_category_parent(LLInventoryModel* model, + LLViewerInventoryCategory* cat, + const LLUUID& new_parent_id, + BOOL restamp); +// Generates a string containing the path to the item specified by item_id. +void append_path(const LLUUID& id, std::string& path); + +/******************************************************************************** + ** ** + ** INVENTORY COLLECTOR FUNCTIONS + **/ + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCollectFunctor +// +// Base class for LLInventoryModel::collectDescendentsIf() method +// which accepts an instance of one of these objects to use as the +// function to determine if it should be added. Derive from this class +// and override the () operator to return TRUE if you want to collect +// the category or item passed in. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCollectFunctor +{ +public: + virtual ~LLInventoryCollectFunctor(){}; + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; + + static bool itemTransferCommonlyAllowed(const LLInventoryItem* item); +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLAssetIDMatches +// +// This functor finds inventory items pointing to the specified asset +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLViewerInventoryItem; + +class LLAssetIDMatches : public LLInventoryCollectFunctor +{ +public: + LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} + virtual ~LLAssetIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + +protected: + LLUUID mAssetID; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLLinkedItemIDMatches +// +// This functor finds inventory items linked to the specific inventory id. +// Assumes the inventory id is itself not a linked item. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLLinkedItemIDMatches : public LLInventoryCollectFunctor +{ +public: + LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} + virtual ~LLLinkedItemIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + +protected: + LLUUID mBaseItemID; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsType +// +// Implementation of a LLInventoryCollectFunctor which returns TRUE if +// the type is the type passed in during construction. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLIsType : public LLInventoryCollectFunctor +{ +public: + LLIsType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + LLAssetType::EType mType; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsNotType +// +// Implementation of a LLInventoryCollectFunctor which returns FALSE if the +// type is the type passed in during construction, otherwise false. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLIsNotType : public LLInventoryCollectFunctor +{ +public: + LLIsNotType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsNotType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + LLAssetType::EType mType; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsOfAssetType +// +// Implementation of a LLInventoryCollectFunctor which returns TRUE if +// the item or category is of asset type passed in during construction. +// Link types are treated as links, not as the types they point to. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLIsOfAssetType : public LLInventoryCollectFunctor +{ +public: + LLIsOfAssetType(LLAssetType::EType type) : mType(type) {} + virtual ~LLIsOfAssetType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + LLAssetType::EType mType; +}; + +class LLIsTypeWithPermissions : public LLInventoryCollectFunctor +{ +public: + LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) + : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} + virtual ~LLIsTypeWithPermissions() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + LLAssetType::EType mType; + PermissionBit mPerm; + LLUUID mAgentID; + LLUUID mGroupID; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLBuddyCollector +// +// Simple class that collects calling cards that are not null, and not +// the agent. Duplicates are possible. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLBuddyCollector : public LLInventoryCollectFunctor +{ +public: + LLBuddyCollector() {} + virtual ~LLBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLUniqueBuddyCollector +// +// Simple class that collects calling cards that are not null, and not +// the agent. Duplicates are discarded. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLUniqueBuddyCollector : public LLInventoryCollectFunctor +{ +public: + LLUniqueBuddyCollector() {} + virtual ~LLUniqueBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); + +protected: + std::set mSeen; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLParticularBuddyCollector +// +// Simple class that collects calling cards that match a particular uuid +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLParticularBuddyCollector : public LLInventoryCollectFunctor +{ +public: + LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} + virtual ~LLParticularBuddyCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + LLUUID mBuddyID; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLNameCategoryCollector +// +// Collects categories based on case-insensitive match of prefix +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLNameCategoryCollector : public LLInventoryCollectFunctor +{ +public: + LLNameCategoryCollector(const std::string& name) : mName(name) {} + virtual ~LLNameCategoryCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + std::string mName; +}; +class LLInventoryState +{ +public: + // HACK: Until we can route this info through the instant message hierarchy + static BOOL sWearNewClothing; + static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction +}; + + +#endif // LL_LLINVENTORYFUNCTIONS_H + + + diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 68a52b1f2..09678c6c7 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -39,6 +39,8 @@ #include "lldir.h" #include "llsys.h" #include "llxfermanager.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" #include "message.h" #include "llagent.h" @@ -54,7 +56,7 @@ #include "lldbstrings.h" #include "llviewerstats.h" #include "llmutelist.h" -#include "llnotify.h" +#include "llnotificationsutil.h" #include "llcallbacklist.h" #include "llpreview.h" #include "llviewercontrol.h" @@ -235,6 +237,9 @@ LLInventoryModel::LLInventoryModel() mParentChildCategoryTree(), mParentChildItemTree(), mObservers(), + mRootFolderID(), + mLibraryRootFolderID(), + mLibraryOwnerID(), mIsNotifyObservers(FALSE), mIsAgentInvUsable(false) { @@ -405,6 +410,30 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, categories = get_ptr_in_map(mParentChildCategoryTree, cat_id); } +LLMD5 LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const +{ + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + getDirectDescendentsOf(cat_id,cat_array,item_array); + LLMD5 item_name_hash; + if (!item_array) + { + item_name_hash.finalize(); + return item_name_hash; + } + for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); + iter != item_array->end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter); + if (!item) + continue; + item_name_hash.update(item->getName()); + } + item_name_hash.finalize(); + return item_name_hash; +} + // SJB: Added version to lock the arrays to catch potential logic bugs void LLInventoryModel::lockDirectDescendentArrays(const LLUUID& cat_id, cat_array_t*& categories, @@ -808,27 +837,6 @@ LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID return items; } -// Generates a string containing the path to the item specified by -// item_id. -void LLInventoryModel::appendPath(const LLUUID& id, std::string& path) -{ - std::string temp; - LLInventoryObject* obj = getObject(id); - LLUUID parent_id; - if(obj) parent_id = obj->getParentUUID(); - std::string forward_slash("/"); - while(obj) - { - obj = getCategory(parent_id); - if(obj) - { - temp.assign(forward_slash + obj->getName() + temp); - parent_id = obj->getParentUUID(); - } - } - path.append(temp); -} - bool LLInventoryModel::isInventoryUsable() const { bool result = false; @@ -1249,98 +1257,6 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) } } -void LLInventoryModel::deleteFromServer(LLDynamicArray& category_ids, - LLDynamicArray& item_ids) -{ - // Store off tre UUIDS of parents which are being deleted (thus no - // need to increment) and the parents which are being modified. We - // have to increment the version of the parent with each message - // sent upstream since the dataserver will increment each unique - // parent per update message. - std::set ignore_parents; - update_map_t inc_parents; - - S32 i; - S32 count = category_ids.count(); - BOOL start_new_message = TRUE; - LLMessageSystem* msg = gMessageSystem; - LLPointer cat; - for(i = 0; i < count; i++) - { - if(start_new_message) - { - start_new_message = FALSE; - msg->newMessageFast(_PREHASH_RemoveInventoryObjects); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - } - LLUUID cat_id = category_ids.get(i); - - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, cat_id); - cat = getCategory(cat_id); - ignore_parents.insert(cat_id); - addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, cat_id); - if(cat.notNull() && (ignore_parents.find(cat->getParentUUID())==ignore_parents.end())) - { - --inc_parents[cat->getParentUUID()]; - } - if(msg->isSendFullFast(_PREHASH_FolderData)) - { - start_new_message = TRUE; - msg->nextBlockFast(_PREHASH_ItemData); - msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null); - gAgent.sendReliableMessage(); - accountForUpdate(inc_parents); - inc_parents.clear(); - } - } - - count = item_ids.count(); - std::set::iterator not_ignored = ignore_parents.end(); - LLPointer item; - if((0 == count) && (!start_new_message)) - { - msg->nextBlockFast(_PREHASH_ItemData); - msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null); - } - for(i = 0; i < count; i++) - { - if(start_new_message) - { - start_new_message = FALSE; - msg->newMessageFast(_PREHASH_RemoveInventoryObjects); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, LLUUID::null); - } - LLUUID item_id = item_ids.get(i); - msg->nextBlockFast(_PREHASH_ItemData); - msg->addUUIDFast(_PREHASH_ItemID, item_id); - item = getItem(item_id); - addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, item_id); - if(item.notNull() && (ignore_parents.find(item->getParentUUID()) == not_ignored)) - { - --inc_parents[item->getParentUUID()]; - } - if(msg->isSendFullFast(_PREHASH_ItemData)) - { - start_new_message = TRUE; - gAgent.sendReliableMessage(); - accountForUpdate(inc_parents); - inc_parents.clear(); - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - accountForUpdate(inc_parents); - } -} - // Add/remove an observer. If the observer is destroyed, be sure to // remove it. void LLInventoryModel::addObserver(LLInventoryObserver* observer) @@ -2766,6 +2682,33 @@ void LLInventoryModel::buildParentChildMap() cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); if(catsp) { + // *HACK - fix root inventory folder + // some accounts has pbroken inventory root folders + + std::string name = "My Inventory"; + LLUUID prev_root_id = mRootFolderID; + for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), + it_end = mParentChildCategoryTree.end(); it != it_end; ++it) + { + cat_array_t* cat_array = it->second; + for (cat_array_t::const_iterator cat_it = cat_array->begin(), + cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it) + { + LLPointer category = *cat_it; + + if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY) + continue; + if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) ) + { + if(category->getUUID()!=mRootFolderID) + { + LLUUID& new_inv_root_folder_id = const_cast(mRootFolderID); + new_inv_root_folder_id = category->getUUID(); + } + } + } + } + // 'My Inventory', // root of the agent's inv found. // The inv tree is built. @@ -3037,6 +2980,9 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder, processRemoveInventoryFolder, NULL); + msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects, + processRemoveInventoryObjects, + NULL); //msg->setHandlerFuncFast(_PREHASH_ExchangeCallingCard, // processExchangeCallingcard, // NULL); @@ -3152,6 +3098,37 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) return true; } +// static +void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label) +{ + LLUUID item_id; + S32 count = msg->getNumberOfBlocksFast(msg_label); + lldebugs << "Message has " << count << " item blocks" << llendl; + uuid_vec_t item_ids; + update_map_t update; + for(S32 i = 0; i < count; ++i) + { + msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); + lldebugs << "Checking for item-to-be-removed " << item_id << llendl; + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if(itemp) + { + lldebugs << "Item will be removed " << item_id << llendl; + // we only bother with the delete and account if we found + // the item - this is usually a back-up for permissions, + // so frequently the item will already be gone. + --update[itemp->getParentUUID()]; + item_ids.push_back(item_id); + } + } + gInventory.accountForUpdate(update); + for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) + { + lldebugs << "Calling deleteObject " << *it << llendl; + gInventory.deleteObject(*it); + } +} + // static void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) { @@ -3164,27 +3141,7 @@ void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) << llendl; return; } - S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - uuid_vec_t item_ids; - update_map_t update; - for(S32 i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if(itemp) - { - // we only bother with the delete and account if we found - // the item - this is usually a back-up for permissions, - // so frequently the item will already be gone. - --update[itemp->getParentUUID()]; - item_ids.push_back(item_id); - } - } - gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - gInventory.deleteObject(*it); - } + LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); gInventory.notifyObservers(); } @@ -3249,18 +3206,10 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, } // static -void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, - void**) +void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, + LLMessageSystem* msg) { - lldebugs << "LLInventoryModel::processRemoveInventoryFolder()" << llendl; - LLUUID agent_id, folder_id; - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - llwarns << "Got a RemoveInventoryFolder for the wrong agent." - << llendl; - return; - } + LLUUID folder_id; uuid_vec_t folder_ids; update_map_t update; S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); @@ -3279,6 +3228,42 @@ void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, { gInventory.deleteObject(*it); } +} + +// static +void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, + void**) +{ + lldebugs << "LLInventoryModel::processRemoveInventoryFolder()" << llendl; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + llwarns << "Got a RemoveInventoryFolder for the wrong agent." + << llendl; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + gInventory.notifyObservers(); +} + +// static +void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, + void**) +{ + lldebugs << "LLInventoryModel::processRemoveInventoryObjects()" << llendl; + LLUUID agent_id, session_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); + if(agent_id != gAgent.getID()) + { + llwarns << "Got a RemoveInventoryObjects for the wrong agent." + << llendl; + return; + } + LLInventoryModel::removeInventoryFolder( agent_id, msg ); + LLInventoryModel::removeInventoryItem( agent_id, msg, _PREHASH_ItemData ); gInventory.notifyObservers(); } @@ -3474,13 +3459,13 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // The incoming inventory could span more than one BulkInventoryUpdate packet, // so record the transaction ID for this purchase, then wear all clothing // that comes in as part of that transaction ID. JC - if (LLInventoryView::sWearNewClothing) + if (LLInventoryState::sWearNewClothing) { - LLInventoryView::sWearNewClothingTransactionID = tid; - LLInventoryView::sWearNewClothing = FALSE; + LLInventoryState::sWearNewClothingTransactionID = tid; + LLInventoryState::sWearNewClothing = FALSE; } - if (tid.notNull() && tid == LLInventoryView::sWearNewClothingTransactionID) + if (tid.notNull() && tid == LLInventoryState::sWearNewClothingTransactionID) { count = wearable_ids.size(); for (i = 0; i < count; ++i) @@ -3629,7 +3614,37 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) } } +//---------------------------------------------------------------------------- +// Trash: LLFolderType::FT_TRASH, "ConfirmEmptyTrash" +// Lost&Found: LLFolderType::FT_LOST_AND_FOUND, "ConfirmEmptyLostAndFound" + +bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purgeDescendentsOf(folder_id); + notifyObservers(); + } + return false; +} + +void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderType::EType preferred_type) +{ + if (!notification.empty()) + { + LLNotificationsUtil::add(notification, LLSD(), LLSD(), + boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); + } + else + { + const LLUUID folder_id = findCategoryUUIDForType(preferred_type); + purgeDescendentsOf(folder_id); + notifyObservers(); + } +} void LLInventoryModel::removeItem(const LLUUID& item_id) { LLViewerInventoryItem* item = getItem(item_id); @@ -3684,746 +3699,37 @@ void LLInventoryModel::setLibraryOwnerID(const LLUUID& val) // *NOTE: DEBUG functionality void LLInventoryModel::dumpInventory() const { - LL_DEBUGS("Inventory") << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; - LL_DEBUGS("Inventory") << "mCategroy[] contains " << mCategoryMap.size() << " items." << LL_ENDL; + llinfos << "\nBegin Inventory Dump\n**********************:" << llendl; + llinfos << "mCategory[] contains " << mCategoryMap.size() << " items." << llendl; for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) { - LLViewerInventoryCategory* cat = cit->second; + const LLViewerInventoryCategory* cat = cit->second; if(cat) { - LL_DEBUGS("Inventory") << " " << cat->getUUID() << " '" << cat->getName() << "' " + llinfos << " " << cat->getUUID() << " '" << cat->getName() << "' " << cat->getVersion() << " " << cat->getDescendentCount() << " parent: " << cat->getParentUUID() << LL_ENDL; } else { - LL_DEBUGS("Inventory") << " NULL!" << LL_ENDL; + llinfos << " NULL!" << llendl; } } - LL_DEBUGS("Inventory") << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; + llinfos << "mItemMap[] contains " << mItemMap.size() << " items." << llendl; for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) { - LLViewerInventoryItem* item = iit->second; + const LLViewerInventoryItem* item = iit->second; if(item) { - LL_DEBUGS("Inventory") << " " << item->getUUID() << " " - << item->getName() << LL_ENDL; + llinfos << " " << item->getUUID() << " " + << item->getName() << llendl; } else { - LL_DEBUGS("Inventory") << " NULL!" << LL_ENDL; + llinfos << " NULL!" << llendl; } } - LL_DEBUGS("Inventory") << "\n**********************\nEnd Inventory Dump" << LL_ENDL; -} - -///---------------------------------------------------------------------------- -/// LLInventoryCollectFunctor implementations -///---------------------------------------------------------------------------- - -// static -bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item) -{ - if (!item) - return false; - - bool allowed = false; - LLVOAvatar* my_avatar = NULL; - - switch(item->getType()) - { - case LLAssetType::AT_CALLINGCARD: - // not allowed - break; - - case LLAssetType::AT_OBJECT: - my_avatar = gAgentAvatarp; - if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID())) - { - allowed = true; - } - break; - - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - if(!gAgentWearables.isWearingItem(item->getUUID())) - { - allowed = true; - } - break; - - default: - allowed = true; - break; - } - - return allowed; -} - -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 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 LLIsClone::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -//{ -// if(cat) return FALSE; -// if(item) -// { -// if(mItemMap->getType() == LLAssetType::AT_CALLINGCARD) -// { -// if((item->getType() == LLAssetType::AT_CALLINGCARD) -// && !(item->getCreatorUUID().isNull()) -// && (item->getCreatorUUID() == mItemMap->getCreatorUUID())) -// { -// return TRUE; -// } -// } -// else -// { -// if((item->getType() == mItemMap->getType()) -// && !(item->getAssetUUID().isNull()) -// && (item->getAssetUUID() == mItemMap->getAssetUUID()) -// && (item->getName() == mItemMap->getName())) -// { -// 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; -} - - - -///---------------------------------------------------------------------------- -/// Observers -///---------------------------------------------------------------------------- - -void LLInventoryCompletionObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mIncomplete.empty()) - { - for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - it = mIncomplete.erase(it); - continue; - } - if(item->isComplete()) - { - mComplete.push_back(*it); - it = mIncomplete.erase(it); - continue; - } - ++it; - } - if(mIncomplete.empty()) - { - done(); - } - } -} - -void LLInventoryCompletionObserver::watchItem(const LLUUID& id) -{ - if(id.notNull()) - { - mIncomplete.push_back(id); - } -} - - -void LLInventoryFetchObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mIncomplete.empty()) - { - for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - // BUG: This can cause done() to get called prematurely below. - // This happens with the LLGestureInventoryFetchObserver that - // loads gestures at startup. JC - it = mIncomplete.erase(it); - continue; - } - if(item->isComplete()) - { - mComplete.push_back(*it); - it = mIncomplete.erase(it); - continue; - } - ++it; - } - if(mIncomplete.empty()) - { - done(); - } - } - //llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; - //llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; -} - -bool LLInventoryFetchObserver::isEverythingComplete() const -{ - return mIncomplete.empty(); -} - -void fetch_items_from_llsd(const LLSD& items_llsd) -{ - if (!items_llsd.size()) return; - LLSD body; - body[0]["cap_name"] = "FetchInventory"; - body[1]["cap_name"] = "FetchLib"; - for (S32 i=0; i= body[i].size()) continue; - std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString()); - - if (!url.empty()) - { - body[i]["agent_id"] = gAgent.getID(); - LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); - break; - } - - LLMessageSystem* msg = gMessageSystem; - BOOL start_new_message = TRUE; - for (S32 j=0; jnewMessageFast(_PREHASH_FetchInventory); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID()); - msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID()); - if(msg->isSendFull(NULL)) - { - start_new_message = TRUE; - gAgent.sendReliableMessage(); - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - } - } -} - -void LLInventoryFetchObserver::fetchItems( - const LLInventoryFetchObserver::item_ref_t& ids) -{ - LLUUID owner_id; - LLSD items_llsd; - for(item_ref_t::const_iterator it = ids.begin(); it < ids.end(); ++it) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(item) - { - if(item->isComplete()) - { - // It's complete, so put it on the complete container. - mComplete.push_back(*it); - continue; - } - else - { - owner_id = item->getPermissions().getOwner(); - } - } - else - { - // assume it's agent inventory. - owner_id = gAgent.getID(); - } - - // It's incomplete, so put it on the incomplete container, and - // pack this on the message. - mIncomplete.push_back(*it); - - // Prepare the data to fetch - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*it); - items_llsd.append(item_entry); - } - fetch_items_from_llsd(items_llsd); -} - -// virtual -void LLInventoryFetchDescendentsObserver::changed(U32 mask) -{ - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) - { - it = mIncompleteFolders.erase(it); - continue; - } - if(isComplete(cat)) - { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); - continue; - } - ++it; - } - if(mIncompleteFolders.empty()) - { - done(); - } -} - -void LLInventoryFetchDescendentsObserver::fetchDescendents( - const folder_ref_t& ids) -{ - for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) continue; - if(!isComplete(cat)) - { - cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it. - mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer. - } - else - { - mCompleteFolders.push_back(*it); - } - } -} - -bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const -{ - return mIncompleteFolders.empty(); -} - -bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) -{ - S32 version = cat->getVersion(); - S32 descendents = cat->getDescendentCount(); - if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) - || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) - { - return false; - } - // it might be complete - check known descendents against - // currently available. - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); - if(!cats || !items) - { - // bit of a hack - pretend we're done if they are gone or - // incomplete. should never know, but it would suck if this - // kept tight looping because of a corrupt memory state. - return true; - } - S32 known = cats->count() + items->count(); - if(descendents == known) - { - // hey - we're done. - return true; - } - return false; -} - -void LLInventoryFetchComboObserver::changed(U32 mask) -{ - if(!mIncompleteItems.empty()) - { - for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - it = mIncompleteItems.erase(it); - continue; - } - if(item->isComplete()) - { - mCompleteItems.push_back(*it); - it = mIncompleteItems.erase(it); - continue; - } - ++it; - } - } - if(!mIncompleteFolders.empty()) - { - for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if(!cat) - { - it = mIncompleteFolders.erase(it); - continue; - } - if(gInventory.isCategoryComplete(*it)) - { - mCompleteFolders.push_back(*it); - it = mIncompleteFolders.erase(it); - continue; - } - ++it; - } - } - if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) - { - mDone = true; - done(); - } -} - -void LLInventoryFetchComboObserver::fetch( - const folder_ref_t& folder_ids, - const item_ref_t& item_ids) -{ - lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; - for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); - if(!cat) continue; - if(!gInventory.isCategoryComplete(*fit)) - { - cat->fetchDescendents(); - lldebugs << "fetching folder " << *fit <isComplete()) - { - // It's complete, so put it on the complete container. - mCompleteItems.push_back(*iit); - lldebugs << "completing item " << *iit << llendl; - continue; - } - else - { - mIncompleteItems.push_back(*iit); - owner_id = item->getPermissions().getOwner(); - } - if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) - { - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*iit); - items_llsd.append(item_entry); - } - else - { - lldebugs << "not worrying about " << *iit << llendl; - } - } - fetch_items_from_llsd(items_llsd); -} - -void LLInventoryExistenceObserver::watchItem(const LLUUID& id) -{ - if(id.notNull()) - { - mMIA.push_back(id); - } -} - -void LLInventoryExistenceObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if(!mMIA.empty()) - { - for(item_ref_t::iterator it = mMIA.begin(); it < mMIA.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(!item) - { - ++it; - continue; - } - mExist.push_back(*it); - it = mMIA.erase(it); - } - if(mMIA.empty()) - { - done(); - } - } -} - -void LLInventoryAddedObserver::changed(U32 mask) -{ - if(!(mask & LLInventoryObserver::ADD)) - { - return; - } - - // *HACK: If this was in response to a packet off - // the network, figure out which item was updated. - LLMessageSystem* msg = gMessageSystem; - - std::string msg_name; - if (mMessageName.empty()) - { - msg_name = msg->getMessageName(); - } - else - { - msg_name = mMessageName; - } - - if (msg_name.empty()) - { - return; - } - - // We only want newly created inventory items. JC - if ( msg_name != "UpdateCreateInventoryItem") - { - return; - } - - LLPointer titem = new LLViewerInventoryItem; - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for(S32 i = 0; i < num_blocks; ++i) - { - titem->unpackMessage(msg, _PREHASH_InventoryData, i); - if (!(titem->getUUID().isNull())) - { - //we don't do anything with null keys - mAdded.push_back(titem->getUUID()); - } - } - if (!mAdded.empty()) - { - done(); - } -} - -LLInventoryTransactionObserver::LLInventoryTransactionObserver( - const LLTransactionID& transaction_id) : - mTransactionID(transaction_id) -{ -} - -void LLInventoryTransactionObserver::changed(U32 mask) -{ - if(mask & LLInventoryObserver::ADD) - { - // This could be it - see if we are processing a bulk update - LLMessageSystem* msg = gMessageSystem; - if(msg->getMessageName() - && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) - { - // we have a match for the message - now check the - // transaction id. - LLUUID id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); - if(id == mTransactionID) - { - // woo hoo, we found it - folder_ref_t folders; - item_ref_t items; - S32 count; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - S32 i; - for(i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); - if(id.notNull()) - { - folders.push_back(id); - } - } - count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); - for(i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); - if(id.notNull()) - { - items.push_back(id); - } - } - - // call the derived class the implements this method. - done(folders, items); - } - } - } -} - - -///---------------------------------------------------------------------------- -/// 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. + llinfos << "\n**********************\nEnd Inventory Dump" << llendl; } ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index b3608a536..95983ffc8 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -36,44 +36,20 @@ #include "llassettype.h" #include "llfoldertype.h" #include "lldarray.h" +#include "llhttpclient.h" #include "lluuid.h" #include "llpermissionsflags.h" #include "llstring.h" -#include "llhttpclient.h" + +#include "llmd5.h" #include #include #include #include -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryObserver -// -// This class is designed to be a simple abstract base class which can -// relay messages when the inventory changes. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryObserver; -class LLInventoryObserver -{ -public: - // This enumeration is a way to refer to what changed in a more - // human readable format. You can mask the value provided by - // chaged() to see if the observer is interested in the change. - enum - { - NONE = 0, - LABEL = 1, // name changed - INTERNAL = 2, // internal change, eg, asset uuid different - ADD = 4, // something added - REMOVE = 8, // something deleted - STRUCTURE = 16, // structural change, eg, item or folder moved - CALLING_CARD = 32, // online, grant status, cancel, etc change - ALL = 0xffffffff - }; - virtual ~LLInventoryObserver() {}; - virtual void changed(U32 mask) = 0; - std::string mMessageName; // used by Agent Inventory Service only. [DEV-20328] -}; class LLInventoryObject; class LLInventoryItem; class LLInventoryCategory; @@ -223,6 +199,9 @@ public: void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t*& categories) const; + // Compute a hash of direct descendent names (for detecting child name changes) + LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const; + // Starting with the object specified, add its descendents to the // array provided, but do not add the inventory object specified // by id. There is no guaranteed order. @@ -381,10 +360,6 @@ public: //void requestFromServer(const LLUUID& agent_id); - // Generates a string containing the path to the item specified by - // item_id. - void appendPath(const LLUUID& id, std::string& path); - //-------------------------------------------------------------------- // Creation //-------------------------------------------------------------------- @@ -524,6 +499,9 @@ public: // Callbacks //-------------------------------------------------------------------- public: + // Trigger a notification and empty the folder type (FT_TRASH or FT_LOST_AND_FOUND) if confirmed + void emptyFolderType(const std::string notification, LLFolderType::EType folder_type); + bool callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type); static void registerCallbacks(LLMessageSystem* msg); //-------------------------------------------------------------------- @@ -544,9 +522,12 @@ protected: //-------------------------------------------------------------------- public: static void processUpdateCreateInventoryItem(LLMessageSystem* msg, void**); + static void removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg, const char* msg_label); static void processRemoveInventoryItem(LLMessageSystem* msg, void**); static void processUpdateInventoryFolder(LLMessageSystem* msg, void**); + static void removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg); static void processRemoveInventoryFolder(LLMessageSystem* msg, void**); + static void processRemoveInventoryObjects(LLMessageSystem* msg, void**); static void processSaveAssetIntoInventory(LLMessageSystem* msg, void**); static void processBulkUpdateInventory(LLMessageSystem* msg, void**); static void processInventoryDescendents(LLMessageSystem* msg, void**); @@ -597,384 +578,5 @@ public: // a special inventory model for the agent extern LLInventoryModel gInventory; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryCollectFunctor -// -// Base class for LLInventoryModel::collectDescendentsIf() method -// which accepts an instance of one of these objects to use as the -// function to determine if it should be added. Derive from this class -// and override the () operator to return TRUE if you want to collect -// the category or item passed in. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryCollectFunctor -{ -public: - virtual ~LLInventoryCollectFunctor(){}; - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0; - - static bool itemTransferCommonlyAllowed(LLInventoryItem* item); -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLAssetIDMatches -// -// This functor finds inventory items pointing to the specified asset -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryItem; - -class LLAssetIDMatches : public LLInventoryCollectFunctor -{ -public: - LLAssetIDMatches(const LLUUID& asset_id) : mAssetID(asset_id) {} - virtual ~LLAssetIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - -protected: - LLUUID mAssetID; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLLinkedItemIDMatches -// -// This functor finds inventory items linked to the specific inventory id. -// Assumes the inventory id is itself not a linked item. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLLinkedItemIDMatches : public LLInventoryCollectFunctor -{ -public: - LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} - virtual ~LLLinkedItemIDMatches() {} - bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - -protected: - LLUUID mBaseItemID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIsType -// -// Implementation of a LLInventoryCollectFunctor which returns TRUE if -// the type is the type passed in during construction. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLIsType : public LLInventoryCollectFunctor -{ -public: - LLIsType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -protected: - LLAssetType::EType mType; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIsNotType -// -// Implementation of a LLInventoryCollectFunctor which returns FALSE if the -// type is the type passed in during construction, otherwise false. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLIsNotType : public LLInventoryCollectFunctor -{ -public: - LLIsNotType(LLAssetType::EType type) : mType(type) {} - virtual ~LLIsNotType() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -protected: - LLAssetType::EType mType; -}; - -class LLIsTypeWithPermissions : public LLInventoryCollectFunctor -{ -public: - LLIsTypeWithPermissions(LLAssetType::EType type, const PermissionBit perms, const LLUUID &agent_id, const LLUUID &group_id) - : mType(type), mPerm(perms), mAgentID(agent_id), mGroupID(group_id) {} - virtual ~LLIsTypeWithPermissions() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -protected: - LLAssetType::EType mType; - PermissionBit mPerm; - LLUUID mAgentID; - LLUUID mGroupID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIsClone -// -// Implementation of a LLInventoryCollectFunctor which returns TRUE if -// the object is a clone of the item passed in during -// construction. -// -// *NOTE: Since clone information is determined based off of asset id -// (or creator with calling cards), if the id is NULL, it has no -// clones - even itself. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -//class LLIsClone : public LLInventoryCollectFunctor -//{ -//public: -// LLIsClone(LLViewerInventoryItem* item) : mItem(item) {} -// virtual ~LLIsClone() {} -// virtual bool operator()(LLViewerInventoryCategory* cat, -// LLViewerInventoryItem* item); -//protected: -// LLPointer mItem; -//}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLBuddyCollector -// -// Simple class that collects calling cards that are not null, and not -// the agent. Duplicates are possible. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLBuddyCollector : public LLInventoryCollectFunctor -{ -public: - LLBuddyCollector() {} - virtual ~LLBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLUniqueBuddyCollector -// -// Simple class that collects calling cards that are not null, and not -// the agent. Duplicates are discarded. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLUniqueBuddyCollector : public LLInventoryCollectFunctor -{ -public: - LLUniqueBuddyCollector() {} - virtual ~LLUniqueBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - -protected: - std::set mSeen; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLParticularBuddyCollector -// -// Simple class that collects calling cards that match a particular uuid -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLParticularBuddyCollector : public LLInventoryCollectFunctor -{ -public: - LLParticularBuddyCollector(const LLUUID& id) : mBuddyID(id) {} - virtual ~LLParticularBuddyCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -protected: - LLUUID mBuddyID; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLNameCategoryCollector -// -// Collects categories based on case-insensitive match of prefix -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLNameCategoryCollector : public LLInventoryCollectFunctor -{ -public: - LLNameCategoryCollector(const std::string& name) : mName(name) {} - virtual ~LLNameCategoryCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -protected: - std::string mName; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryCompletionObserver -// -// Class which can be used as a base class for doing something when -// when all observed items are locally complete. This class implements -// the changed() method of LLInventoryObserver and declares a new -// method named done() which is called when all watched items have -// complete information in the inventory model. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryCompletionObserver : public LLInventoryObserver -{ -public: - LLInventoryCompletionObserver() {} - virtual void changed(U32 mask); - - void watchItem(const LLUUID& id); - -protected: - virtual void done() = 0; - - typedef std::vector item_ref_t; - item_ref_t mComplete; - item_ref_t mIncomplete; -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchObserver -// -// This class is much like the LLInventoryCompletionObserver, except -// that it handles all the the fetching necessary. Override the done() -// method to do the thing you want. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryFetchObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchObserver() {} - virtual void changed(U32 mask); - - typedef std::vector item_ref_t; - - bool isEverythingComplete() const; - void fetchItems(const item_ref_t& ids); - virtual void done() = 0; - -protected: - item_ref_t mComplete; - item_ref_t mIncomplete; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchDescendentsObserver -// -// This class is much like the LLInventoryCompletionObserver, except -// that it handles fetching based on category. Override the done() -// method to do the thing you want. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchDescendentsObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchDescendentsObserver() {} - virtual void changed(U32 mask); - - typedef std::vector folder_ref_t; - void fetchDescendents(const folder_ref_t& ids); - bool isEverythingComplete() const; - virtual void done() = 0; - -protected: - bool isComplete(LLViewerInventoryCategory* cat); - folder_ref_t mIncompleteFolders; - folder_ref_t mCompleteFolders; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryFetchComboObserver -// -// This class does an appropriate combination of fetch descendents and -// item fetches based on completion of categories and items. Much like -// the fetch and fetch descendents, this will call done() when everything -// has arrived. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFetchComboObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchComboObserver() : mDone(false) {} - virtual void changed(U32 mask); - - typedef std::vector folder_ref_t; - typedef std::vector item_ref_t; - void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); - - virtual void done() = 0; - -protected: - bool mDone; - folder_ref_t mCompleteFolders; - folder_ref_t mIncompleteFolders; - item_ref_t mCompleteItems; - item_ref_t mIncompleteItems; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryExistenceObserver -// -// This class is used as a base class for doing somethign when all the -// observed item ids exist in the inventory somewhere. You can derive -// a class from this class and implement the done() method to do -// something useful. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryExistenceObserver : public LLInventoryObserver -{ -public: - LLInventoryExistenceObserver() {} - virtual void changed(U32 mask); - - void watchItem(const LLUUID& id); - -protected: - virtual void done() = 0; - - typedef std::vector item_ref_t; - item_ref_t mExist; - item_ref_t mMIA; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryAddedObserver -// -// This class is used as a base class for doing something when -// a new item arrives in inventory. -// It does not watch for a certain UUID, rather it acts when anything is added -// Derive a class from this class and implement the done() method to do -// something useful. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryAddedObserver : public LLInventoryObserver -{ -public: - LLInventoryAddedObserver() : mAdded() {} - virtual void changed(U32 mask); - -protected: - virtual void done() = 0; - - typedef std::vector item_ref_t; - item_ref_t mAdded; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryTransactionObserver -// -// Class which can be used as a base class for doing something when an -// inventory transaction completes. -// -// *NOTE: This class is not quite complete. Avoid using unless you fix up it's -// functionality gaps. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryTransactionObserver : public LLInventoryObserver -{ -public: - LLInventoryTransactionObserver(const LLTransactionID& transaction_id); - virtual void changed(U32 mask); - -protected: - typedef std::vector folder_ref_t; - typedef std::vector item_ref_t; - virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; - - LLTransactionID mTransactionID; -}; - - #endif // LL_LLINVENTORYMODEL_H diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp new file mode 100644 index 000000000..c16e96dbd --- /dev/null +++ b/indra/newview/llinventoryobserver.cpp @@ -0,0 +1,679 @@ +/** + * @file llinventoryobserver.cpp + * @brief Implementation of the inventory observers used to track agent inventory. + * + * $LicenseInfo:firstyear=2002&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 "llinventoryobserver.h" + +#include "llassetstorage.h" +#include "llcrc.h" +#include "lldir.h" +#include "llsys.h" +#include "llxfermanager.h" +#include "message.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llfloater.h" +#include "llfocusmgr.h" +#include "llinventorybridge.h" +//#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llviewerregion.h" +#include "llappviewer.h" +#include "lldbstrings.h" +#include "llviewerstats.h" +#include "llnotificationsutil.h" +#include "llcallbacklist.h" +#include "llpreview.h" +#include "llviewercontrol.h" +#include "llvoavatarself.h" +#include "llsdutil.h" +#include + +const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 60.0f; + +void fetch_items_from_llsd(const LLSD& items_llsd); + +void LLInventoryCompletionObserver::changed(U32 mask) +{ + // scan through the incomplete items and move or erase them as + // appropriate. + if(!mIncomplete.empty()) + { + for(uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + it = mIncomplete.erase(it); + continue; + } + if(item->isComplete()) + { + mComplete.push_back(*it); + it = mIncomplete.erase(it); + continue; + } + ++it; + } + if(mIncomplete.empty()) + { + done(); + } + } +} + +void LLInventoryCompletionObserver::watchItem(const LLUUID& id) +{ + if(id.notNull()) + { + mIncomplete.push_back(id); + } +} + +LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const LLUUID& item_id) +{ + mIDs.clear(); + if (item_id != LLUUID::null) + { + mIDs.push_back(item_id); + } +} + +LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids) + : mIDs(item_ids) +{ +} + +BOOL LLInventoryFetchItemsObserver::isFinished() const +{ + return mIncomplete.empty(); +} + +void LLInventoryFetchItemsObserver::changed(U32 mask) +{ + lldebugs << this << " remaining incomplete " << mIncomplete.size() + << " complete " << mComplete.size() + << " wait period " << mFetchingPeriod.getRemainingTimeF32() + << llendl; + + // scan through the incomplete items and move or erase them as + // appropriate. + if (!mIncomplete.empty()) + { + // Have we exceeded max wait time? + bool timeout_expired = mFetchingPeriod.hasExpired(); + + for (uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) + { + const LLUUID& item_id = (*it); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (item && item->isComplete()) + { + mComplete.push_back(item_id); + it = mIncomplete.erase(it); + } + else + { + if (timeout_expired) + { + // Just concede that this item hasn't arrived in reasonable time and continue on. + llwarns << "Fetcher timed out when fetching inventory item UUID: " << item_id << LL_ENDL; + it = mIncomplete.erase(it); + } + else + { + // Keep trying. + ++it; + } + } + } + + } + + if (mIncomplete.empty()) + { + lldebugs << this << " done at remaining incomplete " + << mIncomplete.size() << " complete " << mComplete.size() << llendl; + done(); + } + //llinfos << "LLInventoryFetchItemsObserver::changed() mComplete size " << mComplete.size() << llendl; + //llinfos << "LLInventoryFetchItemsObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; +} + +void LLInventoryFetchItemsObserver::startFetch() +{ + LLUUID owner_id; + LLSD items_llsd; + for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if (item) + { + if (item->isComplete()) + { + // It's complete, so put it on the complete container. + mComplete.push_back(*it); + continue; + } + else + { + owner_id = item->getPermissions().getOwner(); + } + } + else + { + // assume it's agent inventory. + owner_id = gAgent.getID(); + } + + // Ignore categories since they're not items. We + // could also just add this to mComplete but not sure what the + // side-effects would be, so ignoring to be safe. + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if (cat) + { + continue; + } + + // It's incomplete, so put it on the incomplete container, and + // pack this on the message. + mIncomplete.push_back(*it); + + // Prepare the data to fetch + LLSD item_entry; + item_entry["owner_id"] = owner_id; + item_entry["item_id"] = (*it); + items_llsd.append(item_entry); + } + + mFetchingPeriod.reset(); + mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY); + + fetch_items_from_llsd(items_llsd); +} + +void LLInventoryFetchObserver::changed(U32 mask) +{ + // scan through the incomplete items and move or erase them as + // appropriate. + if(!mIncomplete.empty()) + { + for(uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + // BUG: This can cause done() to get called prematurely below. + // This happens with the LLGestureInventoryFetchObserver that + // loads gestures at startup. JC + it = mIncomplete.erase(it); + continue; + } + if(item->isComplete()) + { + mComplete.push_back(*it); + it = mIncomplete.erase(it); + continue; + } + ++it; + } + if(mIncomplete.empty()) + { + done(); + } + } + //llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl; + //llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; +} + +bool LLInventoryFetchObserver::isEverythingComplete() const +{ + return mIncomplete.empty(); +} + +void fetch_items_from_llsd(const LLSD& items_llsd) +{ + if (!items_llsd.size() || gDisconnected) return; + LLSD body; + body[0]["cap_name"] = "FetchInventory"; + body[1]["cap_name"] = "FetchLib"; + for (S32 i=0; igetCapability(body[i]["cap_name"].asString()); + if (!url.empty()) + { + body[i]["agent_id"] = gAgent.getID(); + LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); + continue; + } + + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + for (S32 j=0; jnewMessageFast(_PREHASH_FetchInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID()); + msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID()); + if(msg->isSendFull(NULL)) + { + start_new_message = TRUE; + gAgent.sendReliableMessage(); + } + } + if(!start_new_message) + { + gAgent.sendReliableMessage(); + } + } +} + +void LLInventoryFetchObserver::fetchItems( + const uuid_vec_t& ids) +{ + LLUUID owner_id; + LLSD items_llsd; + for(uuid_vec_t::const_iterator it = ids.begin(); it < ids.end(); ++it) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(item) + { + if(item->isComplete()) + { + // It's complete, so put it on the complete container. + mComplete.push_back(*it); + continue; + } + else + { + owner_id = item->getPermissions().getOwner(); + } + } + else + { + // assume it's agent inventory. + owner_id = gAgent.getID(); + } + + // It's incomplete, so put it on the incomplete container, and + // pack this on the message. + mIncomplete.push_back(*it); + + // Prepare the data to fetch + LLSD item_entry; + item_entry["owner_id"] = owner_id; + item_entry["item_id"] = (*it); + items_llsd.append(item_entry); + } + fetch_items_from_llsd(items_llsd); +} +// virtual +void LLInventoryFetchDescendentsObserver::changed(U32 mask) +{ + for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if(!cat) + { + it = mIncompleteFolders.erase(it); + continue; + } + if(isComplete(cat)) + { + mCompleteFolders.push_back(*it); + it = mIncompleteFolders.erase(it); + continue; + } + ++it; + } + if(mIncompleteFolders.empty()) + { + done(); + } +} + +void LLInventoryFetchDescendentsObserver::fetchDescendents( + const folder_ref_t& ids) +{ + for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if(!cat) continue; + if(!isComplete(cat)) + { + cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it. + mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer. + } + else + { + mCompleteFolders.push_back(*it); + } + } +} + +bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const +{ + return mIncompleteFolders.empty(); +} + +bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat) +{ + S32 version = cat->getVersion(); + S32 descendents = cat->getDescendentCount(); + if((LLViewerInventoryCategory::VERSION_UNKNOWN == version) + || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents)) + { + return false; + } + // it might be complete - check known descendents against + // currently available. + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items); + if(!cats || !items) + { + // bit of a hack - pretend we're done if they are gone or + // incomplete. should never know, but it would suck if this + // kept tight looping because of a corrupt memory state. + return true; + } + S32 known = cats->count() + items->count(); + if(descendents == known) + { + // hey - we're done. + return true; + } + return false; +} + +void LLInventoryFetchComboObserver::changed(U32 mask) +{ + if(!mIncompleteItems.empty()) + { + for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + it = mIncompleteItems.erase(it); + continue; + } + if(item->isComplete()) + { + mCompleteItems.push_back(*it); + it = mIncompleteItems.erase(it); + continue; + } + ++it; + } + } + if(!mIncompleteFolders.empty()) + { + for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*it); + if(!cat) + { + it = mIncompleteFolders.erase(it); + continue; + } + if(gInventory.isCategoryComplete(*it)) + { + mCompleteFolders.push_back(*it); + it = mIncompleteFolders.erase(it); + continue; + } + ++it; + } + } + if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty()) + { + mDone = true; + done(); + } +} + +void LLInventoryFetchComboObserver::fetch( + const folder_ref_t& folder_ids, + const item_ref_t& item_ids) +{ + lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl; + for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(*fit); + if(!cat) continue; + if(!gInventory.isCategoryComplete(*fit)) + { + cat->fetchDescendents(); + lldebugs << "fetching folder " << *fit <isComplete()) + { + // It's complete, so put it on the complete container. + mCompleteItems.push_back(*iit); + lldebugs << "completing item " << *iit << llendl; + continue; + } + else + { + mIncompleteItems.push_back(*iit); + owner_id = item->getPermissions().getOwner(); + } + if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end()) + { + LLSD item_entry; + item_entry["owner_id"] = owner_id; + item_entry["item_id"] = (*iit); + items_llsd.append(item_entry); + } + else + { + lldebugs << "not worrying about " << *iit << llendl; + } + } + fetch_items_from_llsd(items_llsd); +} + +void LLInventoryExistenceObserver::watchItem(const LLUUID& id) +{ + if(id.notNull()) + { + mMIA.push_back(id); + } +} + +void LLInventoryExistenceObserver::changed(U32 mask) +{ + // scan through the incomplete items and move or erase them as + // appropriate. + if(!mMIA.empty()) + { + for(uuid_vec_t::iterator it = mMIA.begin(); it < mMIA.end(); ) + { + LLViewerInventoryItem* item = gInventory.getItem(*it); + if(!item) + { + ++it; + continue; + } + mExist.push_back(*it); + it = mMIA.erase(it); + } + if(mMIA.empty()) + { + done(); + } + } +} +void LLInventoryAddedObserver::changed(U32 mask) +{ + if(!(mask & LLInventoryObserver::ADD)) + { + return; + } + + // *HACK: If this was in response to a packet off + // the network, figure out which item was updated. + LLMessageSystem* msg = gMessageSystem; + + std::string msg_name = msg->getMessageName(); + if (msg_name.empty()) + { + return; + } + + // We only want newly created inventory items. JC + if ( msg_name != "UpdateCreateInventoryItem") + { + return; + } + + LLPointer titem = new LLViewerInventoryItem; + S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for(S32 i = 0; i < num_blocks; ++i) + { + titem->unpackMessage(msg, _PREHASH_InventoryData, i); + if (!(titem->getUUID().isNull())) + { + //we don't do anything with null keys + mAdded.push_back(titem->getUUID()); + } + } + if (!mAdded.empty()) + { + done(); + } +} + +LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) : + mTransactionID(transaction_id) +{ +} + +void LLInventoryTransactionObserver::changed(U32 mask) +{ + if(mask & LLInventoryObserver::ADD) + { + // This could be it - see if we are processing a bulk update + LLMessageSystem* msg = gMessageSystem; + if(msg->getMessageName() + && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) + { + // we have a match for the message - now check the + // transaction id. + LLUUID id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); + if(id == mTransactionID) + { + // woo hoo, we found it + uuid_vec_t folders; + uuid_vec_t items; + S32 count; + count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + S32 i; + for(i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); + if(id.notNull()) + { + folders.push_back(id); + } + } + count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); + for(i = 0; i < count; ++i) + { + msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); + if(id.notNull()) + { + items.push_back(id); + } + } + + // call the derived class the implements this method. + done(folders, items); + } + } + } +} \ No newline at end of file diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h new file mode 100644 index 000000000..0d3bdb930 --- /dev/null +++ b/indra/newview/llinventoryobserver.h @@ -0,0 +1,257 @@ +/** + * @file llinventoryobserver.h + * @brief LLInventoryObserver class header file + * + * $LicenseInfo:firstyear=2002&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$ + */ + +#ifndef LL_LLINVENTORYOBSERVERS_H +#define LL_LLINVENTORYOBSERVERS_H + +#include "lluuid.h" +#include "llmd5.h" +#include +#include + +class LLViewerInventoryCategory; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryObserver +// +// A simple abstract base class that can relay messages when the inventory +// changes. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryObserver +{ +public: + // This enumeration is a way to refer to what changed in a more + // human readable format. You can mask the value provided by + // chaged() to see if the observer is interested in the change. + enum + { + NONE = 0, + LABEL = 1, // name changed + INTERNAL = 2, // internal change, eg, asset uuid different + ADD = 4, // something added + REMOVE = 8, // something deleted + STRUCTURE = 16, // structural change, eg, item or folder moved + CALLING_CARD = 32, // online, grant status, cancel, etc change + ALL = 0xffffffff + }; + virtual ~LLInventoryObserver() {}; + virtual void changed(U32 mask) = 0; +}; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchObserver +// +// This class is much like the LLInventoryCompletionObserver, except +// that it handles all the the fetching necessary. Override the done() +// method to do the thing you want. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryFetchObserver : public LLInventoryObserver +{ +public: + LLInventoryFetchObserver() {} + virtual void changed(U32 mask); + + bool isEverythingComplete() const; + void fetchItems(const uuid_vec_t& ids); + virtual void done() = 0; + +protected: + uuid_vec_t mComplete; + uuid_vec_t mIncomplete; +}; + +class LLInventoryFetchItemsObserver : public LLInventoryObserver +{ +public: + LLInventoryFetchItemsObserver(const LLUUID& item_id = LLUUID::null); + LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids); + + BOOL isFinished() const; + + virtual void startFetch(); + virtual void changed(U32 mask); + virtual void done() {}; +protected: + uuid_vec_t mComplete; + uuid_vec_t mIncomplete; + uuid_vec_t mIDs; +private: + LLTimer mFetchingPeriod; + + /** + * Period of waiting a notification when requested items get added into inventory. + */ + static const F32 FETCH_TIMER_EXPIRY; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchDescendentsObserver +// +// This class is much like the LLInventoryCompletionObserver, except +// that it handles fetching based on category. Override the done() +// method to do the thing you want. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchDescendentsObserver : public LLInventoryObserver +{ +public: + LLInventoryFetchDescendentsObserver() {} + virtual void changed(U32 mask); + + typedef std::vector folder_ref_t; + void fetchDescendents(const folder_ref_t& ids); + bool isEverythingComplete() const; + virtual void done() = 0; + +protected: + bool isComplete(LLViewerInventoryCategory* cat); + folder_ref_t mIncompleteFolders; + folder_ref_t mCompleteFolders; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryFetchComboObserver +// +// This class does an appropriate combination of fetch descendents and +// item fetches based on completion of categories and items. Much like +// the fetch and fetch descendents, this will call done() when everything +// has arrived. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryFetchComboObserver : public LLInventoryObserver +{ +public: + LLInventoryFetchComboObserver() : mDone(false) {} + virtual void changed(U32 mask); + + typedef std::vector folder_ref_t; + typedef std::vector item_ref_t; + void fetch(const folder_ref_t& folder_ids, const item_ref_t& item_ids); + + virtual void done() = 0; + +protected: + bool mDone; + folder_ref_t mCompleteFolders; + folder_ref_t mIncompleteFolders; + item_ref_t mCompleteItems; + item_ref_t mIncompleteItems; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryExistenceObserver +// +// This class is used as a base class for doing somethign when all the +// observed item ids exist in the inventory somewhere. You can derive +// a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryExistenceObserver : public LLInventoryObserver +{ +public: + LLInventoryExistenceObserver() {} + virtual void changed(U32 mask); + + void watchItem(const LLUUID& id); + +protected: + virtual void done() = 0; + + uuid_vec_t mExist; + uuid_vec_t mMIA; +}; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryAddedObserver +// +// This class is used as a base class for doing something when +// a new item arrives in inventory. +// It does not watch for a certain UUID, rather it acts when anything is added +// Derive a class from this class and implement the done() method to do +// something useful. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryAddedObserver : public LLInventoryObserver +{ +public: + LLInventoryAddedObserver() : mAdded() {} + virtual void changed(U32 mask); + +protected: + virtual void done() = 0; + + typedef std::vector item_ref_t; + item_ref_t mAdded; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryTransactionObserver +// +// Class which can be used as a base class for doing something when an +// inventory transaction completes. +// +// *NOTE: This class is not quite complete. Avoid using unless you fix up it's +// functionality gaps. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryTransactionObserver : public LLInventoryObserver +{ +public: + LLInventoryTransactionObserver(const LLTransactionID& transaction_id); + virtual void changed(U32 mask); + +protected: + typedef std::vector folder_ref_t; + typedef std::vector item_ref_t; + virtual void done(const folder_ref_t& folders, const item_ref_t& items) = 0; + + LLTransactionID mTransactionID; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryCompletionObserver +// +// Class which can be used as a base class for doing something when +// when all observed items are locally complete. This class implements +// the changed() method of LLInventoryObserver and declares a new +// method named done() which is called when all watched items have +// complete information in the inventory model. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCompletionObserver : public LLInventoryObserver +{ +public: + LLInventoryCompletionObserver() {} + virtual void changed(U32 mask); + + void watchItem(const LLUUID& id); + +protected: + virtual void done() = 0; + + uuid_vec_t mComplete; + uuid_vec_t mIncomplete; +}; + +#endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index 7ca697e4d..ba667e658 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -57,7 +57,7 @@ #include "llfolderview.h" #include "llgesturemgr.h" #include "lliconctrl.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryclipboard.h" #include "lllineeditor.h" #include "llmenugl.h" diff --git a/indra/newview/llinventoryview.h b/indra/newview/llinventoryview.h index 285062468..724e3d1c1 100644 --- a/indra/newview/llinventoryview.h +++ b/indra/newview/llinventoryview.h @@ -40,6 +40,7 @@ #include "llinventory.h" #include "llfolderview.h" #include "llinventorymodel.h" +#include "llinventoryobserver.h" #include "llmemberlistener.h" #include "llcombobox.h" #include "lluictrlfactory.h" diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index eec36f941..935d0af1b 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -52,6 +52,7 @@ #include "llcolorswatch.h" #include "llcombobox.h" #include "llfocusmgr.h" +#include "llinventoryfunctions.h" #include "llmanipscale.h" #include "llnotificationsutil.h" #include "llpanelinventory.h" diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index 7d28f028c..ed6bb3087 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -40,6 +40,7 @@ #include "llviewerinventory.h" #include "lltabcontainer.h" #include "llinventorymodel.h" +#include "llinventoryobserver.h" #include class LLLineEditor; diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 1045f16af..ad22dce4c 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -55,7 +55,7 @@ #include "lldelayedgestureerror.h" #include "llfloatergesture.h" // for some label constants #include "llgesturemgr.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -95,8 +95,8 @@ protected: void LLInventoryGestureAvailable::done() { LLPreview* preview = NULL; - item_ref_t::iterator it = mComplete.begin(); - item_ref_t::iterator end = mComplete.end(); + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); for(; it < end; ++it) { preview = LLPreview::find((*it)); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 42820368a..4aca35710 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -128,7 +128,7 @@ #include "llhttpclient.h" #include "llimagebmp.h" #include "llimview.h" // for gIMMgr -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryview.h" #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 854d67841..75aca382d 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -45,7 +45,7 @@ #include "llfocusmgr.h" #include "llfolderview.h" #include "llinventory.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryview.h" #include "lllineeditor.h" #include "llui.h" diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index b42ec4c17..f6f658f3f 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -52,7 +52,7 @@ #include "llhudmanager.h" #include "llinventorybridge.h" #include "llinventorydefines.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryview.h" #include "llmutelist.h" #include "llnotify.h" @@ -287,8 +287,8 @@ void LLCategoryDropObserver::done() { // *FIX: coalesce these... LLInventoryItem* item = NULL; - item_ref_t::iterator it = mComplete.begin(); - item_ref_t::iterator end = mComplete.end(); + uuid_vec_t::iterator it = mComplete.begin(); + uuid_vec_t::iterator end = mComplete.end(); for(; it < end; ++it) { item = gInventory.getItem(*it); @@ -346,8 +346,8 @@ void LLCategoryDropDescendentsObserver::done() { unique_ids.insert(items.get(i)->getUUID()); } - LLInventoryFetchObserver::item_ref_t ids; - std::back_insert_iterator copier(ids); + uuid_vec_t ids; + std::back_insert_iterator copier(ids); std::copy(unique_ids.begin(), unique_ids.end(), copier); LLCategoryDropObserver* dropper; dropper = new LLCategoryDropObserver(mObjectID, mSource); @@ -2812,7 +2812,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( if(drop && (ACCEPT_YES_COPY_SINGLE <= rv)) { S32 count = items.count(); - LLInventoryFetchObserver::item_ref_t ids; + uuid_vec_t ids; for(i = 0; i < count; ++i) { //dropInventory(root_object, items.get(i), mSource, mSourceID); diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index 169d78089..badefaa57 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -57,7 +57,7 @@ #include "llhudtext.h" #include "llhudview.h" #include "llinventorydefines.h" -#include "llinventorymodel.h" +#include "llinventoryobserver.h" #include "lllandmarklist.h" #include "llprogressview.h" #include "llsky.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 821a8477f..4836e5323 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -170,7 +170,7 @@ #include "llimagej2c.h" #include "llimagetga.h" #include "llinventorydefines.h" -#include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "llinventoryview.h" #include "llkeyboard.h" #include "llpanellogin.h" @@ -7179,7 +7179,7 @@ class LLAttachmentEnableDrop : public view_listener_t // if a fetch is already out there (being sent from a slow sim) // we refetch and there are 2 fetches LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver(); - LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched + uuid_vec_t items; //add item to the inventory item to be fetched items.push_back((*attachment_iter)->getAttachmentItemID()); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 9524ef1f6..f62e98be0 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1309,7 +1309,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& #endif // RLV_EXTENSION_GIVETORLV_A2A // [/RLVa:KB] - LLInventoryFetchObserver::item_ref_t items; + uuid_vec_t items; items.push_back(mObjectID); LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string); open_agent_offer->fetchItems(items); diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp index aa0d8fed8..9b0100f6e 100644 --- a/indra/newview/llviewerobjectbackup.cpp +++ b/indra/newview/llviewerobjectbackup.cpp @@ -62,6 +62,7 @@ #include "llfloaternamedesc.h" #include "llfloatersnapshot.h" #include "llinventorymodel.h" // gInventory +#include "llinventoryfunctions.h" #include "llnotificationsutil.h" #include "llresourcedata.h" #include "llselectmgr.h" diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5ceb8fc9e..27a22670e 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -60,6 +60,7 @@ #include "llhudmanager.h" #include "llinventorybridge.h" #include "llinventoryview.h" +#include "llinventoryfunctions.h" #include "llhudnametag.h" #include "llhudtext.h" // for mText/mDebugText #include "llkeyframefallmotion.h" diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 1c18245b1..cf8157c64 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -46,7 +46,7 @@ #include "llassetuploadresponders.h" #include "llviewerwindow.h" #include "llfloatercustomize.h" -#include "llinventorymodel.h" +#include "llinventoryobserver.h" #include "llviewertexturelist.h" #include "llviewerinventory.h" #include "llviewerregion.h" diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index c46bb4830..e32cd8475 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -20,7 +20,7 @@ #include "llagent.h" #include "llboost.h" #include "llgesturemgr.h" -#include "llinventorymodel.h" +#include "llinventoryobserver.h" #include "llviewerinventory.h" #include "llvoavatar.h" #include "llwlparamset.h" diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp index 54fb89f76..da62f0e73 100644 --- a/indra/newview/rlvinventory.cpp +++ b/indra/newview/rlvinventory.cpp @@ -178,7 +178,7 @@ void RlvInventory::fetchWornItem(const LLUUID& idItem) { if (idItem.notNull()) { - LLInventoryFetchObserver::item_ref_t idItems; + uuid_vec_t idItems; idItems.push_back(idItem); RlvItemFetcher itemFetcher; itemFetcher.fetchItems(idItems); diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h index a5a799bb4..87dabd87c 100644 --- a/indra/newview/rlvinventory.h +++ b/indra/newview/rlvinventory.h @@ -19,6 +19,7 @@ #include "llmemory.h" #include "llviewerinventory.h" +#include "llinventoryfunctions.h" #include "rlvhelper.h" #include "rlvlocks.h" diff --git a/indra/newview/rlvviewer2.cpp b/indra/newview/rlvviewer2.cpp index a90f93c80..c0633333d 100644 --- a/indra/newview/rlvviewer2.cpp +++ b/indra/newview/rlvviewer2.cpp @@ -27,181 +27,3 @@ #include "rlvviewer2.h" // ============================================================================ -// From llinventoryobserver.cpp - -void fetch_items_from_llsd(const LLSD& items_llsd); - -const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 60.0f; - -LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const LLUUID& item_id) -{ - mIDs.clear(); - if (item_id != LLUUID::null) - { - mIDs.push_back(item_id); - } -} - -LLInventoryFetchItemsObserver::LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids) - : mIDs(item_ids) -{ -} - -BOOL LLInventoryFetchItemsObserver::isFinished() const -{ - return mIncomplete.empty(); -} - -void LLInventoryFetchItemsObserver::changed(U32 mask) -{ - lldebugs << this << " remaining incomplete " << mIncomplete.size() - << " complete " << mComplete.size() - << " wait period " << mFetchingPeriod.getRemainingTimeF32() - << llendl; - - // scan through the incomplete items and move or erase them as - // appropriate. - if (!mIncomplete.empty()) - { - // Have we exceeded max wait time? - bool timeout_expired = mFetchingPeriod.hasExpired(); - - for (uuid_vec_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); ) - { - const LLUUID& item_id = (*it); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if (item && item->isComplete()) - { - mComplete.push_back(item_id); - it = mIncomplete.erase(it); - } - else - { - if (timeout_expired) - { - // Just concede that this item hasn't arrived in reasonable time and continue on. - llwarns << "Fetcher timed out when fetching inventory item UUID: " << item_id << LL_ENDL; - it = mIncomplete.erase(it); - } - else - { - // Keep trying. - ++it; - } - } - } - - } - - if (mIncomplete.empty()) - { - lldebugs << this << " done at remaining incomplete " - << mIncomplete.size() << " complete " << mComplete.size() << llendl; - done(); - } - //llinfos << "LLInventoryFetchItemsObserver::changed() mComplete size " << mComplete.size() << llendl; - //llinfos << "LLInventoryFetchItemsObserver::changed() mIncomplete size " << mIncomplete.size() << llendl; -} - -void LLInventoryFetchItemsObserver::startFetch() -{ - LLUUID owner_id; - LLSD items_llsd; - for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if (item) - { - if (item->isComplete()) - { - // It's complete, so put it on the complete container. - mComplete.push_back(*it); - continue; - } - else - { - owner_id = item->getPermissions().getOwner(); - } - } - else - { - // assume it's agent inventory. - owner_id = gAgent.getID(); - } - - // Ignore categories since they're not items. We - // could also just add this to mComplete but not sure what the - // side-effects would be, so ignoring to be safe. - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if (cat) - { - continue; - } - - // It's incomplete, so put it on the incomplete container, and - // pack this on the message. - mIncomplete.push_back(*it); - - // Prepare the data to fetch - LLSD item_entry; - item_entry["owner_id"] = owner_id; - item_entry["item_id"] = (*it); - items_llsd.append(item_entry); - } - - mFetchingPeriod.reset(); - mFetchingPeriod.setTimerExpirySec(FETCH_TIMER_EXPIRY); - - fetch_items_from_llsd(items_llsd); -} - -// ============================================================================ -// From llinventoryfunctions.cpp - -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 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 new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - model->updateCategory(new_cat); - model->notifyObservers(); -} - -// ============================================================================ diff --git a/indra/newview/rlvviewer2.h b/indra/newview/rlvviewer2.h index 28075031e..9e5137ffc 100644 --- a/indra/newview/rlvviewer2.h +++ b/indra/newview/rlvviewer2.h @@ -25,43 +25,9 @@ #define RLV_VIEWER2_H #include "llcallbacklist.h" -#include "llinventorymodel.h" #include "boost/function.hpp" -// ============================================================================ -// From llinventoryobserver.h - -class LLInventoryFetchItemsObserver : public LLInventoryObserver -{ -public: - LLInventoryFetchItemsObserver(const LLUUID& item_id = LLUUID::null); - LLInventoryFetchItemsObserver(const uuid_vec_t& item_ids); - - BOOL isFinished() const; - - virtual void startFetch(); - virtual void changed(U32 mask); - virtual void done() {}; -protected: - uuid_vec_t mComplete; - uuid_vec_t mIncomplete; - uuid_vec_t mIDs; -private: - LLTimer mFetchingPeriod; - - /** - * Period of waiting a notification when requested items get added into inventory. - */ - static const F32 FETCH_TIMER_EXPIRY; -}; - -// ============================================================================ -// From llinventoryfunctions.cpp - -void change_item_parent(LLInventoryModel* model, LLViewerInventoryItem* item, const LLUUID& new_parent_id, BOOL restamp); -void change_category_parent(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& new_parent_id, BOOL restamp); - // ============================================================================ #endif // RLV_VIEWER2_H diff --git a/indra/newview/statemachine/aifetchinventoryfolder.cpp b/indra/newview/statemachine/aifetchinventoryfolder.cpp index b757872a1..4e8e16456 100644 --- a/indra/newview/statemachine/aifetchinventoryfolder.cpp +++ b/indra/newview/statemachine/aifetchinventoryfolder.cpp @@ -32,6 +32,7 @@ #include "aifetchinventoryfolder.h" #include "aievent.h" #include "llagent.h" +#include "llinventoryobserver.h" enum fetchinventoryfolder_state_type { AIFetchInventoryFolder_checkFolderExists = AIStateMachine::max_state,