diff options
Diffstat (limited to 'indra/newview/llinventorymodel.cpp')
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 448 |
1 files changed, 345 insertions, 103 deletions
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 08229d3a50..6452ae82f8 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -2,25 +2,31 @@ * @file llinventorymodel.cpp * @brief Implementation of the inventory model used to track agent inventory. * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ @@ -29,7 +35,6 @@ #include "llagent.h" #include "llagentwearables.h" -#include "llappearancemgr.h" #include "llinventorypanel.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" @@ -288,30 +293,6 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, items = get_ptr_in_map(mParentChildItemTree, 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, @@ -338,18 +319,30 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id) // specifies 'type' as what it defaults to containing. The category is // not necessarily only for that type. *NOTE: This will create a new // inventory category on the fly if one does not exist. -const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, - bool create_folder, - bool find_in_library) +const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType t, bool create_folder, bool find_in_library) +{ + const LLUUID &rv = findCatUUID(t, find_in_library); + if(rv.isNull() && isInventoryUsable() && (create_folder && !find_in_library)) + { + const LLUUID &root_id = gInventory.getRootFolderID(); + if(root_id.notNull()) + { + return createNewCategory(root_id, t, LLStringUtil::null); + } + } + return rv; +} + +// Internal method which looks for a category with the specified +// preferred type. Returns LLUUID::null if not found. +const LLUUID &LLInventoryModel::findCatUUID(LLFolderType::EType preferred_type, bool find_in_library) const { - LLUUID rv = LLUUID::null; - const LLUUID &root_id = (find_in_library) ? gInventory.getLibraryRootFolderID() : gInventory.getRootFolderID(); if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) { - rv = root_id; + return root_id; } - else if (root_id.notNull()) + if(root_id.notNull()) { cat_array_t* cats = NULL; cats = get_ptr_in_map(mParentChildCategoryTree, root_id); @@ -360,21 +353,12 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe { if(cats->get(i)->getPreferredType() == preferred_type) { - rv = cats->get(i)->getUUID(); - break; + return cats->get(i)->getUUID(); } } } } - - if(rv.isNull() && isInventoryUsable() && (create_folder && !find_in_library)) - { - if(root_id.notNull()) - { - return createNewCategory(root_id, preferred_type, LLStringUtil::null); - } - } - return rv; + return LLUUID::null; } // Convenience function to create a new category. You could call @@ -585,11 +569,6 @@ const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const return item->getLinkedUUID(); } -LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) const -{ - return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; -} - LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id, const LLUUID& start_folder_id) { @@ -604,6 +583,27 @@ 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) const +{ + std::string temp; + const 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; @@ -739,20 +739,8 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) // Valid UUID; set the item UUID and rename it new_item->setCreator(id); std::string avatar_name; - - if (gCacheName->getFullName(id, avatar_name)) - { - new_item->rename(avatar_name); - mask |= LLInventoryObserver::LABEL; - } - else - { - // Fetch the current name - gCacheName->get(id, FALSE, - boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), - _1, _2, _3)); - } - + // Fetch the currect name + gCacheName->get(id, FALSE, boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), _1, _2, _3)); } } else if (new_item->getType() == LLAssetType::AT_GESTURE) @@ -1036,6 +1024,98 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) } } +void LLInventoryModel::deleteFromServer(LLDynamicArray<LLUUID>& category_ids, + LLDynamicArray<LLUUID>& 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<LLUUID> ignore_parents; + update_map_t inc_parents; + + S32 i; + S32 count = category_ids.count(); + BOOL start_new_message = TRUE; + LLMessageSystem* msg = gMessageSystem; + LLPointer<LLViewerInventoryCategory> 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<LLUUID>::iterator not_ignored = ignore_parents.end(); + LLPointer<LLViewerInventoryItem> 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) @@ -1126,7 +1206,29 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) } } -// If we get back a normal response, handle it here +// This method to prepares a set of mock inventory which provides +// minimal functionality before the actual arrival of inventory. +/* +void LLInventoryModel::mock(const LLUUID& root_id) +{ + llinfos << "LLInventoryModel::mock() " << root_id << llendl; + if(root_id.isNull()) + { + llwarns << "Not a valid root id" << llendl; + return; + } + LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory( + root_id, + LLUUID::null, + LLAssetType::AT_CATEGORY, + LLFolderType::lookupNewCategoryName(LLFolderType::FT_ROOT_INVENTORY), + gAgent.getID()); + addCategory(cat); + gInventory.buildParentChildMap(); +} +*/ + +//If we get back a normal response, handle it here void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) { start_new_inventory_observer(); @@ -1199,7 +1301,7 @@ void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::str gInventory.notifyObservers("fetchinventory"); } -bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const +bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) { if(folder_id.isNull()) { @@ -1227,6 +1329,7 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const return cat->fetch(); } + void LLInventoryModel::cache( const LLUUID& parent_folder_id, const LLUUID& agent_id) @@ -1272,9 +1375,6 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) //llinfos << "LLInventoryModel::addCategory()" << llendl; if(category) { - // try to localize default names first. See EXT-8319, EXT-7051. - category->localizeName(); - // Insert category uniquely into the map mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one //mInventory[category->getUUID()] = category; @@ -1283,6 +1383,8 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) void LLInventoryModel::addItem(LLViewerInventoryItem* item) { + //llinfos << "LLInventoryModel::addItem()" << llendl; + llassert(item); if(item) { @@ -1681,17 +1783,6 @@ bool LLInventoryModel::loadSkeleton( } } - // Invalidate all categories that failed fetching descendents for whatever - // reason (e.g. one of the descendents was a broken link). - for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); - invalid_cat_it != invalid_categories.end(); - invalid_cat_it++) - { - LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); - cat->setVersion(NO_VERSION); - llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; - } - // At this point, we need to set the known descendents for each // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. @@ -1714,6 +1805,17 @@ bool LLInventoryModel::loadSkeleton( } } + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; + } + if(remove_inventory_file) { // clean up the gunzipped file. @@ -1735,6 +1837,88 @@ bool LLInventoryModel::loadSkeleton( return rv; } +bool LLInventoryModel::loadMeat(const LLSD& options, const LLUUID& owner_id) +{ + llinfos << "importing inventory for " << owner_id << llendl; + bool rv = true; + for(LLSD::array_const_iterator it = options.beginArray(), + end = options.endArray(); it != end; ++it) + { + LLSD name = (*it)["name"]; + LLSD item_id = (*it)["item_id"]; + LLSD parent_id = (*it)["parent_id"]; + LLSD asset_type = (*it)["type"]; + LLSD data_id = (*it)["data_id"]; + if(name.isDefined() + && item_id.isDefined() + && parent_id.isDefined() + && asset_type.isDefined() + && data_id.isDefined()) + { + LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem; + item->rename(name.asString()); + item->setUUID(item_id.asUUID()); + item->setParent(parent_id.asUUID()); + LLAssetType::EType type = (LLAssetType::EType)asset_type.asInteger(); + item->setType(type); + + LLSD llsd_inv_type = (*it)["inv_type"]; + if(llsd_inv_type.isDefined()) + { + LLInventoryType::EType inv_type = (LLInventoryType::EType)llsd_inv_type.asInteger(); + item->setInventoryType(inv_type); + } + + if(LLAssetType::AT_CALLINGCARD == type) + { + LLPermissions perm; + perm.init(data_id.asUUID(), owner_id, LLUUID::null, LLUUID::null); + item->setPermissions(perm); + } + else + { + LLPermissions default_perm; + default_perm.init(LLUUID::null, owner_id, LLUUID::null, LLUUID::null); + LLSD llsd_perm_mask = (*it)["perm_mask"]; + if(llsd_perm_mask.isDefined()) + { + PermissionMask perm_mask = llsd_perm_mask.asInteger(); + default_perm.initMasks( + perm_mask, perm_mask, perm_mask, perm_mask, perm_mask); + } + else + { + default_perm.initMasks( + PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE); + } + item->setPermissions(default_perm); + item->setAssetUUID(data_id.asUUID()); + } + + LLSD flags = (*it)["flags"]; + if(flags.isDefined()) + { + // Not sure how well LLSD.asInteger() maps to + // unsigned long - using strtoul() + item->setFlags(strtoul(flags.asString().c_str(), NULL, 0)); + } + + LLSD time = (*it)["time"]; + if(time.isDefined()) + { + item->setCreationDate(time.asInteger()); + } + addItem(item); + } + else + { + llwarns << "Unable to import near " << name.asString() << llendl; + rv = false; + } + } + return rv; +} + // This is a brute force method to rebuild the entire parent-child // relations. The overall operation has O(NlogN) performance, which // should be sufficient for our needs. @@ -2002,6 +2186,73 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const return (mID > rhs.mID); } +// Given the current state of the inventory items, figure out the +// clone information. *FIX: This is sub-optimal, since we can insert +// this information snurgically, but this makes sure the implementation +// works before we worry about optimization. +//void LLInventoryModel::recalculateCloneInformation() +//{ +// //dumpInventory(); +// +// // This implements a 'multi-map' like structure to keep track of +// // how many clones we find. +// typedef LLDynamicArray<LLViewerInventoryItem*> viewer_item_array_t; +// typedef std::map<LLUUIDAndName, viewer_item_array_t*> clone_map_t; +// clone_map_t clone_map; +// LLUUIDAndName id_and_name; +// viewer_item_array_t* clones = NULL; +// LLViewerInventoryItem* item = NULL; +// for(item = (LLViewerInventoryItem*)mItemMap.getFirstData(); +// item != NULL; +// item = (LLViewerInventoryItem*)mItemMap.getNextData()) +// { +// if(item->getType() == LLAssetType::AT_CALLINGCARD) +// { +// // if it's a calling card, we key off of the creator id, not +// // the asset id. +// id_and_name.mID = item->getCreatorUUID(); +// } +// else +// { +// // if it's not a calling card, we key clones from the +// // asset id. +// id_and_name.mID = item->getAssetUUID(); +// } +// if(id_and_name.mID == LLUUID::null) +// { +// continue; +// } +// id_and_name.mName = item->getName(); +// if(clone_map.checkData(id_and_name)) +// { +// clones = clone_map.getData(id_and_name); +// } +// else +// { +// clones = new viewer_item_array_t; +// clone_map.addData(id_and_name, clones); +// } +// clones->put(item); +// } +// +// S32 count = 0; +// for(clones = clone_map.getFirstData(); +// clones != NULL; +// clones = clone_map.getNextData()) +// { +// count = clones->count(); +// for(S32 i = 0; i < count; i++) +// { +// item = clones->get(i); +// item->setCloneCount(count - 1); +// //clones[i] = NULL; +// } +// delete clones; +// } +// clone_map.removeAllData(); +// //dumpInventory(); +//} + // static bool LLInventoryModel::loadFromFile(const std::string& filename, LLInventoryModel::cat_array_t& categories, @@ -2468,9 +2719,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) } LLUUID tid; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); -#ifndef LL_RELEASE_FOR_DOWNLOAD llinfos << "Bulk inventory: " << tid << llendl; -#endif update_map_t update; cat_array_t folders; @@ -2591,7 +2840,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { LLViewerInventoryItem* wearable_item; wearable_item = gInventory.getItem(wearable_ids[i]); - LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); + wear_inventory_item_on_avatar(wearable_item); } } @@ -2849,10 +3098,6 @@ static LLInventoryModel::item_array_t::iterator find_item_iter_by_uuid(LLInvento } // static -// * @param[in, out] items - vector with items to be updated. It should be sorted in a right way -// * before calling this method. -// * @param src_item_id - LLUUID of inventory item to be moved in new position -// * @param dest_item_id - LLUUID of inventory item before which source item should be placed. void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id) { LLInventoryModel::item_array_t::iterator it_src = find_item_iter_by_uuid(items, src_item_id); @@ -2868,7 +3113,6 @@ void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, c items.insert(it_dest, src_item); } -//* @param[in] items vector of items in order to be saved. void LLInventoryModel::saveItemsOrder(const LLInventoryModel::item_array_t& items) { int sortField = 0; @@ -2912,8 +3156,6 @@ static void rearrange_item_order_by_sort_field(LLInventoryModel::item_array_t& i std::sort(items.begin(), items.end(), sort_functor); } -// * @param source_item_id - LLUUID of the source item to be moved into new position -// * @param target_item_id - LLUUID of the target item before which source item should be placed. void LLInventoryModel::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id) { LLInventoryModel::cat_array_t cats; |