diff options
Diffstat (limited to 'indra/newview/llinventorybridge.cpp')
-rw-r--r-- | indra/newview/llinventorybridge.cpp | 1649 |
1 files changed, 704 insertions, 945 deletions
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index b85bf0d518..569dfc08e2 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2,31 +2,25 @@ * @file llinventorybridge.cpp * @brief Implementation of the Inventory-Folder-View-Bridge classes. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -34,19 +28,20 @@ #include "llinventorybridge.h" // external projects -#include "lltransfersourceasset.h" +#include "lltransfersourceasset.h" #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llappearancemgr.h" -#include "llavataractions.h" -#include "llfloatercustomize.h" +#include "llattachmentsmgr.h" +#include "llavataractions.h" #include "llfloateropenobject.h" #include "llfloaterreg.h" #include "llfloaterworldmap.h" #include "llfriendcard.h" #include "llgesturemgr.h" +#include "llgiveinventory.h" #include "llimfloater.h" #include "llimview.h" #include "llinventoryclipboard.h" @@ -61,15 +56,17 @@ #include "llpreviewgesture.h" #include "llpreviewtexture.h" #include "llselectmgr.h" +#include "llsidepanelappearance.h" #include "llsidetray.h" #include "lltrans.h" #include "llviewerassettype.h" +#include "llviewerfoldertype.h" +#include "llviewermenu.h" #include "llviewermessage.h" #include "llviewerobjectlist.h" #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llwearablelist.h" -#include "llpaneloutfitsinventory.h" typedef std::pair<LLUUID, LLUUID> two_uuids_t; typedef std::list<two_uuids_t> two_uuids_list_t; @@ -101,52 +98,12 @@ void dec_busy_count() } // Function declarations -void wear_add_inventory_item_on_avatar(LLInventoryItem* item); void remove_inventory_category_from_avatar(LLInventoryCategory* category); void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id); bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); -bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response); +bool confirm_attachment_rez(const LLSD& notification, const LLSD& response); void teleport_via_landmark(const LLUUID& asset_id); -std::string ICON_NAME[ICON_NAME_COUNT] = -{ - "Inv_Texture", - "Inv_Sound", - "Inv_CallingCard", - "Inv_CallingCard", - "Inv_Landmark", - "Inv_Landmark", - "Inv_Script", - "Inv_Clothing", - "Inv_Object", - "Inv_Object_Multi", - "Inv_Notecard", - "Inv_Skin", - "Inv_Snapshot", - - "Inv_BodyShape", - "Inv_Skin", - "Inv_Hair", - "Inv_Eye", - "Inv_Shirt", - "Inv_Pants", - "Inv_Shoe", - "Inv_Socks", - "Inv_Jacket", - "Inv_Gloves", - "Inv_Undershirt", - "Inv_Underpants", - "Inv_Skirt", - "Inv_Alpha", - "Inv_Tattoo", - - "Inv_Animation", - "Inv_Gesture", - - "Inv_LinkItem", - "Inv_LinkFolder" -}; - // +=================================================+ // | LLInvFVBridge | // +=================================================+ @@ -156,14 +113,17 @@ LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : mUUID(uuid), mRoot(root), - mInvType(LLInventoryType::IT_NONE) + mInvType(LLInventoryType::IT_NONE), + mIsLink(FALSE) { mInventoryPanel = inventory->getHandle(); + const LLInventoryObject* obj = getInventoryObject(); + mIsLink = obj && obj->getIsLinkType(); } const std::string& LLInvFVBridge::getName() const { - LLInventoryObject* obj = getInventoryObject(); + const LLInventoryObject* obj = getInventoryObject(); if(obj) { return obj->getName(); @@ -179,7 +139,6 @@ const std::string& LLInvFVBridge::getDisplayName() const // Folders have full perms PermissionMask LLInvFVBridge::getPermissionMask() const { - return PERM_ALL; } @@ -199,34 +158,7 @@ time_t LLInvFVBridge::getCreationDate() const // Can be destroyed (or moved to trash) BOOL LLInvFVBridge::isItemRemovable() const { - const LLInventoryModel* model = getInventoryModel(); - if(!model) - { - return FALSE; - } - - // Can't delete an item that's in the library. - if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) - { - return FALSE; - } - - // Disable delete from COF folder; have users explicitly choose "detach/take off". - if (LLAppearanceMgr::instance().getIsProtectedCOFItem(mUUID)) - { - return FALSE; - } - - const LLInventoryObject *obj = model->getItem(mUUID); - if (obj && obj->getIsLinkType()) - { - return TRUE; - } - if (get_is_item_worn(mUUID)) - { - return FALSE; - } - return TRUE; + return get_is_item_removable(getInventoryModel(), mUUID); } // Can be moved to another folder @@ -235,6 +167,11 @@ BOOL LLInvFVBridge::isItemMovable() const return TRUE; } +BOOL LLInvFVBridge::isLink() const +{ + return mIsLink; +} + /*virtual*/ /** * @brief Adds this item into clipboard storage @@ -249,9 +186,7 @@ void LLInvFVBridge::cutToClipboard() // *TODO: make sure this does the right thing void LLInvFVBridge::showProperties() { - LLSD key; - key["id"] = mUUID; - LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); + show_item_profile(mUUID); // Disable old properties floater; this is replaced by the sidepanel. /* @@ -494,7 +429,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const } } const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i)); - if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { return FALSE; } @@ -504,7 +439,8 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const void hide_context_entries(LLMenuGL& menu, const menuentry_vec_t &entries_to_show, - const menuentry_vec_t &disabled_entries) + const menuentry_vec_t &disabled_entries, + BOOL append) // If append is TRUE, then new enabled entries { const LLView::child_list_t *list = menu.getChildList(); @@ -512,13 +448,15 @@ void hide_context_entries(LLMenuGL& menu, // if the first element is a separator, it will not be shown. BOOL is_previous_entry_separator = TRUE; - LLView::child_list_t::const_iterator itor; - for (itor = list->begin(); itor != list->end(); ++itor) + for (LLView::child_list_t::const_iterator itor = list->begin(); + itor != list->end(); + ++itor) { - std::string name = (*itor)->getName(); + LLView *menu_item = (*itor); + std::string name = menu_item->getName(); // descend into split menus: - LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(*itor); + LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item); if ((name == "More") && branchp) { hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries); @@ -539,7 +477,7 @@ void hide_context_entries(LLMenuGL& menu, // between two separators). if (found) { - const BOOL is_entry_separator = (dynamic_cast<LLMenuItemSeparatorGL *>(*itor) != NULL); + const BOOL is_entry_separator = (dynamic_cast<LLMenuItemSeparatorGL *>(menu_item) != NULL); if (is_entry_separator && is_previous_entry_separator) found = false; is_previous_entry_separator = is_entry_separator; @@ -547,16 +485,27 @@ void hide_context_entries(LLMenuGL& menu, if (!found) { - (*itor)->setVisible(FALSE); + if (!menu_item->getLastVisible()) + { + menu_item->setVisible(FALSE); + } + menu_item->setEnabled(FALSE); } else { - (*itor)->setVisible(TRUE); + menu_item->setVisible(TRUE); + // A bit of a hack so we can remember that some UI element explicitly set this to be visible + // so that some other UI element from multi-select doesn't later set this invisible. + menu_item->pushVisible(TRUE); + if (append) + { + menu_item->setEnabled(TRUE); + } for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2) { if (*itor2 == name) { - (*itor)->setEnabled(FALSE); + menu_item->setEnabled(FALSE); } } } @@ -570,17 +519,6 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, { const LLInventoryObject *obj = getInventoryObject(); - bool is_sidepanel = isInOutfitsSidePanel(); - if (is_sidepanel) - { - // Sidepanel includes restricted menu. - if (obj && obj->getIsLinkType() && !get_is_item_worn(mUUID)) - { - items.push_back(std::string("Remove Link")); - } - return; - } - if (obj) { if (obj->getIsLinkType()) @@ -641,7 +579,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Paste")); } - if (gAgent.isGodlike()) + if (gSavedSettings.getBOOL("InventoryLinking")) { items.push_back(std::string("Paste As Link")); if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) @@ -677,7 +615,8 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Share")); } - items.push_back(std::string("Open")); + + addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -712,7 +651,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items, const LLInventoryObject *obj = getInventoryObject(); // Don't allow delete as a direct option from COF folder. - if (obj && obj->getIsLinkType() && isCOFFolder()) + if (obj && obj->getIsLinkType() && isCOFFolder() && get_is_item_worn(mUUID)) { return; } @@ -733,6 +672,17 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items, } } +void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items) +{ + const LLInventoryObject *obj = getInventoryObject(); + const BOOL is_link = (obj && obj->getIsLinkType()); + + if (is_link) + items.push_back(std::string("Open Original")); + else + items.push_back(std::string("Open")); +} + // *TODO: remove this BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { @@ -840,21 +790,7 @@ void LLInvFVBridge::changeItemParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - if (item->getParentUUID() != new_parent_id) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(restamp); - model->updateItem(new_item); - model->notifyObservers(); - } + change_item_parent(model, item, new_parent_id, restamp); } // static @@ -863,24 +799,7 @@ void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - // Can't move a folder into a child of itself. - if (model->isObjectDescendentOf(new_parent_id, cat->getUUID())) - { - return; - } - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - model->accountForUpdate(update); - - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - model->updateCategory(new_cat); - model->notifyObservers(); + change_category_parent(model, cat, new_parent_id, restamp); } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, @@ -931,7 +850,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, { llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; } - new_listener = new LLScriptBridge(inventory, root, uuid); + new_listener = new LLItemBridge(inventory, root, uuid); break; case LLAssetType::AT_OBJECT: @@ -980,7 +899,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, { llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; } - new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (EWearableType)flags); + new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags); break; case LLAssetType::AT_CATEGORY: if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) @@ -1026,46 +945,25 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) } } -bool LLInvFVBridge::isInOutfitsSidePanel() const +BOOL LLInvFVBridge::canShare() const { - LLInventoryPanel *my_panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get()); - LLPanelOutfitsInventory *outfit_panel = - dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); - if (!outfit_panel) - return false; - return outfit_panel->isTabPanel(my_panel); -} + if (!isAgentInventory()) return FALSE; -bool LLInvFVBridge::canShare() -{ const LLInventoryModel* model = getInventoryModel(); - if(!model) - { - return false; - } + if (!model) return FALSE; - LLViewerInventoryItem *item = model->getItem(mUUID); + const LLViewerInventoryItem *item = model->getItem(mUUID); if (item) { - bool allowed = false; - allowed = LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item); - if (allowed && - !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) - { - allowed = false; - } - if (allowed && - !item->getPermissions().allowCopyBy(gAgent.getID())) - { - allowed = false; - } - return allowed; + if (!LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item)) + return FALSE; + return (BOOL)LLGiveInventory::isInventoryGiveAcceptable(item); } - LLViewerInventoryCategory* cat = model->getCategory(mUUID); + // Categories can be given. + if (model->getCategory(mUUID)) return TRUE; - // All categories can be given. - return cat != NULL; + return FALSE; } // +=================================================+ @@ -1099,7 +997,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) gotoItem(); } - if ("open" == action) + if ("open" == action || "open_original" == action) { openItem(); return; @@ -1243,25 +1141,22 @@ void LLItemBridge::gotoItem() LLUIImagePtr LLItemBridge::getIcon() const { - return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]); + LLInventoryObject *obj = getInventoryObject(); + if (obj) + { + return LLInventoryIcon::getIcon(obj->getType(), + LLInventoryType::IT_NONE, + mIsLink); + } + + return LLInventoryIcon::getIcon(LLInventoryIcon::ICONNAME_OBJECT); } PermissionMask LLItemBridge::getPermissionMask() const { LLViewerInventoryItem* item = getItem(); PermissionMask perm_mask = 0; - if(item) - { - BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); - BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); - BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, - gAgent.getID()); - - if (copy) perm_mask |= PERM_COPY; - if (mod) perm_mask |= PERM_MODIFY; - if (xfer) perm_mask |= PERM_TRANSFER; - - } + if (item) perm_mask = item->getPermissionMask(); return perm_mask; } @@ -1289,18 +1184,18 @@ void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name) LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const { U8 font = LLFontGL::NORMAL; + const LLViewerInventoryItem* item = getItem(); if (get_is_item_worn(mUUID)) { // llinfos << "BOLD" << llendl; font |= LLFontGL::BOLD; } - - const LLViewerInventoryItem* item = getItem(); - if (item && item->getIsLinkType()) + else if(item && item->getIsLinkType()) { font |= LLFontGL::ITALIC; } + return (LLFontGL::StyleFlags)font; } @@ -1370,6 +1265,12 @@ BOOL LLItemBridge::isItemRenameable() const { return FALSE; } + + if (!item->isFinished()) // EXT-8662 + { + return FALSE; + } + return (item->getPermissions().allowModifyBy(gAgent.getID())); } return FALSE; @@ -1406,13 +1307,65 @@ BOOL LLItemBridge::removeItem() { return FALSE; } + + // move it to the trash LLPreview::hide(mUUID, TRUE); LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); LLViewerInventoryItem* item = getItem(); + if (!item) return FALSE; + + // Already in trash + if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE; + + LLNotification::Params params("ConfirmItemDeleteHasLinks"); + params.functor.function(boost::bind(&LLItemBridge::confirmRemoveItem, this, _1, _2)); + + // Check if this item has any links. If generic inventory linking is enabled, + // we can't do this check because we may have items in a folder somewhere that is + // not yet in memory, so we don't want false negatives. (If disabled, then we + // know we only have links in the Outfits folder which we explicitly fetch.) + if (!gSavedSettings.getBOOL("InventoryLinking")) + { + if (!item->getIsLinkType()) + { + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLLinkedItemIDMatches is_linked_item_match(mUUID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + + const U32 num_links = cat_array.size() + item_array.size(); + if (num_links > 0) + { + // Warn if the user is will break any links when deleting this item. + LLNotifications::instance().add(params); + return FALSE; + } + } + } + + LLNotifications::instance().forceResponse(params, 0); + return TRUE; +} + +BOOL LLItemBridge::confirmRemoveItem(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return FALSE; + + LLInventoryModel* model = getInventoryModel(); + if (!model) return FALSE; + LLViewerInventoryItem* item = getItem(); + if (!item) return FALSE; + + const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); // if item is not already in trash if(item && !model->isObjectDescendentOf(mUUID, trash_id)) { @@ -1421,11 +1374,7 @@ BOOL LLItemBridge::removeItem() // delete was successful return TRUE; } - else - { - // tried to delete already item in trash (should purge?) - return FALSE; - } + return FALSE; } BOOL LLItemBridge::isItemCopyable() const @@ -1445,17 +1394,11 @@ BOOL LLItemBridge::isItemCopyable() const return FALSE; } - if (gAgent.isGodlike()) - { - // All items can be copied in god mode since you can - // at least paste-as-link the item, though you - // still may not be able paste the item. - return TRUE; - } - else - { - return (item->getPermissions().allowCopyBy(gAgent.getID())); - } + // All items can be copied in god mode since you can + // at least paste-as-link the item, though you + // still may not be able paste the item. + return TRUE; + // return (item->getPermissions().allowCopyBy(gAgent.getID())); } return FALSE; } @@ -1505,7 +1448,7 @@ bool LLItemBridge::isRemoveAction(std::string action) const // | LLFolderBridge | // +=================================================+ -LLFolderBridge* LLFolderBridge::sSelf=NULL; +LLHandle<LLFolderBridge> LLFolderBridge::sSelf; // Can be moved to another folder BOOL LLFolderBridge::isItemMovable() const @@ -1543,26 +1486,7 @@ public: // Can be destroyed (or moved to trash) BOOL LLFolderBridge::isItemRemovable() const { - LLInventoryModel* model = getInventoryModel(); - if(!model) - { - return FALSE; - } - - if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) - { - return FALSE; - } - - if (!isAgentAvatarValid()) return FALSE; - - LLInventoryCategory* category = model->getCategory(mUUID); - if(!category) - { - return FALSE; - } - - if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + if (!get_is_category_removable(getInventoryModel(), mUUID)) { return FALSE; } @@ -1578,6 +1502,7 @@ BOOL LLFolderBridge::isItemRemovable() const return FALSE; } } + return TRUE; } @@ -1596,6 +1521,11 @@ BOOL LLFolderBridge::isUpToDate() const BOOL LLFolderBridge::isItemCopyable() const { + if (gSavedSettings.getBOOL("InventoryLinking")) + { + // Can copy folders to paste-as-link, but not for straight paste. + return TRUE; + } return FALSE; } @@ -1698,85 +1628,71 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL drop) { - // This should never happen, but if an inventory item is incorrectly parented, - // the UI will get confused and pass in a NULL. - if(!inv_cat) return FALSE; LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; + if (!inv_cat) return FALSE; // shouldn't happen, but in case item is incorrectly parented in which case inv_cat will be NULL + if (!model) return FALSE; if (!isAgentAvatarValid()) return FALSE; + if (!isAgentInventory()) return FALSE; // cannot drag categories into library - // cannot drag categories into library - if(!isAgentInventory()) - { - return FALSE; - } // check to make sure source is agent inventory, and is represented there. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) + const BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) && (LLToolDragAndDrop::SOURCE_AGENT == source); BOOL accept = FALSE; - S32 i; - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - if(is_agent_inventory) + if (is_agent_inventory) { - const LLUUID& cat_id = inv_cat->getUUID(); + const LLUUID &cat_id = inv_cat->getUUID(); + const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + + const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); + const BOOL move_is_into_outfit = getCategory() && (getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT); + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - // Is the destination the trash? - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - BOOL move_is_into_trash = (mUUID == trash_id) - || model->isObjectDescendentOf(mUUID, trash_id); - BOOL is_movable = (!LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())); - const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - if (move_is_into_current_outfit || move_is_into_outfit) - { - // BAP - restrictions? - is_movable = true; - } + //-------------------------------------------------------------------------------- + // Determine if folder can be moved. + // + BOOL is_movable = TRUE; + if (LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) + is_movable = FALSE; + if (move_is_into_outfit) + is_movable = FALSE; if (mUUID == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)) + is_movable = FALSE; + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE); + for (S32 i=0; i < descendent_categories.count(); ++i) { - is_movable = FALSE; // It's generally movable but not into Favorites folder. EXT-1604 + LLInventoryCategory* category = descendent_categories[i]; + if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + { + // Can't move "special folders" (e.g. Textures Folder). + is_movable = FALSE; + break; + } } - - if( is_movable ) + if (move_is_into_trash) { - gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); - - for( i = 0; i < descendent_categories.count(); i++ ) + for (S32 i=0; i < descendent_items.count(); ++i) { - LLInventoryCategory* category = descendent_categories[i]; - if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + LLInventoryItem* item = descendent_items[i]; + if (get_is_item_worn(item->getUUID())) { - // ...can't move "special folders" like Textures is_movable = FALSE; - break; - } - } - - if( is_movable ) - { - if( move_is_into_trash ) - { - for( i = 0; i < descendent_items.count(); i++ ) - { - LLInventoryItem* item = descendent_items[i]; - if (get_is_item_worn(item->getUUID())) - { - is_movable = FALSE; - break; // It's generally movable, but not into the trash! - } - } + break; // It's generally movable, but not into the trash. } } } + // + //-------------------------------------------------------------------------------- + accept = is_movable && (mUUID != cat_id) // Can't move a folder into itself && (mUUID != inv_cat->getParentUUID()) // Avoid moves that would change nothing @@ -1786,7 +1702,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // Look for any gestures and deactivate them if (move_is_into_trash) { - for (i = 0; i < descendent_items.count(); i++) + for (S32 i=0; i < descendent_items.count(); i++) { LLInventoryItem* item = descendent_items[i]; if (item->getType() == LLAssetType::AT_GESTURE @@ -1827,11 +1743,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, else { LLPointer<LLInventoryCallback> cb = NULL; + const std::string empty_description = ""; link_inventory_item( gAgent.getID(), inv_cat->getUUID(), mUUID, inv_cat->getName(), + empty_description, LLAssetType::AT_LINK_FOLDER, cb); } @@ -2145,7 +2063,7 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask) mContentsCount) { gInventory.removeObserver(this); - LLAppearanceMgr::instance().wearInventoryCategory(category, FALSE, TRUE); + LLAppearanceMgr::instance().wearInventoryCategory(category, FALSE, FALSE); delete this; } } @@ -2273,13 +2191,7 @@ void LLFolderBridge::determineFolderType() BOOL LLFolderBridge::isItemRenameable() const { - LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory(); - if(cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) - && (cat->getOwnerID() == gAgent.getID())) - { - return TRUE; - } - return FALSE; + return get_is_category_renameable(getInventoryModel(), mUUID); } void LLFolderBridge::restoreItem() @@ -2319,42 +2231,22 @@ LLUIImagePtr LLFolderBridge::getIcon() const return getIcon(preferred_type); } +// static LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) { - // we only have one folder image now - if (preferred_type == LLFolderType::FT_OUTFIT) - { - return LLUI::getUIImage("Inv_LookFolderClosed"); - } - return LLUI::getUIImage("Inv_FolderClosed"); + return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE)); } LLUIImagePtr LLFolderBridge::getOpenIcon() const { - if (getPreferredType() == LLFolderType::FT_OUTFIT) - { - return LLUI::getUIImage("Inv_LookFolderOpen"); - } - return LLUI::getUIImage("Inv_FolderOpen"); + return LLUI::getUIImage(LLViewerFolderType::lookupIconName(getPreferredType(), TRUE)); + } BOOL LLFolderBridge::renameItem(const std::string& new_name) { - if(!isItemRenameable()) - return FALSE; - LLInventoryModel* model = getInventoryModel(); - if(!model) - return FALSE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat && (cat->getName() != new_name)) - { - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat); - new_cat->rename(new_name); - new_cat->updateServer(FALSE); - model->updateCategory(new_cat); + rename_category(getInventoryModel(), mUUID, new_name); - model->notifyObservers(); - } // return FALSE because we either notified observers (& therefore // rebuilt) or we didn't update. return FALSE; @@ -2408,36 +2300,7 @@ bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& re { // move it to the trash LLPreview::hide(mUUID); - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE ); - - for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); - iter != descendent_items.end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - const LLUUID& item_id = item->getUUID(); - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item_id)) - { - LLGestureMgr::instance().deactivateGesture(item_id); - } - } - - // go ahead and do the normal remove if no 'last calling - // cards' are being removed. - LLViewerInventoryCategory* cat = getCategory(); - if(cat) - { - LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE); - } + remove_category(getInventoryModel(), mUUID); return TRUE; } return FALSE; @@ -2500,37 +2363,40 @@ void LLFolderBridge::pasteLinkFromClipboard() ++iter) { const LLUUID &object_id = (*iter); -#if SUPPORT_ENSEMBLES if (LLInventoryCategory *cat = model->getCategory(object_id)) { + const std::string empty_description = ""; link_inventory_item( gAgent.getID(), cat->getUUID(), parent_id, cat->getName(), + empty_description, LLAssetType::AT_LINK_FOLDER, LLPointer<LLInventoryCallback>(NULL)); } - else -#endif - if (LLInventoryItem *item = model->getItem(object_id)) - { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - parent_id, - item->getName(), - LLAssetType::AT_LINK, - LLPointer<LLInventoryCallback>(NULL)); - } + else if (LLInventoryItem *item = model->getItem(object_id)) + { + link_inventory_item( + gAgent.getID(), + item->getLinkedUUID(), + parent_id, + item->getName(), + item->getDescription(), + LLAssetType::AT_LINK, + LLPointer<LLInventoryCallback>(NULL)); + } } } } void LLFolderBridge::staticFolderOptionsMenu() { - if (!sSelf) return; - sSelf->folderOptionsMenu(); + LLFolderBridge* selfp = sSelf.get(); + if (selfp) + { + selfp->folderOptionsMenu(); + } } void LLFolderBridge::folderOptionsMenu() @@ -2543,23 +2409,19 @@ void LLFolderBridge::folderOptionsMenu() const LLInventoryCategory* category = model->getCategory(mUUID); if(!category) return; + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id == mUUID) return; + if (isItemInTrash()) return; + if (!isAgentInventory()) return; + LLFolderType::EType type = category->getPreferredType(); const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); // BAP change once we're no longer treating regular categories as ensembles. const bool is_ensemble = (type == LLFolderType::FT_NONE || LLFolderType::lookupIsEnsembleType(type)); - // calling card related functionality for folders. - - const bool is_sidepanel = isInOutfitsSidePanel(); - if (is_sidepanel) - { - mItems.push_back("Rename"); - addDeleteContextMenuOptions(mItems, disabled_items); - } - // Only enable calling-card related options for non-system folders. - if (!is_sidepanel && !is_system_folder) + if (!is_system_folder) { LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard)) @@ -2588,10 +2450,7 @@ void LLFolderBridge::folderOptionsMenu() checkFolderForContentsOfType(model, is_object) || checkFolderForContentsOfType(model, is_gesture) ) { - if (!is_sidepanel) - { - mItems.push_back(std::string("Folder Wearables Separator")); - } + mItems.push_back(std::string("Folder Wearables Separator")); // Only enable add/replace outfit for non-system folders. if (!is_system_folder) @@ -2608,17 +2467,25 @@ void LLFolderBridge::folderOptionsMenu() mItems.push_back(std::string("Wear As Ensemble")); } mItems.push_back(std::string("Remove From Outfit")); - if (!areAnyContentsWorn(model)) + if (!LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) { disabled_items.push_back(std::string("Remove From Outfit")); } + if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) + { + disabled_items.push_back(std::string("Replace Outfit")); + } mItems.push_back(std::string("Outfit Separator")); } - hide_context_entries(*mMenu, mItems, disabled_items); + LLMenuGL* menup = dynamic_cast<LLMenuGL*>(mMenu.get()); + if (menup) + { + hide_context_entries(*menup, mItems, disabled_items, TRUE); - // Reposition the menu, in case we're adding items to an existing menu. - mMenu->needsArrange(); - mMenu->arrangeAndClear(); + // Reposition the menu, in case we're adding items to an existing menu. + menup->needsArrange(); + menup->arrangeAndClear(); + } } BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) @@ -2633,35 +2500,6 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv return ((item_array.count() > 0) ? TRUE : FALSE ); } -class LLFindWorn : public LLInventoryCollectFunctor -{ -public: - LLFindWorn() {} - virtual ~LLFindWorn() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - if (item && get_is_item_worn(item->getUUID())) - { - return TRUE; - } - return FALSE; - } -}; - -BOOL LLFolderBridge::areAnyContentsWorn(LLInventoryModel* model) const -{ - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLFindWorn is_worn; - model->collectDescendentsIf(mUUID, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_worn); - return (item_array.size() > 0); -} - // Flags unused void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { @@ -2689,6 +2527,10 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mDisabledItems.push_back(std::string("New Body Parts")); } + // clear out old menu and folder pointers + mMenu.markDead(); + sSelf.markDead(); + if(trash_id == mUUID) { // This is the trash. @@ -2716,9 +2558,9 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mItems.push_back(std::string("New Clothes")); mItems.push_back(std::string("New Body Parts")); - // Changing folder types is just a debug feature; this is fairly unsupported +#if SUPPORT_ENSEMBLES + // Changing folder types is an unfinished unsupported feature // and can lead to unexpected behavior if enabled. -#if !LL_RELEASE_FOR_DOWNLOAD mItems.push_back(std::string("Change Type")); const LLViewerInventoryCategory *cat = getCategory(); if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) @@ -2764,36 +2606,6 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { mWearables=TRUE; } - - mMenu = &menu; - sSelf = this; - - - uuid_vec_t folders; - LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); - if (category) - { - folders.push_back(category->getUUID()); - } - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); - fetch->startFetch(); - inc_busy_count(); - if(fetch->isFinished()) - { - // everything is already here - call done. - fetch->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(fetch); - } - } - else - { - mItems.push_back(std::string("--no options--")); - mDisabledItems.push_back(std::string("--no options--")); } // Preemptively disable system folder removal if more than one item selected. @@ -2809,6 +2621,30 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } hide_context_entries(menu, mItems, mDisabledItems); + + // Add menu items that are dependent on the contents of the folder. + uuid_vec_t folders; + LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); + if (category) + { + folders.push_back(category->getUUID()); + } + + mMenu = menu.getHandle(); + sSelf = getHandle(); + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); + fetch->startFetch(); + inc_busy_count(); + if(fetch->isFinished()) + { + // everything is already here - call done. + fetch->done(); + } + else + { + // it's all on its way - add an observer, and the inventory will call done for us when everything is here. + gInventory.addObserver(fetch); + } } BOOL LLFolderBridge::hasChildren() const @@ -2899,90 +2735,75 @@ void LLFolderBridge::createNewCategory(void* user_data) void LLFolderBridge::createNewShirt(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHIRT); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHIRT); } void LLFolderBridge::createNewPants(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PANTS); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_PANTS); } void LLFolderBridge::createNewShoes(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHOES); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHOES); } void LLFolderBridge::createNewSocks(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SOCKS); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SOCKS); } void LLFolderBridge::createNewJacket(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_JACKET); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_JACKET); } void LLFolderBridge::createNewSkirt(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIRT); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIRT); } void LLFolderBridge::createNewGloves(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_GLOVES); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_GLOVES); } void LLFolderBridge::createNewUndershirt(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERSHIRT); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERSHIRT); } void LLFolderBridge::createNewUnderpants(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERPANTS); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERPANTS); } void LLFolderBridge::createNewShape(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHAPE); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHAPE); } void LLFolderBridge::createNewSkin(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIN); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIN); } void LLFolderBridge::createNewHair(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_HAIR); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_HAIR); } void LLFolderBridge::createNewEyes(void* user_data) { - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES); + LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_EYES); } // static -void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type) +void LLFolderBridge::createWearable(LLFolderBridge* bridge, LLWearableType::EType type) { if(!bridge) return; LLUUID parent_id = bridge->getUUID(); - createWearable(parent_id, type); -} - -// Separate function so can be called by global menu as well as right-click -// menu. -// static -void LLFolderBridge::createWearable(const LLUUID &parent_id, EWearableType type) -{ - LLWearable* wearable = LLWearableList::instance().createNewWearable(type); - LLAssetType::EType asset_type = wearable->getAssetType(); - LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - parent_id, wearable->getTransactionID(), wearable->getName(), - wearable->getDescription(), asset_type, inv_type, wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), - LLPointer<LLInventoryCallback>(NULL)); + LLAgentWearables::createWearable(type, false, parent_id); } void LLFolderBridge::modifyOutfit(BOOL append) @@ -3035,27 +2856,102 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response return false; } -BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, - BOOL drop) +// Returns true if the item can be moved to Current Outfit or any outfit folder. +static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit) { - LLInventoryModel* model = getInventoryModel(); - if(!model || !inv_item) return FALSE; + if ((inv_item->getInventoryType() != LLInventoryType::IT_WEARABLE) && + (inv_item->getInventoryType() != LLInventoryType::IT_GESTURE) && + (inv_item->getInventoryType() != LLInventoryType::IT_OBJECT)) + { + return FALSE; + } - // cannot drag into library - if(!isAgentInventory()) + if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID())) { return FALSE; } + return TRUE; +} + +void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item) +{ + // use callback to rearrange favorite landmarks after adding + // to have new one placed before target (on which it was dropped). See EXT-4312. + LLPointer<AddFavoriteLandmarkCallback> cb = new AddFavoriteLandmarkCallback(); + LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get()); + LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; + if (drag_over_item && drag_over_item->getListener()) + { + cb.get()->setTargetLandmarkId(drag_over_item->getListener()->getUUID()); + } + + copy_inventory_item( + gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + mUUID, + std::string(), + cb); +} + +void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit) +{ + // BAP - should skip if dup. + if (move_is_into_current_outfit) + { + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item->getUUID(), true, true); + } + else + { + LLPointer<LLInventoryCallback> cb = NULL; + link_inventory_item( + gAgent.getID(), + inv_item->getLinkedUUID(), + mUUID, + inv_item->getName(), + inv_item->getDescription(), + LLAssetType::AT_LINK, + cb); + } +} + +// This is used both for testing whether an item can be dropped +// into the folder, as well as performing the actual drop, depending +// if drop == TRUE. +BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, + BOOL drop) +{ + LLInventoryModel* model = getInventoryModel(); + + if(!model || !inv_item) return FALSE; + if(!isAgentInventory()) return FALSE; // cannot drag into library if (!isAgentAvatarValid()) return FALSE; + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); + + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); BOOL accept = FALSE; LLViewerObject* object = NULL; if(LLToolDragAndDrop::SOURCE_AGENT == source) { + const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); + + const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); + const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID()); + const BOOL folder_allows_reorder = (mUUID == favorites_id); + + //-------------------------------------------------------------------------------- + // Determine if item can be moved. + // + BOOL is_movable = TRUE; - switch( inv_item->getActualType() ) + + switch (inv_item->getActualType()) { case LLAssetType::AT_CATEGORY: is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType()); @@ -3063,41 +2959,43 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, default: break; } - - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const BOOL move_is_outof_current_outfit = LLAppearanceMgr::instance().getIsInCOF(inv_item->getUUID()); - // Can't explicitly drag things out of the COF. if (move_is_outof_current_outfit) { is_movable = FALSE; } - - if(is_movable && move_is_into_trash) + if (move_is_into_trash) { - is_movable = inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); + is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); } - - if ( is_movable ) + if (is_movable) { // Don't allow creating duplicates in the Calling Card/Friends // subfolders, see bug EXT-1599. Check is item direct descendent // of target folder and forbid item's movement if it so. // Note: isItemDirectDescendentOfCategory checks if // passed category is in the Calling Card/Friends folder - is_movable = ! LLFriendCardsManager::instance() - .isObjDirectDescendentOfCategory (inv_item, getCategory()); + is_movable &= !LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(inv_item, getCategory()); + } + + // + //-------------------------------------------------------------------------------- + + //-------------------------------------------------------------------------------- + // Determine if item can be moved & dropped + // + + accept = TRUE; + + if (!is_movable) + accept = FALSE; + if ((mUUID == inv_item->getParentUUID()) && !folder_allows_reorder) + accept = FALSE; + if (move_is_into_current_outfit || move_is_into_outfit) + { + accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); } - const LLUUID& favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const BOOL folder_allows_reorder = (mUUID == favorites_id); - - // we can move item inside a folder only if this folder is Favorites. See EXT-719 - accept = is_movable && ((mUUID != inv_item->getParentUUID()) || folder_allows_reorder); if(accept && drop) { if (inv_item->getType() == LLAssetType::AT_GESTURE @@ -3105,10 +3003,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { LLGestureMgr::instance().deactivateGesture(inv_item->getUUID()); } - // If an item is being dragged between windows, unselect - // everything in the active window so that we don't follow - // the selection to its new location (which is very - // annoying). + // If an item is being dragged between windows, unselect everything in the active window + // so that we don't follow the selection to its new location (which is very annoying). LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); if (active_panel) { @@ -3119,7 +3015,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } } - // if dragging from/into favorites folder only reorder items + //-------------------------------------------------------------------------------- + // Destination folder logic + // + + // REORDER + // (only reorder the item) if ((mUUID == inv_item->getParentUUID()) && folder_allows_reorder) { LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get()); @@ -3131,57 +3032,36 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, gInventory.rearrangeFavoriteLandmarks(srcItemId, destItemId); } } - else if (favorites_id == mUUID) // if target is the favorites folder we use copy - { - // use callback to rearrange favorite landmarks after adding - // to have new one placed before target (on which it was dropped). See EXT-4312. - LLPointer<AddFavoriteLandmarkCallback> cb = new AddFavoriteLandmarkCallback(); - LLInventoryPanel* panel = dynamic_cast<LLInventoryPanel*>(mInventoryPanel.get()); - LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; - if (drag_over_item && drag_over_item->getListener()) - { - cb.get()->setTargetLandmarkId(drag_over_item->getListener()->getUUID()); - } - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - mUUID, - std::string(), - cb); + // FAVORITES folder + // (copy the item) + else if (favorites_id == mUUID) + { + dropToFavorites(inv_item); } + // CURRENT OUTFIT or OUTFIT folder + // (link the item) else if (move_is_into_current_outfit || move_is_into_outfit) { - // BAP - should skip if dup. - if (move_is_into_current_outfit) - { - LLAppearanceMgr::instance().addCOFItemLink(inv_item); - } - else - { - LLPointer<LLInventoryCallback> cb = NULL; - link_inventory_item( - gAgent.getID(), - inv_item->getLinkedUUID(), - mUUID, - inv_item->getName(), - LLAssetType::AT_LINK, - cb); - } + dropToOutfit(inv_item, move_is_into_current_outfit); } + // NORMAL or TRASH folder + // (move the item, restamp if into trash) else { - // restamp if the move is into the trash. LLInvFVBridge::changeItemParent( model, (LLViewerInventoryItem*)inv_item, mUUID, move_is_into_trash); } + + // + //-------------------------------------------------------------------------------- + } } - else if(LLToolDragAndDrop::SOURCE_WORLD == source) + else if (LLToolDragAndDrop::SOURCE_WORLD == source) { // Make sure the object exists. If we allowed dragging from // anonymous objects, it would be possible to bypass @@ -3199,7 +3079,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, BOOL is_move = FALSE; if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) && perm.allowTransferTo(gAgent.getID()))) -// || gAgent.isGodlike()) + // || gAgent.isGodlike()) { accept = TRUE; @@ -3212,6 +3092,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, is_move = TRUE; accept = TRUE; } + + // Don't allow placing an original item into Current Outfit or an outfit folder + // because they must contain only links to wearable items. + // *TODO: Probably we should create a link to an item if it was dragged to outfit or COF. + if(move_is_into_current_outfit || move_is_into_outfit) + { + accept = FALSE; + } + if(drop && accept) { LLMoveInv* move_inv = new LLMoveInv; @@ -3251,15 +3140,36 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, if(item && item->isFinished()) { accept = TRUE; - if(drop) + + if (move_is_into_current_outfit || move_is_into_outfit) { - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - mUUID, - std::string(), - LLPointer<LLInventoryCallback>(NULL)); + accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); + } + + if (accept && drop) + { + // FAVORITES folder + // (copy the item) + if (favorites_id == mUUID) + { + dropToFavorites(inv_item); + } + // CURRENT OUTFIT or OUTFIT folder + // (link the item) + else if (move_is_into_current_outfit || move_is_into_outfit) + { + dropToOutfit(inv_item, move_is_into_current_outfit); + } + else + { + copy_inventory_item( + gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + mUUID, + std::string(), + LLPointer<LLInventoryCallback>(NULL)); + } } } } @@ -3271,21 +3181,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } // +=================================================+ -// | LLScriptBridge (DEPRECTED) | -// +=================================================+ - -LLUIImagePtr LLScriptBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); -} - -// +=================================================+ // | LLTextureBridge | // +=================================================+ LLUIImagePtr LLTextureBridge::getIcon() const { - return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0, FALSE); + return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInvType); } void LLTextureBridge::openItem() @@ -3331,7 +3232,7 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) disabled_items.push_back(std::string("Share")); } - items.push_back(std::string("Open")); + addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -3365,32 +3266,14 @@ void LLTextureBridge::performAction(LLInventoryModel* model, std::string action) // | LLSoundBridge | // +=================================================+ -LLUIImagePtr LLSoundBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); -} - void LLSoundBridge::openItem() { - LLViewerInventoryItem* item = getItem(); - + const LLViewerInventoryItem* item = getItem(); if (item) { LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } -/* -// Changed this back to the way it USED to work: -// only open the preview dialog through the contextual right-click menu -// double-click just plays the sound - -LLViewerInventoryItem* item = getItem(); -if(item) -{ -openSoundPreview((void*)this); -//send_uuid_sound_trigger(item->getAssetUUID(), 1.0); } -*/ - } void LLSoundBridge::previewItem() { @@ -3455,7 +3338,7 @@ LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory, LLUIImagePtr LLLandmarkBridge::getIcon() const { - return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE); + return LLInventoryIcon::getIcon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE); } void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) @@ -3647,7 +3530,7 @@ LLUIImagePtr LLCallingCardBridge::getIcon() const { online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()); } - return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, FALSE); + return LLInventoryIcon::getIcon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, FALSE); } std::string LLCallingCardBridge::getLabelSuffix() const @@ -3697,7 +3580,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Share")); } - items.push_back(std::string("Open")); + addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -3759,7 +3642,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, rv = TRUE; if(drop) { - LLToolDragAndDrop::giveInventory(item->getCreatorUUID(), + LLGiveInventory::doGiveInventoryItem(item->getCreatorUUID(), (LLInventoryItem*)cargo_data); } } @@ -3780,7 +3663,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, rv = TRUE; if(drop) { - LLToolDragAndDrop::giveInventoryCategory( + LLGiveInventory::doGiveInventoryCategory( item->getCreatorUUID(), inv_cat); } @@ -3805,39 +3688,19 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, // | LLNotecardBridge | // +=================================================+ -LLUIImagePtr LLNotecardBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); -} - void LLNotecardBridge::openItem() { LLViewerInventoryItem* item = getItem(); - if (item) { LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } - -/* - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); - } -*/ } - // +=================================================+ // | LLGestureBridge | // +=================================================+ -LLUIImagePtr LLGestureBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); -} - LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const { if( LLGestureMgr::instance().isGestureActive(mUUID) ) @@ -3972,13 +3835,9 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Share")); } - bool is_sidepanel = isInOutfitsSidePanel(); - if (!is_sidepanel) - { - items.push_back(std::string("Open")); - items.push_back(std::string("Properties")); - } + addOpenRightClickMenuOption(items); + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -4013,11 +3872,6 @@ void LLGestureBridge::playGesture(const LLUUID& item_id) // | LLAnimationBridge | // +=================================================+ -LLUIImagePtr LLAnimationBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); -} - void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { menuentry_vec_t items; @@ -4102,17 +3956,16 @@ LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : - LLItemBridge(inventory, root, uuid), - mInvType(type) + LLItemBridge(inventory, root, uuid) { mAttachPt = (flags & 0xff); // low bye of inventory flags - mIsMultiObject = ( flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; + mInvType = type; } LLUIImagePtr LLObjectBridge::getIcon() const { - return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject ); + return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject); } LLInventoryObject* LLObjectBridge::getObject() const @@ -4136,7 +3989,7 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) item = (LLViewerInventoryItem*)gInventory.getItem(object_id); if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID())) { - rez_attachment(item, NULL); + rez_attachment(item, NULL, true); // Replace if "Wear"ing. } else if(item && item->isFinished()) { @@ -4152,23 +4005,16 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) } gFocusMgr.setKeyboardFocus(NULL); } + else if ("wear_add" == action) + { + LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding. + } else if (isRemoveAction(action)) { LLInventoryItem* item = gInventory.getItem(mUUID); if(item) { - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); - gMessageSystem->sendReliable( gAgent.getRegion()->getHost()); - - // this object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = gObjectList.findObject(item->getLinkedUUID()); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - } + LLVOAvatarSelf::detachAttachmentIntoInventory(item->getLinkedUUID()); } } else LLItemBridge::performAction(model, action); @@ -4176,62 +4022,46 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) void LLObjectBridge::openItem() { - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } - - LLSD key; - key["id"] = mUUID; - LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); - - // Disable old properties floater; this is replaced by the sidepanel. - /* - LLFloaterReg::showInstance("properties", mUUID); - */ -} - -LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const -{ - U8 font = LLFontGL::NORMAL; - - if(get_is_item_worn( mUUID ) ) - { - font |= LLFontGL::BOLD; - } - - LLInventoryItem* item = getItem(); - if (item && item->getIsLinkType()) - { - font |= LLFontGL::ITALIC; - } - - return (LLFontGL::StyleFlags)font; + // object double-click action is to wear/unwear object + performAction(getInventoryModel(), + get_is_item_worn(mUUID) ? "detach" : "attach"); } std::string LLObjectBridge::getLabelSuffix() const { if (get_is_item_worn(mUUID)) { + if (!isAgentAvatarValid()) // Error condition, can't figure out attach point + { + return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); + } std::string attachment_point_name = gAgentAvatarp->getAttachedPointName(mUUID); - + if (attachment_point_name == LLStringUtil::null) // Error condition, invalid attach point + { + attachment_point_name = "Invalid Attachment"; + } // e.g. "(worn on ...)" / "(attached to ...)" LLStringUtil::format_map_t args; args["[ATTACHMENT_POINT]"] = LLTrans::getString(attachment_point_name); + return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args); } - else - { - return LLItemBridge::getLabelSuffix(); - } + return LLItemBridge::getLabelSuffix(); } -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment) +void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) { - LLSD payload; - payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link. + const LLUUID& item_id = item->getLinkedUUID(); + + // Check for duplicate request. + if (isAgentAvatarValid() && + (gAgentAvatarp->attachmentWasRequested(item_id) || + gAgentAvatarp->isWearingAttachment(item_id))) + { + llwarns << "duplicate attachment request, ignoring" << llendl; + return; + } + gAgentAvatarp->addAttachmentRequest(item_id); S32 attach_pt = 0; if (isAgentAvatarValid() && attachment) @@ -4247,21 +4077,23 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach } } + LLSD payload; + payload["item_id"] = item_id; // Wear the base object in case this is a link. payload["attachment_point"] = attach_pt; + payload["is_add"] = !replace; -#if !ENABLE_MULTIATTACHMENTS - if (attachment && attachment->getNumObjects() > 0) + if (replace && + (attachment && attachment->getNumObjects() > 0)) { - LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); + LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez); } else -#endif { LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); } } -bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response) +bool confirm_attachment_rez(const LLSD& notification, const LLSD& response) { if (!gAgentAvatarp->canAttachMoreObjects()) { @@ -4274,32 +4106,46 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option == 0/*YES*/) { - LLViewerInventoryItem* itemp = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + LLUUID item_id = notification["payload"]["item_id"].asUUID(); + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); if (itemp) { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); - msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); + /* + { + U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); + msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); + msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); + pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); + msg->addStringFast(_PREHASH_Name, itemp->getName()); + msg->addStringFast(_PREHASH_Description, itemp->getDescription()); + msg->sendReliable(gAgent.getRegion()->getHost()); + return false; + } + */ + + // Queue up attachments to be sent in next idle tick, this way the + // attachments are batched up all into one message versus each attachment + // being sent in its own separate attachments message. U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); -#if ENABLE_MULTIATTACHMENTS - attachment_pt |= ATTACHMENT_ADD; -#endif - msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); - pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); - msg->addStringFast(_PREHASH_Name, itemp->getName()); - msg->addStringFast(_PREHASH_Description, itemp->getDescription()); - msg->sendReliable(gAgent.getRegion()->getHost()); + BOOL is_add = notification["payload"]["is_add"].asBoolean(); + + LLAttachmentsMgr::instance().addAttachment(item_id, + attachment_pt, + is_add); } } return false; } -static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_replace_attachment_rez); +static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_attachment_rez); void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { @@ -4316,12 +4162,8 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { disabled_items.push_back(std::string("Share")); } - bool is_sidepanel = isInOutfitsSidePanel(); - if (!is_sidepanel) - { - items.push_back(std::string("Properties")); - } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -4334,13 +4176,14 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if( get_is_item_worn( mUUID ) ) { - items.push_back(std::string("Attach Separator")); + items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Detach From Yourself")); } else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder()) { - items.push_back(std::string("Attach Separator")); - items.push_back(std::string("Object Wear")); + items.push_back(std::string("Wearable And Object Separator")); + items.push_back(std::string("Wearable And Object Wear")); + items.push_back(std::string("Wearable Add")); items.push_back(std::string("Attach To")); items.push_back(std::string("Attach To HUD")); // commented out for DEV-32347 @@ -4348,7 +4191,8 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if (!gAgentAvatarp->canAttachMoreObjects()) { - disabled_items.push_back(std::string("Object Wear")); + disabled_items.push_back(std::string("Wearable And Object Wear")); + disabled_items.push_back(std::string("Wearable Add")); disabled_items.push_back(std::string("Attach To")); disabled_items.push_back(std::string("Attach To HUD")); } @@ -4377,7 +4221,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } LLSD cbparams; cbparams["index"] = curiter->first; - cbparams["label"] = attachment->getName(); + cbparams["label"] = p.name; p.on_click.function_name = "Inventory.AttachObject"; p.on_click.parameter = LLSD(attachment->getName()); p.on_enable.function_name = "Attachment.Label"; @@ -4432,11 +4276,6 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name) // | LLLSLTextBridge | // +=================================================+ -LLUIImagePtr LLLSLTextBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); -} - void LLLSLTextBridge::openItem() { LLViewerInventoryItem* item = getItem(); @@ -4456,39 +4295,12 @@ LLWearableBridge::LLWearableBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLAssetType::EType asset_type, LLInventoryType::EType inv_type, - EWearableType wearable_type) : + LLWearableType::EType wearable_type) : LLItemBridge(inventory, root, uuid), mAssetType( asset_type ), - mInvType(inv_type), mWearableType(wearable_type) { -} - -// *NOTE: hack to get from avatar inventory to avatar -void wear_inventory_item_on_avatar( LLInventoryItem* item ) -{ - if(item) - { - lldebugs << "wear_inventory_item_on_avatar( " << item->getName() - << " )" << llendl; - - LLAppearanceMgr::instance().addCOFItemLink(item); - } -} - -void wear_add_inventory_item_on_avatar( LLInventoryItem* item ) -{ - if(item) - { - lldebugs << "wear_add_inventory_item_on_avatar( " << item->getName() - << " )" << llendl; - - LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - LLWearableBridge::onWearAddOnAvatarArrived, - new LLUUID(item->getUUID())); - } + mInvType = inv_type; } void remove_inventory_category_from_avatar( LLInventoryCategory* category ) @@ -4498,15 +4310,13 @@ void remove_inventory_category_from_avatar( LLInventoryCategory* category ) << " )" << llendl; - if( gFloaterCustomize ) + if (gAgentCamera.cameraCustomizeAvatar()) { - gFloaterCustomize->askToSaveIfDirty( - boost::bind(remove_inventory_category_from_avatar_step2, _1, category->getUUID())); - } - else - { - remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() ); + // switching to outfit editor should automagically save any currently edited wearable + LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit")); } + + remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() ); } struct OnRemoveStruct @@ -4565,7 +4375,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_ if (item->getType() == LLAssetType::AT_BODYPART) continue; if (gAgent.isTeen() && item->isWearableType() && - (item->getWearableType() == WT_UNDERPANTS || item->getWearableType() == WT_UNDERSHIRT)) + (item->getWearableType() == LLWearableType::WT_UNDERPANTS || item->getWearableType() == LLWearableType::WT_UNDERSHIRT)) continue; if (get_is_item_worn(item->getUUID())) { @@ -4585,19 +4395,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_ LLViewerInventoryItem *obj_item = obj_item_array.get(i); if (get_is_item_worn(obj_item->getUUID())) { - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData ); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, obj_item->getLinkedUUID() ); - - gMessageSystem->sendReliable( gAgent.getRegion()->getHost() ); - - // this object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = gObjectList.findObject( obj_item->getLinkedUUID()); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - } + LLVOAvatarSelf::detachAttachmentIntoInventory(obj_item->getLinkedUUID()); } } } @@ -4643,7 +4441,7 @@ std::string LLWearableBridge::getLabelSuffix() const LLUIImagePtr LLWearableBridge::getIcon() const { - return get_item_icon(mAssetType, mInvType, mWearableType, FALSE); + return LLInventoryIcon::getIcon(mAssetType, mInvType, mWearableType, FALSE); } // virtual @@ -4704,30 +4502,27 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { can_open = FALSE; } - items.push_back(std::string("Share")); if (!canShare()) { disabled_items.push_back(std::string("Share")); } - bool is_sidepanel = isInOutfitsSidePanel(); - if (can_open && !is_sidepanel) + if (can_open) { - items.push_back(std::string("Open")); + addOpenRightClickMenuOption(items); } - - if (!is_sidepanel) + else { - items.push_back(std::string("Properties")); + disabled_items.push_back(std::string("Open")); + disabled_items.push_back(std::string("Open Original")); } + items.push_back(std::string("Properties")); + getClipboardEntries(true, items, disabled_items, flags); - if (!is_sidepanel) - { - items.push_back(std::string("Wearable Separator")); - } + items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Wearable Edit")); @@ -4738,7 +4533,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // Don't allow items to be worn if their baseobj is in the trash. if (isLinkedObjectInTrash() || isLinkedObjectMissing() || isCOFFolder()) { - disabled_items.push_back(std::string("Wearable Wear")); + disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Add")); disabled_items.push_back(std::string("Wearable Edit")); } @@ -4754,14 +4549,15 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) case LLAssetType::AT_BODYPART: if (get_is_item_worn(item->getUUID())) { - disabled_items.push_back(std::string("Wearable Wear")); + disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Add")); } else { - items.push_back(std::string("Wearable Wear")); + items.push_back(std::string("Wearable And Object Wear")); items.push_back(std::string("Wearable Add")); disabled_items.push_back(std::string("Take Off")); + disabled_items.push_back(std::string("Wearable Edit")); } break; default: @@ -4797,63 +4593,23 @@ void LLWearableBridge::onWearOnAvatar(void* user_data) void LLWearableBridge::wearOnAvatar() { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 LLViewerInventoryItem* item = getItem(); if(item) { - if(!isAgentInventory()) - { - LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_inventory_item_on_avatar(item); - } + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true); } } void LLWearableBridge::wearAddOnAvatar() { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 LLViewerInventoryItem* item = getItem(); if(item) { - if(!isAgentInventory()) - { - LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_add_inventory_item_on_avatar(item); - } + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, false); } } @@ -4930,20 +4686,7 @@ void LLWearableBridge::onEditOnAvatar(void* user_data) void LLWearableBridge::editOnAvatar() { - LLUUID linked_id = gInventory.getLinkedItemID(mUUID); - const LLWearable* wearable = gAgentWearables.getWearableFromItemID(linked_id); - if( wearable ) - { - // Set the tab to the right wearable. - if (gFloaterCustomize) - gFloaterCustomize->setCurrentWearableType( wearable->getType() ); - - if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() ) - { - // Start Avatar Customization - gAgentCamera.changeCameraToCustomizeAvatar(); - } - } + LLAgentWearables::editWearable(mUUID); } // static @@ -4987,10 +4730,10 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, { if( get_is_item_worn( item_id ) ) { - EWearableType type = wearable->getType(); + LLWearableType::EType type = wearable->getType(); - if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES ) ) //&& - //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) + if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES ) ) //&& + //!((!gAgent.isTeen()) && ( type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT )) ) { bool do_remove_all = false; U32 index = gAgentWearables.getWearableIndex(wearable); @@ -5010,23 +4753,25 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, void LLWearableBridge::removeAllClothesFromAvatar() { // Remove COF links. - for (S32 itype = WT_SHAPE; itype < WT_COUNT; ++itype) + for (S32 itype = LLWearableType::WT_SHAPE; itype < LLWearableType::WT_COUNT; ++itype) { - if (itype == WT_SHAPE || itype == WT_SKIN || itype == WT_HAIR || itype == WT_EYES) - continue; - - // MULTI-WEARABLES: fixed to index 0 - LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>( - gAgentWearables.getWearableInventoryItem((EWearableType)itype, 0)); - if (!item) - continue; - const LLUUID &item_id = gInventory.getLinkedItemID(item->getUUID()); - const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id); - if (!wearable) + if (itype == LLWearableType::WT_SHAPE || itype == LLWearableType::WT_SKIN || itype == LLWearableType::WT_HAIR || itype == LLWearableType::WT_EYES) continue; - // Find and remove this item from the COF. - LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false); + for (S32 index = gAgentWearables.getWearableCount(itype)-1; index >= 0 ; --index) + { + LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>( + gAgentWearables.getWearableInventoryItem((LLWearableType::EType)itype, index)); + if (!item) + continue; + const LLUUID &item_id = item->getUUID(); + const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id); + if (!wearable) + continue; + + // Find and remove this item from the COF. + LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false); + } } gInventory.notifyObservers(); @@ -5060,18 +4805,9 @@ void LLWearableBridge::removeFromAvatar() // | LLLinkItemBridge | // +=================================================+ // For broken item links + std::string LLLinkItemBridge::sPrefix("Link: "); -LLUIImagePtr LLLinkItemBridge::getIcon() const -{ - if (LLViewerInventoryItem *item = getItem()) - { - U32 attachment_point = (item->getFlags() & 0xff); // low byte of inventory flags - bool is_multi = LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS & item->getFlags(); - return get_item_icon(item->getActualType(), item->getInventoryType(), attachment_point, is_multi); - } - return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE); -} void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { // *TODO: Translate @@ -5101,16 +4837,24 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::string LLLinkFolderBridge::sPrefix("Link: "); LLUIImagePtr LLLinkFolderBridge::getIcon() const { - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - if (LLViewerInventoryItem *item = getItem()) + LLFolderType::EType folder_type = LLFolderType::FT_NONE; + const LLInventoryObject *obj = getInventoryObject(); + if (obj) { - if (const LLViewerInventoryCategory* cat = item->getLinkedCategory()) + LLViewerInventoryCategory* cat = NULL; + LLInventoryModel* model = getInventoryModel(); + if(model) { - preferred_type = cat->getPreferredType(); + cat = (LLViewerInventoryCategory*)model->getCategory(obj->getLinkedUUID()); + if (cat) + { + folder_type = cat->getPreferredType(); + } } } - return LLFolderBridge::getIcon(preferred_type); + return LLFolderBridge::getIcon(folder_type); } + void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { // *TODO: Translate @@ -5175,9 +4919,13 @@ const LLUUID &LLLinkFolderBridge::getFolderID() const // static void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type, - const LLUUID& uuid,LLInventoryModel* model) + const LLUUID& uuid, + LLInventoryModel* model) { - LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); + // Perform indirection in case of link. + const LLUUID& linked_uuid = gInventory.getLinkedItemID(uuid); + + LLInvFVBridgeAction* action = createAction(asset_type,linked_uuid,model); if(action) { action->doIt(); @@ -5290,7 +5038,8 @@ protected: }; -class LLNotecardBridgeAction: public LLInvFVBridgeAction +class LLNotecardBridgeAction +: public LLInvFVBridgeAction { friend class LLInvFVBridgeAction; public: @@ -5385,41 +5134,7 @@ class LLWearableBridgeAction: public LLInvFVBridgeAction public: virtual void doIt() { - if(isItemInTrash()) - { - LLNotificationsUtil::add("CannotWearTrash"); - } - else if(isAgentInventory()) - { - if(!get_is_item_worn(mUUID)) - { - wearOnAvatar(); - } - } - else - { - // must be in the inventory library. copy it to our inventory - // and put it on right away. - LLViewerInventoryItem* item = getItem(); - if(item && item->isFinished()) - { - LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else if(item) - { - // *TODO: We should fetch the item details, and then do - // the operation above. - LLNotificationsUtil::add("CannotWearInfoNotComplete"); - } - } - LLInvFVBridgeAction::doIt(); + wearOnAvatar(); } virtual ~LLWearableBridgeAction(){} protected: @@ -5447,32 +5162,12 @@ BOOL LLWearableBridgeAction::isAgentInventory() const void LLWearableBridgeAction::wearOnAvatar() { - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); - return; - } + // TODO: investigate wearables may not be loaded at this point EXT-8231 LLViewerInventoryItem* item = getItem(); if(item) { - if(!isAgentInventory()) - { - LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_inventory_item_on_avatar(item); - } + LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true); } } @@ -5523,3 +5218,67 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_ /** Bridge Actions ** ********************************************************************************/ + +/************************************************************************/ +/* Recent Inventory Panel related classes */ +/************************************************************************/ +void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LLFolderBridge::buildContextMenu(menu, flags); + + menuentry_vec_t disabled_items, items = getMenuItems(); + + items.erase(std::remove(items.begin(), items.end(), std::string("New Body Parts")), items.end()); + items.erase(std::remove(items.begin(), items.end(), std::string("New Clothes")), items.end()); + items.erase(std::remove(items.begin(), items.end(), std::string("New Note")), items.end()); + items.erase(std::remove(items.begin(), items.end(), std::string("New Gesture")), items.end()); + items.erase(std::remove(items.begin(), items.end(), std::string("New Script")), items.end()); + items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end()); + + hide_context_entries(menu, items, disabled_items); +} + +LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge( + LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, + LLInventoryType::EType inv_type, + LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid, + U32 flags /*= 0x00*/ ) const +{ + LLInvFVBridge* new_listener = NULL; + switch(asset_type) + { + case LLAssetType::AT_CATEGORY: + if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) + { + // *TODO: Create a link folder handler instead if it is necessary + new_listener = LLInventoryFVBridgeBuilder::createBridge( + asset_type, + actual_asset_type, + inv_type, + inventory, + root, + uuid, + flags); + break; + } + new_listener = new LLRecentItemsFolderBridge(inv_type, inventory, root, uuid); + break; + default: + new_listener = LLInventoryFVBridgeBuilder::createBridge( + asset_type, + actual_asset_type, + inv_type, + inventory, + root, + uuid, + flags); + } + return new_listener; + +} + + +// EOF |