diff options
Diffstat (limited to 'indra/newview/llviewerinventory.cpp')
-rw-r--r-- | indra/newview/llviewerinventory.cpp | 1111 |
1 files changed, 991 insertions, 120 deletions
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 45d24ee7e8..75a5b14154 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -2,61 +2,215 @@ * @file llviewerinventory.cpp * @brief Implementation of the viewer side inventory objects. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * 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 + * 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. * - * 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 + * 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. * - * 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. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llviewerinventory.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" #include "message.h" -#include "indra_constants.h" #include "llagent.h" +#include "llagentcamera.h" +#include "llagentwearables.h" +#include "llviewerfoldertype.h" +#include "llfolderview.h" #include "llviewercontrol.h" #include "llconsole.h" +#include "llinventorydefines.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" -#include "llnotify.h" -#include "llimview.h" +#include "llinventorymodelbackgroundfetch.h" #include "llgesturemgr.h" +#include "llsidetray.h" #include "llinventorybridge.h" -#include "llinventoryview.h" +#include "llinventorypanel.h" +#include "llfloaterinventory.h" +#include "llviewerassettype.h" #include "llviewerregion.h" #include "llviewerobjectlist.h" #include "llpreviewgesture.h" #include "llviewerwindow.h" #include "lltrans.h" +#include "llappearancemgr.h" +#include "llcommandhandler.h" +#include "llviewermessage.h" +#include "llsidepanelappearance.h" + +///---------------------------------------------------------------------------- +/// Helper class to store special inventory item names and their localized values. +///---------------------------------------------------------------------------- +class LLLocalizedInventoryItemsDictionary : public LLSingleton<LLLocalizedInventoryItemsDictionary> +{ +public: + std::map<std::string, std::string> mInventoryItemsDict; + + LLLocalizedInventoryItemsDictionary() + { + mInventoryItemsDict["New Shape"] = LLTrans::getString("New Shape"); + mInventoryItemsDict["New Skin"] = LLTrans::getString("New Skin"); + mInventoryItemsDict["New Hair"] = LLTrans::getString("New Hair"); + mInventoryItemsDict["New Eyes"] = LLTrans::getString("New Eyes"); + mInventoryItemsDict["New Shirt"] = LLTrans::getString("New Shirt"); + mInventoryItemsDict["New Pants"] = LLTrans::getString("New Pants"); + mInventoryItemsDict["New Shoes"] = LLTrans::getString("New Shoes"); + mInventoryItemsDict["New Socks"] = LLTrans::getString("New Socks"); + mInventoryItemsDict["New Jacket"] = LLTrans::getString("New Jacket"); + mInventoryItemsDict["New Gloves"] = LLTrans::getString("New Gloves"); + mInventoryItemsDict["New Undershirt"] = LLTrans::getString("New Undershirt"); + mInventoryItemsDict["New Underpants"] = LLTrans::getString("New Underpants"); + mInventoryItemsDict["New Skirt"] = LLTrans::getString("New Skirt"); + mInventoryItemsDict["New Alpha"] = LLTrans::getString("New Alpha"); + mInventoryItemsDict["New Tattoo"] = LLTrans::getString("New Tattoo"); + mInventoryItemsDict["Invalid Wearable"] = LLTrans::getString("Invalid Wearable"); + + mInventoryItemsDict["New Gesture"] = LLTrans::getString("New Gesture"); + mInventoryItemsDict["New Script"] = LLTrans::getString("New Script"); + mInventoryItemsDict["New Folder"] = LLTrans::getString("New Folder"); + mInventoryItemsDict["New Note"] = LLTrans::getString("New Note"); + mInventoryItemsDict["Contents"] = LLTrans::getString("Contents"); + + mInventoryItemsDict["Gesture"] = LLTrans::getString("Gesture"); + mInventoryItemsDict["Male Gestures"] = LLTrans::getString("Male Gestures"); + mInventoryItemsDict["Female Gestures"] = LLTrans::getString("Female Gestures"); + mInventoryItemsDict["Other Gestures"] = LLTrans::getString("Other Gestures"); + mInventoryItemsDict["Speech Gestures"] = LLTrans::getString("Speech Gestures"); + mInventoryItemsDict["Common Gestures"] = LLTrans::getString("Common Gestures"); + + //predefined gestures + + //male + mInventoryItemsDict["Male - Excuse me"] = LLTrans::getString("Male - Excuse me"); + mInventoryItemsDict["Male - Get lost"] = LLTrans::getString("Male - Get lost"); // double space after Male. EXT-8319 + mInventoryItemsDict["Male - Blow kiss"] = LLTrans::getString("Male - Blow kiss"); + mInventoryItemsDict["Male - Boo"] = LLTrans::getString("Male - Boo"); + mInventoryItemsDict["Male - Bored"] = LLTrans::getString("Male - Bored"); + mInventoryItemsDict["Male - Hey"] = LLTrans::getString("Male - Hey"); + mInventoryItemsDict["Male - Laugh"] = LLTrans::getString("Male - Laugh"); + mInventoryItemsDict["Male - Repulsed"] = LLTrans::getString("Male - Repulsed"); + mInventoryItemsDict["Male - Shrug"] = LLTrans::getString("Male - Shrug"); + mInventoryItemsDict["Male - Stick tougue out"] = LLTrans::getString("Male - Stick tougue out"); + mInventoryItemsDict["Male - Wow"] = LLTrans::getString("Male - Wow"); + + //female + mInventoryItemsDict["Female - Chuckle"] = LLTrans::getString("Female - Chuckle"); + mInventoryItemsDict["Female - Cry"] = LLTrans::getString("Female - Cry"); + mInventoryItemsDict["Female - Embarrassed"] = LLTrans::getString("Female - Embarrassed"); + mInventoryItemsDict["Female - Excuse me"] = LLTrans::getString("Female - Excuse me"); + mInventoryItemsDict["Female - Get lost"] = LLTrans::getString("Female - Get lost"); // double space after Female. EXT-8319 + mInventoryItemsDict["Female - Blow kiss"] = LLTrans::getString("Female - Blow kiss"); + mInventoryItemsDict["Female - Boo"] = LLTrans::getString("Female - Boo"); + mInventoryItemsDict["Female - Bored"] = LLTrans::getString("Female - Bored"); + mInventoryItemsDict["Female - Hey"] = LLTrans::getString("Female - Hey"); + mInventoryItemsDict["Female - Hey baby"] = LLTrans::getString("Female - Hey baby"); + mInventoryItemsDict["Female - Laugh"] = LLTrans::getString("Female - Laugh"); + mInventoryItemsDict["Female - Looking good"] = LLTrans::getString("Female - Looking good"); + mInventoryItemsDict["Female - Over here"] = LLTrans::getString("Female - Over here"); + mInventoryItemsDict["Female - Please"] = LLTrans::getString("Female - Please"); + mInventoryItemsDict["Female - Repulsed"] = LLTrans::getString("Female - Repulsed"); + mInventoryItemsDict["Female - Shrug"] = LLTrans::getString("Female - Shrug"); + mInventoryItemsDict["Female - Stick tougue out"]= LLTrans::getString("Female - Stick tougue out"); + mInventoryItemsDict["Female - Wow"] = LLTrans::getString("Female - Wow"); + + } + + /** + * Finds passed name in dictionary and replaces it with found localized value. + * + * @param object_name - string to be localized. + * @return true if passed name was found and localized, false otherwise. + */ + bool localizeInventoryObjectName(std::string& object_name) + { + LL_DEBUGS("InventoryLocalize") << "Searching for localization: " << object_name << LL_ENDL; + + std::map<std::string, std::string>::const_iterator dictionary_iter = mInventoryItemsDict.find(object_name); + + bool found = dictionary_iter != mInventoryItemsDict.end(); + if(found) + { + object_name = dictionary_iter->second; + LL_DEBUGS("InventoryLocalize") << "Found, new name is: " << object_name << LL_ENDL; + } + return found; + } +}; + ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- +class LLInventoryHandler : public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) + { + if (params.size() < 1) + { + return false; + } + + // support secondlife:///app/inventory/show + if (params[0].asString() == "show") + { + LLSideTray::getInstance()->showPanel("sidepanel_inventory", LLSD()); + return true; + } + + // otherwise, we need a UUID and a verb... + if (params.size() < 2) + { + return false; + } + LLUUID inventory_id; + if (!inventory_id.set(params[0], FALSE)) + { + return false; + } + + const std::string verb = params[1].asString(); + if (verb == "select") + { + uuid_vec_t items_to_open; + items_to_open.push_back(inventory_id); + //inventory_handler is just a stub, because we don't know from who this offer + open_inventory_offer(items_to_open, "inventory_handler"); + return true; + } + + return false; + } +}; +LLInventoryHandler gInventoryHandler; + ///---------------------------------------------------------------------------- /// Class LLViewerInventoryItem ///---------------------------------------------------------------------------- @@ -201,10 +355,23 @@ void LLViewerInventoryItem::fetchFromServer(void) const { std::string url; - if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString()) - url = gAgent.getRegion()->getCapability("FetchLib"); - else - url = gAgent.getRegion()->getCapability("FetchInventory"); + LLViewerRegion* region = gAgent.getRegion(); + // we have to check region. It can be null after region was destroyed. See EXT-245 + if (region) + { + if(gAgent.getID() != mPermissions.getOwner()) + { + url = region->getCapability("FetchLib"); + } + else + { + url = region->getCapability("FetchInventory"); + } + } + else + { + llwarns << "Agent Region is absent" << llendl; + } if (!url.empty()) { @@ -244,10 +411,12 @@ BOOL LLViewerInventoryItem::unpackMessage(LLSD item) } // virtual -BOOL LLViewerInventoryItem::unpackMessage( - LLMessageSystem* msg, const char* block, S32 block_num) +BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) { BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num); + + LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName); + mIsComplete = TRUE; return rv; } @@ -348,7 +517,7 @@ void LLViewerInventoryItem::updateParentOnServer(BOOL restamp) const LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid, const LLUUID& parent_uuid, - LLAssetType::EType pref, + LLFolderType::EType pref, const std::string& name, const LLUUID& owner_id) : LLInventoryCategory(uuid, parent_uuid, pref, name), @@ -404,9 +573,10 @@ void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const void LLViewerInventoryCategory::updateServer(BOOL is_new) const { // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + + if (LLFolderType::lookupIsProtectedType(mPreferredType)) { - LLNotifications::instance().add("CannotModifyProtectedCategories"); + LLNotificationsUtil::add("CannotModifyProtectedCategories"); return; } @@ -428,9 +598,9 @@ void LLViewerInventoryCategory::removeFromServer( void ) llinfos << "Removing inventory category " << mUUID << " from server." << llendl; // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + if(LLFolderType::lookupIsProtectedType(mPreferredType)) { - LLNotifications::instance().add("CannotRemoveProtectedCategories"); + LLNotificationsUtil::add("CannotRemoveProtectedCategories"); return; } @@ -447,11 +617,12 @@ void LLViewerInventoryCategory::removeFromServer( void ) gAgent.sendReliableMessage(); } -bool LLViewerInventoryCategory::fetchDescendents() +bool LLViewerInventoryCategory::fetch() { if((VERSION_UNKNOWN == mVersion) && mDescendentsRequested.hasExpired()) //Expired check prevents multiple downloads. { + LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL; const F32 FETCH_TIMER_EXPIRY = 10.0f; mDescendentsRequested.reset(); mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY); @@ -461,13 +632,26 @@ bool LLViewerInventoryCategory::fetchDescendents() // 2 = folders by date // Need to mask off anything but the first bit. // This comes from LLInventoryFilter from llfolderview.h - U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1; + U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1; - std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents"); - + // *NOTE: For bug EXT-2879, originally commented out + // gAgent.getRegion()->getCapability in order to use the old + // message-based system. This has been uncommented now that + // AIS folks are aware of the issue and have a fix in process. + // see ticket for details. + + std::string url; + if (gAgent.getRegion()) + { + url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents"); + } + else + { + llwarns << "agent region is null" << llendl; + } if (!url.empty()) //Capability found. Build up LLSD and use it. { - LLInventoryModel::startBackgroundFetch(mUUID); + LLInventoryModelBackgroundFetch::instance().start(mUUID, false); } else { //Deprecated, but if we don't have a capability, use the old system. @@ -531,7 +715,7 @@ bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp) } else if(0 == strcmp("pref_type", keyword)) { - mPreferredType = LLAssetType::lookup(valuestr); + mPreferredType = LLFolderType::lookup(valuestr); } else if(0 == strcmp("name", keyword)) { @@ -569,7 +753,7 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const mParentUUID.toString(uuid_str); fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str()); fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType)); - fprintf(fp, "\t\tpref_type\t%s\n", LLAssetType::lookup(mPreferredType)); + fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str()); fprintf(fp, "\t\tname\t%s|\n", mName.c_str()); mOwnerID.toString(uuid_str); fprintf(fp, "\t\towner_id\t%s\n", uuid_str.c_str()); @@ -578,6 +762,84 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const return true; } +void LLViewerInventoryCategory::determineFolderType() +{ + /* Do NOT uncomment this code. This is for future 2.1 support of ensembles. + llassert(FALSE); + LLFolderType::EType original_type = getPreferredType(); + if (LLFolderType::lookupIsProtectedType(original_type)) + return; + + U64 folder_valid = 0; + U64 folder_invalid = 0; + LLInventoryModel::cat_array_t category_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getUUID(),category_array,item_array,FALSE); + + // For ensembles + if (category_array.empty()) + { + for (LLInventoryModel::item_array_t::iterator item_iter = item_array.begin(); + item_iter != item_array.end(); + item_iter++) + { + const LLViewerInventoryItem *item = (*item_iter); + if (item->getIsLinkType()) + return; + if (item->isWearableType()) + { + const LLWearableType::EType wearable_type = item->getWearableType(); + const std::string& wearable_name = LLWearableType::getTypeName(wearable_type); + U64 valid_folder_types = LLViewerFolderType::lookupValidFolderTypes(wearable_name); + folder_valid |= valid_folder_types; + folder_invalid |= ~valid_folder_types; + } + } + for (U8 i = LLFolderType::FT_ENSEMBLE_START; i <= LLFolderType::FT_ENSEMBLE_END; i++) + { + if ((folder_valid & (1LL << i)) && + !(folder_invalid & (1LL << i))) + { + changeType((LLFolderType::EType)i); + return; + } + } + } + if (LLFolderType::lookupIsEnsembleType(original_type)) + { + changeType(LLFolderType::FT_NONE); + } + llassert(FALSE); + */ +} + +void LLViewerInventoryCategory::changeType(LLFolderType::EType new_folder_type) +{ + const LLUUID &folder_id = getUUID(); + const LLUUID &parent_id = getParentUUID(); + const std::string &name = getName(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->addUUIDFast(_PREHASH_ParentID, parent_id); + msg->addS8Fast(_PREHASH_Type, new_folder_type); + msg->addStringFast(_PREHASH_Name, name); + gAgent.sendReliableMessage(); + + setPreferredType(new_folder_type); + gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); +} + +void LLViewerInventoryCategory::localizeName() +{ + LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName); +} + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- @@ -605,6 +867,21 @@ LLInventoryCallbackManager::~LLInventoryCallbackManager() sInstance = NULL; } +//static +void LLInventoryCallbackManager::destroyClass() +{ + if (sInstance) + { + for (callback_map_t::iterator it = sInstance->mMap.begin(), end_it = sInstance->mMap.end(); it != end_it; ++it) + { + // drop LLPointer reference to callback + it->second = NULL; + } + sInstance->mMap.clear(); + } +} + + U32 LLInventoryCallbackManager::registerCB(LLPointer<LLInventoryCallback> cb) { if (cb.isNull()) @@ -641,7 +918,26 @@ void WearOnAvatarCallback::fire(const LLUUID& inv_item) LLViewerInventoryItem *item = gInventory.getItem(inv_item); if (item) { - wear_inventory_item_on_avatar(item); + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item, true, mReplace); + } +} + +void ModifiedCOFCallback::fire(const LLUUID& inv_item) +{ + LLAppearanceMgr::instance().updateAppearanceFromCOF(); + + // Start editing the item if previously requested. + gAgentWearables.editWearableIfRequested(inv_item); + + // TODO: camera mode may not be changed if a debug setting is tweaked + if( gAgentCamera.cameraCustomizeAvatar() ) + { + // If we're in appearance editing mode, the current tab may need to be refreshed + LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLSideTray::getInstance()->getPanel("sidepanel_appearance")); + if (panel) + { + panel->showDefaultSubpart(); + } } } @@ -665,13 +961,17 @@ void RezAttachmentCallback::fire(const LLUUID& inv_item) } } -extern LLGestureManager gGestureManager; void ActivateGestureCallback::fire(const LLUUID& inv_item) { if (inv_item.isNull()) return; + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (!item) + return; + if (item->getType() != LLAssetType::AT_GESTURE) + return; - gGestureManager.activateGesture(inv_item); + LLGestureMgr::instance().activateGesture(inv_item); } void CreateGestureCallback::fire(const LLUUID& inv_item) @@ -679,7 +979,7 @@ void CreateGestureCallback::fire(const LLUUID& inv_item) if (inv_item.isNull()) return; - gGestureManager.activateGesture(inv_item); + LLGestureMgr::instance().activateGesture(inv_item); LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (!item) return; @@ -691,16 +991,42 @@ void CreateGestureCallback::fire(const LLUUID& inv_item) gFloaterView->adjustToFitScreen(preview, FALSE); } +void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) +{ + if (mTargetLandmarkId.isNull()) return; + + gInventory.rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); +} + LLInventoryCallbackManager gInventoryCallbacks; void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, const LLUUID& parent, const LLTransactionID& transaction_id, const std::string& name, const std::string& desc, LLAssetType::EType asset_type, - LLInventoryType::EType inv_type, EWearableType wtype, + LLInventoryType::EType inv_type, LLWearableType::EType wtype, U32 next_owner_perm, LLPointer<LLInventoryCallback> cb) { + //check if name is equal to one of special inventory items names + //EXT-5839 + std::string server_name = name; + + { + std::map<std::string, std::string>::const_iterator dictionary_iter; + + for (dictionary_iter = LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.begin(); + dictionary_iter != LLLocalizedInventoryItemsDictionary::getInstance()->mInventoryItemsDict.end(); + dictionary_iter++) + { + const std::string& localized_name = dictionary_iter->second; + if(localized_name == name) + { + server_name = dictionary_iter->first; + } + } + } + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_CreateInventoryItem); msg->nextBlock(_PREHASH_AgentData); @@ -714,12 +1040,22 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, msg->addS8Fast(_PREHASH_Type, (S8)asset_type); msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); msg->addU8Fast(_PREHASH_WearableType, (U8)wtype); - msg->addStringFast(_PREHASH_Name, name); + msg->addStringFast(_PREHASH_Name, server_name); msg->addStringFast(_PREHASH_Description, desc); gAgent.sendReliableMessage(); } +void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer<LLInventoryCallback> cb/*=NULL*/) +{ + std::string item_desc = avatar_id.asString(); + std::string item_name; + gCacheName->getFullName(avatar_id, item_name); + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD, + LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); +} + void copy_inventory_item( const LLUUID& agent_id, const LLUUID& current_owner, @@ -742,6 +1078,72 @@ void copy_inventory_item( gAgent.sendReliableMessage(); } +void link_inventory_item( + const LLUUID& agent_id, + const LLUUID& item_id, + const LLUUID& parent_id, + const std::string& new_name, + const std::string& new_description, + const LLAssetType::EType asset_type, + LLPointer<LLInventoryCallback> cb) +{ + const LLInventoryObject *baseobj = gInventory.getObject(item_id); + if (!baseobj) + { + llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl; + return; + } + if (baseobj && baseobj->getIsLinkType()) + { + llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl; + return; + } + + if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType())) + { + // Fail if item can be found but is of a type that can't be linked. + // Arguably should fail if the item can't be found too, but that could + // be a larger behavioral change. + llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl; + return; + } + + LLUUID transaction_id; + LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; + if (dynamic_cast<const LLInventoryCategory *>(baseobj)) + { + inv_type = LLInventoryType::IT_CATEGORY; + } + else + { + const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj); + if (baseitem) + { + inv_type = baseitem->getInventoryType(); + } + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LinkInventoryItem); + msg->nextBlock(_PREHASH_AgentData); + { + msg->addUUIDFast(_PREHASH_AgentID, agent_id); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlock(_PREHASH_InventoryBlock); + { + msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); + msg->addUUIDFast(_PREHASH_FolderID, parent_id); + msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); + msg->addUUIDFast(_PREHASH_OldItemID, item_id); + msg->addS8Fast(_PREHASH_Type, (S8)asset_type); + msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); + msg->addStringFast(_PREHASH_Name, new_name); + msg->addStringFast(_PREHASH_Description, new_description); + } + gAgent.sendReliableMessage(); +} + void move_inventory_item( const LLUUID& agent_id, const LLUUID& session_id, @@ -765,6 +1167,14 @@ void move_inventory_item( void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecard_inv_id, const LLInventoryItem *src, U32 callback_id) { + if (NULL == src) + { + LL_WARNS("copy_inventory_from_notecard") << "Null pointer to item was passed for object_id " + << object_id << " and notecard_inv_id " + << notecard_inv_id << LL_ENDL; + return; + } + LLViewerRegion* viewer_region = NULL; LLViewerObject* vo = NULL; if (object_id.notNull() && (vo = gObjectList.findObject(object_id)) != NULL) @@ -787,11 +1197,21 @@ void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecar return; } + // check capability to prevent a crash while LL_ERRS in LLCapabilityListener::capListener. See EXT-8459. + std::string url = viewer_region->getCapability("CopyInventoryFromNotecard"); + if (url.empty()) + { + LL_WARNS("copy_inventory_from_notecard") << "There is no 'CopyInventoryFromNotecard' capability" + << " for region: " << viewer_region->getName() + << LL_ENDL; + return; + } + LLSD request, body; body["notecard-id"] = notecard_inv_id; body["object-id"] = object_id; body["item-id"] = src->getUUID(); - body["folder-id"] = gInventory.findCategoryUUIDForType(src->getType()); + body["folder-id"] = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(src->getType())); body["callback-id"] = (LLSD::Integer)callback_id; request["message"] = "CopyInventoryFromNotecard"; @@ -807,7 +1227,7 @@ void create_new_item(const std::string& name, U32 next_owner_perm) { std::string desc; - LLAssetType::generateDescriptionFor(asset_type, desc); + LLViewerAssetType::generateDescriptionFor(asset_type, desc); next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER; @@ -832,154 +1252,605 @@ const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) -void menu_create_inventory_item(LLFolderView* folder, LLFolderBridge *bridge, const LLSD& userdata) +// ! REFACTOR ! Really need to refactor this so that it's not a bunch of if-then statements... +void menu_create_inventory_item(LLFolderView* root, LLFolderBridge *bridge, const LLSD& userdata, const LLUUID& default_parent_uuid) { - std::string type = userdata.asString(); + std::string type_name = userdata.asString(); - if ("category" == type) + if (("category" == type_name) || ("current" == type_name) || ("outfit" == type_name) || ("my_otfts" == type_name)) { - LLUUID category; + LLFolderType::EType preferred_type = LLFolderType::lookup(type_name); + + LLUUID parent_id; if (bridge) { - category = gInventory.createNewCategory(bridge->getUUID(), LLAssetType::AT_NONE, LLStringUtil::null); + parent_id = bridge->getUUID(); + } + else if (default_parent_uuid.notNull()) + { + parent_id = default_parent_uuid; } else { - category = gInventory.createNewCategory(gAgent.getInventoryRootID(), LLAssetType::AT_NONE, LLStringUtil::null); + parent_id = gInventory.getRootFolderID(); } + + LLUUID category = gInventory.createNewCategory(parent_id, preferred_type, LLStringUtil::null); gInventory.notifyObservers(); - folder->setSelectionByID(category, TRUE); + root->setSelectionByID(category, TRUE); } - else if ("lsl" == type) + else if ("lsl" == type_name) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_LSL_TEXT); + const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT); create_new_item(NEW_LSL_NAME, parent_id, LLAssetType::AT_LSL_TEXT, LLInventoryType::IT_LSL, PERM_MOVE | PERM_TRANSFER); } - else if ("notecard" == type) + else if ("notecard" == type_name) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_NOTECARD); + const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD); create_new_item(NEW_NOTECARD_NAME, parent_id, LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, PERM_ALL); } - else if ("gesture" == type) + else if ("gesture" == type_name) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE); + const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); create_new_item(NEW_GESTURE_NAME, parent_id, LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, PERM_ALL); } - else if ("shirt" == type) + else + { + // Use for all clothing and body parts. Adding new wearable types requires updating LLWearableDictionary. + LLWearableType::EType wearable_type = LLWearableType::typeNameToType(type_name); + if (wearable_type >= LLWearableType::WT_SHAPE && wearable_type < LLWearableType::WT_COUNT) + { + const LLUUID parent_id = bridge ? bridge->getUUID() : LLUUID::null; + LLAgentWearables::createWearable(wearable_type, false, parent_id); + } + else + { + llwarns << "Can't create unrecognized type " << type_name << llendl; + } + } + root->setNeedsAutoRename(TRUE); +} + +LLAssetType::EType LLViewerInventoryItem::getType() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_SHIRT); + return linked_item->getType(); } - else if ("pants" == type) + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) + { + return linked_category->getType(); + } + return LLInventoryItem::getType(); +} + +const LLUUID& LLViewerInventoryItem::getAssetUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_PANTS); + return linked_item->getAssetUUID(); } - else if ("shoes" == type) + + return LLInventoryItem::getAssetUUID(); +} + +const LLUUID& LLViewerInventoryItem::getProtectedAssetUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_SHOES); + return linked_item->getProtectedAssetUUID(); } - else if ("socks" == type) + + // check for conditions under which we may return a visible UUID to the user + bool item_is_fullperm = getIsFullPerm(); + bool agent_is_godlike = gAgent.isGodlikeWithoutAdminMenuFakery(); + if (item_is_fullperm || agent_is_godlike) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_SOCKS); + return LLInventoryItem::getAssetUUID(); } - else if ("jacket" == type) + + return LLUUID::null; +} + +const bool LLViewerInventoryItem::getIsFullPerm() const +{ + LLPermissions item_permissions = getPermissions(); + + // modify-ok & copy-ok & transfer-ok + return ( item_permissions.allowOperationBy(PERM_MODIFY, + gAgent.getID(), + gAgent.getGroupID()) && + item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID()) && + item_permissions.allowOperationBy(PERM_TRANSFER, + gAgent.getID(), + gAgent.getGroupID()) ); +} + +const std::string& LLViewerInventoryItem::getName() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_JACKET); + return linked_item->getName(); } - else if ("skirt" == type) + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_SKIRT); + return linked_category->getName(); } - else if ("gloves" == type) + + return LLInventoryItem::getName(); +} + +/** + * Class to store sorting order of favorites landmarks in a local file. EXT-3985. + * It replaced previously implemented solution to store sort index in landmark's name as a "<N>@" prefix. + * Data are stored in user home directory. + */ +class LLFavoritesOrderStorage : public LLSingleton<LLFavoritesOrderStorage> + , public LLDestroyClass<LLFavoritesOrderStorage> +{ +public: + /** + * Sets sort index for specified with LLUUID favorite landmark + */ + void setSortIndex(const LLUUID& inv_item_id, S32 sort_index); + + /** + * Gets sort index for specified with LLUUID favorite landmark + */ + S32 getSortIndex(const LLUUID& inv_item_id); + void removeSortIndex(const LLUUID& inv_item_id); + + /** + * Implementation of LLDestroyClass. Calls cleanup() instance method. + * + * It is important this callback is called before gInventory is cleaned. + * For now it is called from LLAppViewer::cleanup() -> LLAppViewer::disconnectViewer(), + * Inventory is cleaned later from LLAppViewer::cleanup() after LLAppViewer::disconnectViewer() is called. + * @see cleanup() + */ + static void destroyClass(); + + const static S32 NO_INDEX; +private: + friend class LLSingleton<LLFavoritesOrderStorage>; + LLFavoritesOrderStorage() : mIsDirty(false) { load(); } + ~LLFavoritesOrderStorage() { save(); } + + /** + * Removes sort indexes for items which are not in Favorites bar for now. + */ + void cleanup(); + + const static std::string SORTING_DATA_FILE_NAME; + + void load(); + void save(); + + typedef std::map<LLUUID, S32> sort_index_map_t; + sort_index_map_t mSortIndexes; + + bool mIsDirty; + + struct IsNotInFavorites + { + IsNotInFavorites(const LLInventoryModel::item_array_t& items) + : mFavoriteItems(items) + { + + } + + /** + * Returns true if specified item is not found among inventory items + */ + bool operator()(const sort_index_map_t::value_type& id_index_pair) const + { + LLPointer<LLViewerInventoryItem> item = gInventory.getItem(id_index_pair.first); + if (item.isNull()) return true; + + LLInventoryModel::item_array_t::const_iterator found_it = + std::find(mFavoriteItems.begin(), mFavoriteItems.end(), item); + + return found_it == mFavoriteItems.end(); + } + private: + LLInventoryModel::item_array_t mFavoriteItems; + }; + +}; + +const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml"; +const S32 LLFavoritesOrderStorage::NO_INDEX = -1; + +void LLFavoritesOrderStorage::setSortIndex(const LLUUID& inv_item_id, S32 sort_index) +{ + mSortIndexes[inv_item_id] = sort_index; + mIsDirty = true; +} + +S32 LLFavoritesOrderStorage::getSortIndex(const LLUUID& inv_item_id) +{ + sort_index_map_t::const_iterator it = mSortIndexes.find(inv_item_id); + if (it != mSortIndexes.end()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_GLOVES); + return it->second; } - else if ("undershirt" == type) + return NO_INDEX; +} + +void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id) +{ + mSortIndexes.erase(inv_item_id); + mIsDirty = true; +} + +// static +void LLFavoritesOrderStorage::destroyClass() +{ + LLFavoritesOrderStorage::instance().cleanup(); +} + +void LLFavoritesOrderStorage::load() +{ + // load per-resident sorting information + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME); + + LLSD settings_llsd; + llifstream file; + file.open(filename); + if (file.is_open()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_UNDERSHIRT); + LLSDSerialize::fromXML(settings_llsd, file); } - else if ("underpants" == type) + + for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); + iter != settings_llsd.endMap(); ++iter) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); - LLFolderBridge::createWearable(parent_id, WT_UNDERPANTS); + mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); } - else if ("shape" == type) +} + +void LLFavoritesOrderStorage::save() +{ + // nothing to save if clean + if (!mIsDirty) return; + + // If we quit from the login screen we will not have an SL account + // name. Don't try to save, otherwise we'll dump a file in + // C:\Program Files\SecondLife\ or similar. JC + std::string user_dir = gDirUtilp->getLindenUserDir(); + if (!user_dir.empty()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); - LLFolderBridge::createWearable(parent_id, WT_SHAPE); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME); + LLSD settings_llsd; + + for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter) + { + settings_llsd[iter->first.asString()] = iter->second; + } + + llofstream file; + file.open(filename); + LLSDSerialize::toPrettyXML(settings_llsd, file); } - else if ("skin" == type) +} + +void LLFavoritesOrderStorage::cleanup() +{ + // nothing to clean + if (!mIsDirty) return; + + const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + + IsNotInFavorites is_not_in_fav(items); + + sort_index_map_t aTempMap; + //copy unremoved values from mSortIndexes to aTempMap + std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), + inserter(aTempMap, aTempMap.begin()), + is_not_in_fav); + + //Swap the contents of mSortIndexes and aTempMap + mSortIndexes.swap(aTempMap); +} + + +S32 LLViewerInventoryItem::getSortField() const +{ + return LLFavoritesOrderStorage::instance().getSortIndex(mUUID); +} + +void LLViewerInventoryItem::setSortField(S32 sortField) +{ + LLFavoritesOrderStorage::instance().setSortIndex(mUUID, sortField); +} + +const LLPermissions& LLViewerInventoryItem::getPermissions() const +{ + // Use the actual permissions of the symlink, not its parent. + return LLInventoryItem::getPermissions(); +} + +const LLUUID& LLViewerInventoryItem::getCreatorUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); - LLFolderBridge::createWearable(parent_id, WT_SKIN); + return linked_item->getCreatorUUID(); } - else if ("hair" == type) + + return LLInventoryItem::getCreatorUUID(); +} + +const std::string& LLViewerInventoryItem::getDescription() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); - LLFolderBridge::createWearable(parent_id, WT_HAIR); + return linked_item->getDescription(); } - else if ("eyes" == type) + + return LLInventoryItem::getDescription(); +} + +const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) { - LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); - LLFolderBridge::createWearable(parent_id, WT_EYES); + return linked_item->getSaleInfo(); } - - folder->setNeedsAutoRename(TRUE); + + return LLInventoryItem::getSaleInfo(); } -LLAssetType::EType LLViewerInventoryItem::getType() const +LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const { - if (mType == LLAssetType::AT_LINK) + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getInventoryType(); + } + + // Categories don't have types. If this item is an AT_FOLDER_LINK, + // treat it as a category. + if (getLinkedCategory()) { - LLInventoryItem *linked_item = gInventory.getItem(mAssetUUID); - if (linked_item) + return LLInventoryType::IT_CATEGORY; + } + + return LLInventoryItem::getInventoryType(); +} + +U32 LLViewerInventoryItem::getFlags() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getFlags(); + } + return LLInventoryItem::getFlags(); +} + +bool LLViewerInventoryItem::isWearableType() const +{ + return (getInventoryType() == LLInventoryType::IT_WEARABLE); +} + +LLWearableType::EType LLViewerInventoryItem::getWearableType() const +{ + if (!isWearableType()) + { + return LLWearableType::WT_INVALID; + } + return LLWearableType::EType(getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK); +} + + +time_t LLViewerInventoryItem::getCreationDate() const +{ + return LLInventoryItem::getCreationDate(); +} + +U32 LLViewerInventoryItem::getCRC32() const +{ + return LLInventoryItem::getCRC32(); +} + +// *TODO: mantipov: should be removed with LMSortPrefix patch in llinventorymodel.cpp, EXT-3985 +static char getSeparator() { return '@'; } +BOOL LLViewerInventoryItem::extractSortFieldAndDisplayName(const std::string& name, S32* sortField, std::string* displayName) +{ + using std::string; + using std::stringstream; + + const char separator = getSeparator(); + const string::size_type separatorPos = name.find(separator, 0); + + BOOL result = FALSE; + + if (separatorPos < string::npos) + { + if (sortField) { - return linked_item->getType(); + /* + * The conversion from string to S32 is made this way instead of old plain + * atoi() to ensure portability. If on some other platform S32 will not be + * defined to be signed int, this conversion will still work because of + * operators overloading, but atoi() may fail. + */ + stringstream ss(name.substr(0, separatorPos)); + ss >> *sortField; } + + if (displayName) + { + *displayName = name.substr(separatorPos + 1, string::npos); + } + + result = TRUE; } - return LLInventoryItem::getType(); + + return result; } -const LLUUID& LLViewerInventoryItem::getAssetUUID() const +// This returns true if the item that this item points to +// doesn't exist in memory (i.e. LLInventoryModel). The baseitem +// might still be in the database but just not loaded yet. +bool LLViewerInventoryItem::getIsBrokenLink() const +{ + // If the item's type resolves to be a link, that means either: + // A. It wasn't able to perform indirection, i.e. the baseobj doesn't exist in memory. + // B. It's pointing to another link, which is illegal. + return LLAssetType::lookupIsLinkType(getType()); +} + +LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const { if (mType == LLAssetType::AT_LINK) { - LLInventoryItem *linked_item = gInventory.getItem(mAssetUUID); - if (linked_item) + LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID); + if (linked_item && linked_item->getIsLinkType()) { - return linked_item->getAssetUUID(); + llwarns << "Warning: Accessing link to link" << llendl; + return NULL; } + return linked_item; } + return NULL; +} - return LLInventoryItem::getAssetUUID(); +LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const +{ + if (mType == LLAssetType::AT_LINK_FOLDER) + { + LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID); + return linked_category; + } + return NULL; } -const std::string& LLViewerInventoryItem::getName() const +bool LLViewerInventoryItem::checkPermissionsSet(PermissionMask mask) const { - if (mType == LLAssetType::AT_LINK) + const LLPermissions& perm = getPermissions(); + PermissionMask curr_mask = PERM_NONE; + if(perm.getOwner() == gAgent.getID()) + { + curr_mask = perm.getMaskBase(); + } + else if(gAgent.isInGroup(perm.getGroup())) + { + curr_mask = perm.getMaskGroup(); + } + else { - return LLInventoryItem::getName(); //+" link"; + curr_mask = perm.getMaskEveryone(); } + return ((curr_mask & mask) == mask); +} + +PermissionMask LLViewerInventoryItem::getPermissionMask() const +{ + const LLPermissions& permissions = getPermissions(); + + BOOL copy = permissions.allowCopyBy(gAgent.getID()); + BOOL mod = permissions.allowModifyBy(gAgent.getID()); + BOOL xfer = permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID()); + PermissionMask perm_mask = 0; + if (copy) perm_mask |= PERM_COPY; + if (mod) perm_mask |= PERM_MODIFY; + if (xfer) perm_mask |= PERM_TRANSFER; + return perm_mask; +} + +//---------- - return LLInventoryItem::getName(); +void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name) +{ + rename(first_name + " " + last_name); + gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID()); + gInventory.notifyObservers(); } +class LLRegenerateLinkCollector : public LLInventoryCollectFunctor +{ +public: + LLRegenerateLinkCollector(const LLViewerInventoryItem *target_item) : mTargetItem(target_item) {} + virtual ~LLRegenerateLinkCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + if (item) + { + if ((item->getName() == mTargetItem->getName()) && + (item->getInventoryType() == mTargetItem->getInventoryType()) && + (!item->getIsLinkType())) + { + return true; + } + } + return false; + } +protected: + const LLViewerInventoryItem* mTargetItem; +}; + +LLUUID find_possible_item_for_regeneration(const LLViewerInventoryItem *target_item) +{ + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + + LLRegenerateLinkCollector candidate_matches(target_item); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + candidate_matches); + for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) + { + const LLViewerInventoryItem *item = (*item_iter); + if (true) return item->getUUID(); + } + return LLUUID::null; +} + +// This currently dosen't work, because the sim does not allow us +// to change an item's assetID. +BOOL LLViewerInventoryItem::regenerateLink() +{ + const LLUUID target_item_id = find_possible_item_for_regeneration(this); + if (target_item_id.isNull()) + return FALSE; + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(getAssetUUID()); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + asset_id_matches); + for (LLViewerInventoryItem::item_array_t::iterator item_iter = items.begin(); + item_iter != items.end(); + item_iter++) + { + LLViewerInventoryItem *item = (*item_iter); + item->setAssetUUID(target_item_id); + item->updateServer(FALSE); + gInventory.addChangedMask(LLInventoryObserver::REBUILD, item->getUUID()); + } + gInventory.notifyObservers(); + return TRUE; +} |