diff options
Diffstat (limited to 'indra/newview/llinventorybridge.cpp')
-rw-r--r-- | indra/newview/llinventorybridge.cpp | 16311 |
1 files changed, 8262 insertions, 8049 deletions
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 909b7b01ea..d29bcdaa2c 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1,8049 +1,8262 @@ -/** - * @file llinventorybridge.cpp - * @brief Implementation of the Inventory-Folder-View-Bridge classes. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llinventorybridge.h" - -// external projects -#include "lltransfersourceasset.h" -#include "llavatarnamecache.h" // IDEVO - -#include "llagent.h" -#include "llagentcamera.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llattachmentsmgr.h" -#include "llavataractions.h" -#include "llfavoritesbar.h" // management of favorites folder -#include "llfloateropenobject.h" -#include "llfloaterreg.h" -#include "llfloatermarketplacelistings.h" -#include "llfloatersidepanelcontainer.h" -#include "llsidepanelinventory.h" -#include "llfloaterworldmap.h" -#include "llfolderview.h" -#include "llfriendcard.h" -#include "llgesturemgr.h" -#include "llgiveinventory.h" -#include "llfloaterimcontainer.h" -#include "llimview.h" -#include "llclipboard.h" -#include "llinventorydefines.h" -#include "llinventoryfunctions.h" -#include "llinventoryicon.h" -#include "llinventorymodel.h" -#include "llinventorymodelbackgroundfetch.h" -#include "llinventorypanel.h" -#include "llmarketplacefunctions.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "llpreviewanim.h" -#include "llpreviewgesture.h" -#include "llpreviewtexture.h" -#include "llselectmgr.h" -#include "llsidepanelappearance.h" -#include "lltooldraganddrop.h" -#include "lltrans.h" -#include "llurlaction.h" -#include "llviewerassettype.h" -#include "llviewerfoldertype.h" -#include "llviewermenu.h" -#include "llviewermessage.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llviewerwindow.h" -#include "llvoavatarself.h" -#include "llwearablelist.h" -#include "llwearableitemslist.h" -#include "lllandmarkactions.h" -#include "llpanellandmarks.h" -#include "llviewerparcelmgr.h" -#include "llparcel.h" - -#include "llenvironment.h" - -#include <boost/shared_ptr.hpp> - -void copy_slurl_to_clipboard_callback_inv(const std::string& slurl); - -const F32 SOUND_GAIN = 1.0f; - -using namespace LLOldEvents; - -// Function declarations -bool confirm_attachment_rez(const LLSD& notification, const LLSD& response); -void teleport_via_landmark(const LLUUID& asset_id); -static bool check_category(LLInventoryModel* model, - const LLUUID& cat_id, - LLInventoryPanel* active_panel, - LLInventoryFilter* filter); -static bool check_item(const LLUUID& item_id, - LLInventoryPanel* active_panel, - LLInventoryFilter* filter); - -// Helper functions - -bool isAddAction(const std::string& action) -{ - return ("wear" == action || "attach" == action || "activate" == action); -} - -bool isRemoveAction(const std::string& action) -{ - return ("take_off" == action || "detach" == action); -} - -bool isMarketplaceSendAction(const std::string& action) -{ - return ("send_to_marketplace" == action); -} - -bool isPanelActive(const std::string& panel_name) -{ - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(false); - return (active_panel && (active_panel->getName() == panel_name)); -} - -// Used by LLFolderBridge as callback for directory fetching recursion -class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver -{ -public: - LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) {} - ~LLRightClickInventoryFetchDescendentsObserver() {} - virtual void execute(bool clear_observer = false); - virtual void done() - { - execute(true); - } -}; - -// Used by LLFolderBridge as callback for directory content items fetching -class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver -{ -public: - LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : LLInventoryFetchItemsObserver(ids) { }; - ~LLRightClickInventoryFetchObserver() {} - void execute(bool clear_observer = false) - { - if (clear_observer) - { - gInventory.removeObserver(this); - delete this; - } - // we've downloaded all the items, so repaint the dialog - LLFolderBridge::staticFolderOptionsMenu(); - } - virtual void done() - { - execute(true); - } -}; - -class LLPasteIntoFolderCallback: public LLInventoryCallback -{ -public: - LLPasteIntoFolderCallback(LLHandle<LLInventoryPanel>& handle) - : mInventoryPanel(handle) - { - } - ~LLPasteIntoFolderCallback() - { - processItems(); - } - - void fire(const LLUUID& inv_item) - { - mChangedIds.push_back(inv_item); - } - - void processItems() - { - LLInventoryPanel* panel = mInventoryPanel.get(); - bool has_elements = false; - for (LLUUID& inv_item : mChangedIds) - { - LLInventoryItem* item = gInventory.getItem(inv_item); - if (item && panel) - { - LLUUID root_id = panel->getRootFolderID(); - - if (inv_item == root_id) - { - return; - } - - LLFolderViewItem* item = panel->getItemByID(inv_item); - if (item) - { - if (!has_elements) - { - panel->clearSelection(); - panel->getRootFolder()->clearSelection(); - panel->getRootFolder()->requestArrange(); - panel->getRootFolder()->update(); - has_elements = true; - } - panel->getRootFolder()->changeSelection(item, true); - } - } - } - - if (has_elements) - { - panel->getRootFolder()->scrollToShowSelection(); - } - } -private: - LLHandle<LLInventoryPanel> mInventoryPanel; - std::vector<LLUUID> mChangedIds; -}; - -// +=================================================+ -// | LLInvFVBridge | -// +=================================================+ - -LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, - LLFolderView* root, - const LLUUID& uuid) : - mUUID(uuid), - mRoot(root), - mInvType(LLInventoryType::IT_NONE), - mIsLink(false), - LLFolderViewModelItemInventory(inventory->getRootViewModel()) -{ - mInventoryPanel = inventory->getInventoryPanelHandle(); - const LLInventoryObject* obj = getInventoryObject(); - mIsLink = obj && obj->getIsLinkType(); -} - -const std::string& LLInvFVBridge::getName() const -{ - const LLInventoryObject* obj = getInventoryObject(); - if(obj) - { - return obj->getName(); - } - return LLStringUtil::null; -} - -const std::string& LLInvFVBridge::getDisplayName() const -{ - if(mDisplayName.empty()) - { - buildDisplayName(); - } - return mDisplayName; -} - -std::string LLInvFVBridge::getSearchableDescription() const -{ - return get_searchable_description(getInventoryModel(), mUUID); -} - -std::string LLInvFVBridge::getSearchableCreatorName() const -{ - return get_searchable_creator_name(getInventoryModel(), mUUID); -} - -std::string LLInvFVBridge::getSearchableUUIDString() const -{ - return get_searchable_UUID(getInventoryModel(), mUUID); -} - -// Folders have full perms -PermissionMask LLInvFVBridge::getPermissionMask() const -{ - return PERM_ALL; -} - -// virtual -LLFolderType::EType LLInvFVBridge::getPreferredType() const -{ - return LLFolderType::FT_NONE; -} - - -// Folders don't have creation dates. -time_t LLInvFVBridge::getCreationDate() const -{ - LLInventoryObject* objectp = getInventoryObject(); - if (objectp) - { - return objectp->getCreationDate(); - } - return (time_t)0; -} - -void LLInvFVBridge::setCreationDate(time_t creation_date_utc) -{ - LLInventoryObject* objectp = getInventoryObject(); - if (objectp) - { - objectp->setCreationDate(creation_date_utc); - } -} - - -// Can be destroyed (or moved to trash) -bool LLInvFVBridge::isItemRemovable() const -{ - return get_is_item_removable(getInventoryModel(), mUUID); -} - -// Can be moved to another folder -bool LLInvFVBridge::isItemMovable() const -{ - return true; -} - -bool LLInvFVBridge::isLink() const -{ - return mIsLink; -} - -bool LLInvFVBridge::isLibraryItem() const -{ - return gInventory.isObjectDescendentOf(getUUID(),gInventory.getLibraryRootFolderID()); -} - -/*virtual*/ -/** - * @brief Adds this item into clipboard storage - */ -bool LLInvFVBridge::cutToClipboard() -{ - const LLInventoryObject* obj = gInventory.getObject(mUUID); - if (obj && isItemMovable() && isItemRemovable()) - { - const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - const bool cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id); - - if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) || - LLMarketplaceData::instance().isListedAndActive(mUUID))) - { - LLUUID parent_uuid = obj->getParentUUID(); - bool result = perform_cutToClipboard(); - gInventory.addChangedMask(LLInventoryObserver::STRUCTURE, parent_uuid); - return result; - } - else - { - // Otherwise just perform the cut - return perform_cutToClipboard(); - } - } - return false; -} - -// virtual -bool LLInvFVBridge::isCutToClipboard() -{ - if (LLClipboard::instance().isCutMode()) - { - return LLClipboard::instance().isOnClipboard(mUUID); - } - return false; -} - -// Callback for cutToClipboard if DAMA required... -bool LLInvFVBridge::callback_cutToClipboard(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - return perform_cutToClipboard(); - } - return false; -} - -bool LLInvFVBridge::perform_cutToClipboard() -{ - const LLInventoryObject* obj = gInventory.getObject(mUUID); - if (obj && isItemMovable() && isItemRemovable()) - { - LLClipboard::instance().setCutMode(true); - return LLClipboard::instance().addToClipboard(mUUID); - } - return false; -} - -bool LLInvFVBridge::copyToClipboard() const -{ - const LLInventoryObject* obj = gInventory.getObject(mUUID); - if (obj && isItemCopyable()) - { - return LLClipboard::instance().addToClipboard(mUUID); - } - return false; -} - -void LLInvFVBridge::showProperties() -{ - if (isMarketplaceListingsFolder()) - { - LLFloaterReg::showInstance("item_properties", LLSD().with("id",mUUID),true); - // Force it to show on top as this floater has a tendency to hide when confirmation dialog shows up - LLFloater* floater_properties = LLFloaterReg::findInstance("item_properties", LLSD().with("id",mUUID)); - if (floater_properties) - { - floater_properties->setVisibleAndFrontmost(); - } - } - else - { - show_item_profile(mUUID); - } -} - -void LLInvFVBridge::navigateToFolder(bool new_window, bool change_mode) -{ - if(new_window) - { - mInventoryPanel.get()->openSingleViewInventory(mUUID); - } - else - { - if(change_mode) - { - LLInventoryPanel::setSFViewAndOpenFolder(mInventoryPanel.get(), mUUID); - } - else - { - LLInventorySingleFolderPanel* panel = dynamic_cast<LLInventorySingleFolderPanel*>(mInventoryPanel.get()); - if (!panel || !getInventoryModel() || mUUID.isNull()) - { - return; - } - - panel->changeFolderRoot(mUUID); - } - - } -} - -void LLInvFVBridge::removeBatch(std::vector<LLFolderViewModelItem*>& batch) -{ - // Deactivate gestures when moving them into Trash - LLInvFVBridge* bridge; - LLInventoryModel* model = getInventoryModel(); - LLViewerInventoryItem* item = NULL; - LLViewerInventoryCategory* cat = NULL; - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - S32 count = batch.size(); - S32 i,j; - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch[i]); - if(!bridge || !bridge->isItemRemovable()) continue; - item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); - if (item) - { - if(LLAssetType::AT_GESTURE == item->getType()) - { - LLGestureMgr::instance().deactivateGesture(item->getUUID()); - } - } - } - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch[i]); - if(!bridge || !bridge->isItemRemovable()) continue; - cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); - if (cat) - { - gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, false ); - for (j=0; j<descendent_items.size(); j++) - { - if(LLAssetType::AT_GESTURE == descendent_items[j]->getType()) - { - LLGestureMgr::instance().deactivateGesture(descendent_items[j]->getUUID()); - } - } - } - } - removeBatchNoCheck(batch); - model->checkTrashOverflow(); -} - -void LLInvFVBridge::removeBatchNoCheck(std::vector<LLFolderViewModelItem*>& batch) -{ - // this method moves a bunch of items and folders to the trash. As - // per design guidelines for the inventory model, the message is - // built and the accounting is performed first. After all of that, - // we call LLInventoryModel::moveObject() to move everything - // around. - LLInvFVBridge* bridge; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLMessageSystem* msg = gMessageSystem; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - LLViewerInventoryItem* item = NULL; - uuid_vec_t move_ids; - LLInventoryModel::update_map_t update; - bool start_new_message = true; - S32 count = batch.size(); - S32 i; - - // first, hide any 'preview' floaters that correspond to the items - // being deleted. - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch[i]); - if(!bridge || !bridge->isItemRemovable()) continue; - item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); - if(item) - { - LLPreview::hide(item->getUUID()); - } - } - - // do the inventory move to trash - - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch[i]); - if(!bridge || !bridge->isItemRemovable()) continue; - item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); - if(item) - { - if(item->getParentUUID() == trash_id) continue; - move_ids.push_back(item->getUUID()); - --update[item->getParentUUID()]; - ++update[trash_id]; - if(start_new_message) - { - start_new_message = false; - msg->newMessageFast(_PREHASH_MoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addBOOLFast(_PREHASH_Stamp, true); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, item->getUUID()); - msg->addUUIDFast(_PREHASH_FolderID, trash_id); - msg->addString("NewName", NULL); - if(msg->isSendFullFast(_PREHASH_InventoryData)) - { - start_new_message = true; - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - update.clear(); - } - } - } - if(!start_new_message) - { - start_new_message = true; - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - update.clear(); - } - - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch[i]); - if(!bridge || !bridge->isItemRemovable()) continue; - LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); - if(cat) - { - if(cat->getParentUUID() == trash_id) continue; - move_ids.push_back(cat->getUUID()); - --update[cat->getParentUUID()]; - ++update[trash_id]; - if(start_new_message) - { - start_new_message = false; - msg->newMessageFast(_PREHASH_MoveInventoryFolder); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addBOOL("Stamp", true); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID()); - msg->addUUIDFast(_PREHASH_ParentID, trash_id); - if(msg->isSendFullFast(_PREHASH_InventoryData)) - { - start_new_message = true; - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - update.clear(); - } - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - } - - // move everything. - uuid_vec_t::iterator it = move_ids.begin(); - uuid_vec_t::iterator end = move_ids.end(); - for(; it != end; ++it) - { - gInventory.moveObject((*it), trash_id); - LLViewerInventoryItem* item = gInventory.getItem(*it); - if (item) - { - model->updateItem(item); - } - } - - // notify inventory observers. - model->notifyObservers(); -} - -bool LLInvFVBridge::isClipboardPasteable() const -{ - // Return false on degenerated cases: empty clipboard, no inventory, no agent - if (!LLClipboard::instance().hasContents() || !isAgentInventory()) - { - return false; - } - LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return false; - } - - // In cut mode, whatever is on the clipboard is always pastable - if (LLClipboard::instance().isCutMode()) - { - return true; - } - - // In normal mode, we need to check each element of the clipboard to know if we can paste or not - std::vector<LLUUID> objects; - LLClipboard::instance().pasteFromClipboard(objects); - S32 count = objects.size(); - for(S32 i = 0; i < count; i++) - { - const LLUUID &item_id = objects.at(i); - - // Folders are pastable if all items in there are copyable - const LLInventoryCategory *cat = model->getCategory(item_id); - if (cat) - { - LLFolderBridge cat_br(mInventoryPanel.get(), mRoot, item_id); - if (!cat_br.isItemCopyable(false)) - return false; - // Skip to the next item in the clipboard - continue; - } - - // Each item must be copyable to be pastable - LLItemBridge item_br(mInventoryPanel.get(), mRoot, item_id); - if (!item_br.isItemCopyable(false)) - { - return false; - } - } - return true; -} - -bool LLInvFVBridge::isClipboardPasteableAsLink() const -{ - if (!LLClipboard::instance().hasContents() || !isAgentInventory()) - { - return false; - } - const LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return false; - } - - std::vector<LLUUID> objects; - LLClipboard::instance().pasteFromClipboard(objects); - S32 count = objects.size(); - for(S32 i = 0; i < count; i++) - { - const LLInventoryItem *item = model->getItem(objects.at(i)); - if (item) - { - if (!LLAssetType::lookupCanLink(item->getActualType())) - { - return false; - } - - if (gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getLibraryRootFolderID())) - { - return false; - } - } - const LLViewerInventoryCategory *cat = model->getCategory(objects.at(i)); - if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) - { - return false; - } - } - return true; -} - -void disable_context_entries_if_present(LLMenuGL& menu, - const menuentry_vec_t &disabled_entries) -{ - const LLView::child_list_t *list = menu.getChildList(); - for (LLView::child_list_t::const_iterator itor = list->begin(); - itor != list->end(); - ++itor) - { - LLView *menu_item = (*itor); - std::string name = menu_item->getName(); - - // descend into split menus: - LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item); - if ((name == "More") && branchp) - { - disable_context_entries_if_present(*branchp->getBranch(), disabled_entries); - } - - bool found = false; - menuentry_vec_t::const_iterator itor2; - for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2) - { - if (*itor2 == name) - { - found = true; - break; - } - } - - if (found) - { - 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); - - menu_item->setEnabled(false); - } - } -} -void hide_context_entries(LLMenuGL& menu, - const menuentry_vec_t &entries_to_show, - const menuentry_vec_t &disabled_entries) -{ - const LLView::child_list_t *list = menu.getChildList(); - - // For removing double separators or leading separator. Start at true so that - // if the first element is a separator, it will not be shown. - bool is_previous_entry_separator = true; - - for (LLView::child_list_t::const_iterator itor = list->begin(); - itor != list->end(); - ++itor) - { - LLView *menu_item = (*itor); - std::string name = menu_item->getName(); - - // descend into split menus: - LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item); - if (((name == "More") || (name == "create_new")) && branchp) - { - hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries); - } - - bool found = false; - - std::string myinput; - std::vector<std::string> mylist{ "a", "b", "c" }; - - menuentry_vec_t::const_iterator itor2 = std::find(entries_to_show.begin(), entries_to_show.end(), name); - if (itor2 != entries_to_show.end()) - { - found = true; - } - - // Don't allow multiple separators in a row (e.g. such as if there are no items - // between two separators). - if (found) - { - const bool is_entry_separator = (dynamic_cast<LLMenuItemSeparatorGL *>(menu_item) != NULL); - found = !(is_entry_separator && is_previous_entry_separator); - is_previous_entry_separator = is_entry_separator; - } - - if (!found) - { - if (!menu_item->getLastVisible()) - { - menu_item->setVisible(false); - } - - if (menu_item->getEnabled()) - { - // These should stay enabled unless specifically disabled - const menuentry_vec_t exceptions = { - "Detach From Yourself", - "Wearable And Object Wear", - "Wearable Add", - }; - - menuentry_vec_t::const_iterator itor2 = std::find(exceptions.begin(), exceptions.end(), name); - if (itor2 == exceptions.end()) - { - menu_item->setEnabled(false); - } - } - } - else - { - 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); - - bool enabled = true; - for (itor2 = disabled_entries.begin(); enabled && (itor2 != disabled_entries.end()); ++itor2) - { - enabled &= (*itor2 != name); - } - - menu_item->setEnabled(enabled); - } - } -} - -// Helper for commonly-used entries -void LLInvFVBridge::getClipboardEntries(bool show_asset_id, - menuentry_vec_t &items, - menuentry_vec_t &disabled_items, U32 flags) -{ - const LLInventoryObject *obj = getInventoryObject(); - bool single_folder_root = (mRoot == NULL); - - if (obj) - { - - if (obj->getType() != LLAssetType::AT_CATEGORY) - { - items.push_back(std::string("Copy Separator")); - } - items.push_back(std::string("Copy")); - if (!isItemCopyable()) - { - disabled_items.push_back(std::string("Copy")); - } - - if (isAgentInventory() && !single_folder_root) - { - items.push_back(std::string("New folder from selected")); - items.push_back(std::string("Subfolder Separator")); - std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); - uuid_vec_t ids; - std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids)); - if (!is_only_items_selected(ids) && !is_only_cats_selected(ids)) - { - disabled_items.push_back(std::string("New folder from selected")); - } - } - - if (obj->getIsLinkType()) - { - items.push_back(std::string("Find Original")); - if (isLinkedObjectMissing()) - { - disabled_items.push_back(std::string("Find Original")); - } - - items.push_back(std::string("Cut")); - if (!isItemMovable() || !isItemRemovable()) - { - disabled_items.push_back(std::string("Cut")); - } - } - else - { - if (LLAssetType::lookupCanLink(obj->getType())) - { - items.push_back(std::string("Find Links")); - } - - if (!isInboxFolder() && !single_folder_root) - { - items.push_back(std::string("Rename")); - if (!isItemRenameable() || ((flags & FIRST_SELECTED_ITEM) == 0)) - { - disabled_items.push_back(std::string("Rename")); - } - } - - items.push_back(std::string("thumbnail")); - if (isLibraryItem()) - { - disabled_items.push_back(std::string("thumbnail")); - } - - LLViewerInventoryItem *inv_item = gInventory.getItem(mUUID); - if (show_asset_id) - { - items.push_back(std::string("Copy Asset UUID")); - - bool is_asset_knowable = false; - - if (inv_item) - { - is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(inv_item->getType()); - } - if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308 - || (! ( isItemPermissive() || gAgent.isGodlike() ) ) - || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Copy Asset UUID")); - } - } - - if(!single_folder_root) - { - items.push_back(std::string("Cut")); - if (!isItemMovable() || !isItemRemovable()) - { - disabled_items.push_back(std::string("Cut")); - } - - if (canListOnMarketplace() && !isMarketplaceListingsFolder() && !isInboxFolder()) - { - items.push_back(std::string("Marketplace Separator")); - - if (gMenuHolder->getChild<LLView>("MarketplaceListings")->getVisible()) - { - items.push_back(std::string("Marketplace Copy")); - items.push_back(std::string("Marketplace Move")); - if (!canListOnMarketplaceNow()) - { - disabled_items.push_back(std::string("Marketplace Copy")); - disabled_items.push_back(std::string("Marketplace Move")); - } - } - } - } - } - } - - // Don't allow items to be pasted directly into the COF or the inbox - if (!isCOFFolder() && !isInboxFolder()) - { - items.push_back(std::string("Paste")); - } - if (!isClipboardPasteable() || ((flags & FIRST_SELECTED_ITEM) == 0)) - { - disabled_items.push_back(std::string("Paste")); - } - - static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true); - if (inventory_linking) - { - items.push_back(std::string("Paste As Link")); - if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Paste As Link")); - } - } - - if (obj->getType() != LLAssetType::AT_CATEGORY) - { - items.push_back(std::string("Paste Separator")); - } - - if(!single_folder_root) - { - addDeleteContextMenuOptions(items, disabled_items); - } - - if (!isPanelActive("All Items") && !isPanelActive("comb_single_folder_inv")) - { - items.push_back(std::string("Show in Main Panel")); - } -} - -void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLInvFVBridge::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - - addOpenRightClickMenuOption(items); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -bool get_selection_item_uuids(LLFolderView::selected_items_t& selected_items, uuid_vec_t& ids) -{ - uuid_vec_t results; - S32 non_item = 0; - for(LLFolderView::selected_items_t::iterator it = selected_items.begin(); it != selected_items.end(); ++it) - { - LLItemBridge *view_model = dynamic_cast<LLItemBridge *>((*it)->getViewModelItem()); - - if(view_model && view_model->getUUID().notNull()) - { - results.push_back(view_model->getUUID()); - } - else - { - non_item++; - } - } - if (non_item == 0) - { - ids = results; - return true; - } - return false; -} - -void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items, - menuentry_vec_t &disabled_items) -{ - const LLInventoryObject *obj = getInventoryObject(); - if (obj && obj->getIsLinkType()) - { - items.push_back(std::string("Find Original")); - if (isLinkedObjectMissing()) - { - disabled_items.push_back(std::string("Find Original")); - } - } - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - items.push_back(std::string("Restore Item")); -} - -void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items, - menuentry_vec_t &disabled_items) -{ - - const LLInventoryObject *obj = getInventoryObject(); - - // Don't allow delete as a direct option from COF folder. - if (obj && obj->getIsLinkType() && isCOFFolder() && get_is_item_worn(mUUID)) - { - return; - } - - items.push_back(std::string("Delete")); - - if (!isItemRemovable() || isPanelActive("Favorite Items")) - { - disabled_items.push_back(std::string("Delete")); - } -} - -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")); -} - -void LLInvFVBridge::addMarketplaceContextMenuOptions(U32 flags, - menuentry_vec_t &items, - menuentry_vec_t &disabled_items) -{ - S32 depth = depth_nesting_in_marketplace(mUUID); - if (depth == 1) - { - // Options available at the Listing Folder level - items.push_back(std::string("Marketplace Create Listing")); - items.push_back(std::string("Marketplace Associate Listing")); - items.push_back(std::string("Marketplace Check Listing")); - items.push_back(std::string("Marketplace List")); - items.push_back(std::string("Marketplace Unlist")); - if (LLMarketplaceData::instance().isUpdating(mUUID,depth) || ((flags & FIRST_SELECTED_ITEM) == 0)) - { - // During SLM update, disable all marketplace related options - // Also disable all if multiple selected items - disabled_items.push_back(std::string("Marketplace Create Listing")); - disabled_items.push_back(std::string("Marketplace Associate Listing")); - disabled_items.push_back(std::string("Marketplace Check Listing")); - disabled_items.push_back(std::string("Marketplace List")); - disabled_items.push_back(std::string("Marketplace Unlist")); - } - else - { - if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) - { - items.push_back(std::string("Marketplace Get Listing")); - } - if (LLMarketplaceData::instance().isListed(mUUID)) - { - disabled_items.push_back(std::string("Marketplace Create Listing")); - disabled_items.push_back(std::string("Marketplace Associate Listing")); - if (LLMarketplaceData::instance().getVersionFolder(mUUID).isNull()) - { - disabled_items.push_back(std::string("Marketplace List")); - disabled_items.push_back(std::string("Marketplace Unlist")); - } - else - { - if (LLMarketplaceData::instance().getActivationState(mUUID)) - { - disabled_items.push_back(std::string("Marketplace List")); - } - else - { - disabled_items.push_back(std::string("Marketplace Unlist")); - } - } - } - else - { - disabled_items.push_back(std::string("Marketplace List")); - disabled_items.push_back(std::string("Marketplace Unlist")); - if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) - { - disabled_items.push_back(std::string("Marketplace Get Listing")); - } - } - } - } - if (depth == 2) - { - // Options available at the Version Folder levels and only for folders - LLInventoryCategory* cat = gInventory.getCategory(mUUID); - if (cat && LLMarketplaceData::instance().isListed(cat->getParentUUID())) - { - items.push_back(std::string("Marketplace Activate")); - items.push_back(std::string("Marketplace Deactivate")); - if (LLMarketplaceData::instance().isUpdating(mUUID,depth) || ((flags & FIRST_SELECTED_ITEM) == 0)) - { - // During SLM update, disable all marketplace related options - // Also disable all if multiple selected items - disabled_items.push_back(std::string("Marketplace Activate")); - disabled_items.push_back(std::string("Marketplace Deactivate")); - } - else - { - if (LLMarketplaceData::instance().isVersionFolder(mUUID)) - { - disabled_items.push_back(std::string("Marketplace Activate")); - if (LLMarketplaceData::instance().getActivationState(mUUID)) - { - disabled_items.push_back(std::string("Marketplace Deactivate")); - } - } - else - { - disabled_items.push_back(std::string("Marketplace Deactivate")); - } - } - } - } - - items.push_back(std::string("Marketplace Edit Listing")); - LLUUID listing_folder_id = nested_parent_id(mUUID,depth); - LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(listing_folder_id); - - if (depth >= 2) - { - // Prevent creation of new folders if the max count has been reached on this version folder (active or not) - LLUUID local_version_folder_id = nested_parent_id(mUUID,depth-1); - LLInventoryModel::cat_array_t categories; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(local_version_folder_id, categories, items, false); - LLCachedControl<U32> max_depth(gSavedSettings, "InventoryOutboxMaxFolderDepth", 4); - LLCachedControl<U32> max_count(gSavedSettings, "InventoryOutboxMaxFolderCount", 20); - if (categories.size() >= max_count - || depth > (max_depth + 1)) - { - disabled_items.push_back(std::string("New Folder")); - } - } - - // Options available at all levels on items and categories - if (!LLMarketplaceData::instance().isListed(listing_folder_id) || version_folder_id.isNull()) - { - disabled_items.push_back(std::string("Marketplace Edit Listing")); - } - - // Separator - items.push_back(std::string("Marketplace Listings Separator")); -} - -void LLInvFVBridge::addLinkReplaceMenuOption(menuentry_vec_t& items, menuentry_vec_t& disabled_items) -{ - const LLInventoryObject* obj = getInventoryObject(); - - if (isAgentInventory() && obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getType() != LLAssetType::AT_LINK_FOLDER) - { - items.push_back(std::string("Replace Links")); - - if (mRoot->getSelectedCount() != 1) - { - disabled_items.push_back(std::string("Replace Links")); - } - } -} - -// *TODO: remove this -bool LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const -{ - bool rv = false; - - const LLInventoryObject* obj = getInventoryObject(); - - if(obj) - { - *type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType()); - if(*type == DAD_NONE) - { - return false; - } - - *id = obj->getUUID(); - //object_ids.push_back(obj->getUUID()); - - if (*type == DAD_CATEGORY) - { - LLInventoryModelBackgroundFetch::instance().start(obj->getUUID()); - } - - rv = true; - } - - return rv; -} - -LLInventoryObject* LLInvFVBridge::getInventoryObject() const -{ - LLInventoryObject* obj = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - obj = (LLInventoryObject*)model->getObject(mUUID); - } - return obj; -} - -LLInventoryModel* LLInvFVBridge::getInventoryModel() const -{ - LLInventoryPanel* panel = mInventoryPanel.get(); - return panel ? panel->getModel() : NULL; -} - -LLInventoryFilter* LLInvFVBridge::getInventoryFilter() const -{ - LLInventoryPanel* panel = mInventoryPanel.get(); - return panel ? &(panel->getFilter()) : NULL; -} - -bool LLInvFVBridge::isItemInTrash() const -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return false; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - return model->isObjectDescendentOf(mUUID, trash_id); -} - -bool LLInvFVBridge::isLinkedObjectInTrash() const -{ - if (isItemInTrash()) return true; - - const LLInventoryObject *obj = getInventoryObject(); - if (obj && obj->getIsLinkType()) - { - LLInventoryModel* model = getInventoryModel(); - if(!model) return false; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id); - } - return false; -} - -bool LLInvFVBridge::isItemInOutfits() const -{ - const LLInventoryModel* model = getInventoryModel(); - if(!model) return false; - - const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - - return isCOFFolder() || (my_outfits_cat == mUUID) || model->isObjectDescendentOf(mUUID, my_outfits_cat); -} - -bool LLInvFVBridge::isLinkedObjectMissing() const -{ - const LLInventoryObject *obj = getInventoryObject(); - if (!obj) - { - return true; - } - if (obj->getIsLinkType() && LLAssetType::lookupIsLinkType(obj->getType())) - { - return true; - } - return false; -} - -bool LLInvFVBridge::isAgentInventory() const -{ - const LLInventoryModel* model = getInventoryModel(); - if(!model) return false; - if(gInventory.getRootFolderID() == mUUID) return true; - return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); -} - -bool LLInvFVBridge::isCOFFolder() const -{ - return LLAppearanceMgr::instance().getIsInCOF(mUUID); -} - -// *TODO : Suppress isInboxFolder() once Merchant Outbox is fully deprecated -bool LLInvFVBridge::isInboxFolder() const -{ - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX); - - if (inbox_id.isNull()) - { - return false; - } - - return gInventory.isObjectDescendentOf(mUUID, inbox_id); -} - -bool LLInvFVBridge::isMarketplaceListingsFolder() const -{ - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - - if (folder_id.isNull()) - { - return false; - } - - return gInventory.isObjectDescendentOf(mUUID, folder_id); -} - -bool LLInvFVBridge::isItemPermissive() const -{ - return false; -} - -// static -void LLInvFVBridge::changeItemParent(LLInventoryModel* model, - LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - bool restamp) -{ - model->changeItemParent(item, new_parent_id, restamp); -} - -// static -void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, - LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - bool restamp) -{ - model->changeCategoryParent(cat, new_parent_id, restamp); -} - -LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, - LLAssetType::EType actual_asset_type, - LLInventoryType::EType inv_type, - LLInventoryPanel* inventory, - LLFolderViewModelInventory* view_model, - LLFolderView* root, - const LLUUID& uuid, - U32 flags) -{ - LLInvFVBridge* new_listener = NULL; - switch(asset_type) - { - case LLAssetType::AT_TEXTURE: - if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLTextureBridge(inventory, root, uuid, inv_type); - break; - - case LLAssetType::AT_SOUND: - if(!(inv_type == LLInventoryType::IT_SOUND)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLSoundBridge(inventory, root, uuid); - break; - - case LLAssetType::AT_LANDMARK: - if(!(inv_type == LLInventoryType::IT_LANDMARK)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLLandmarkBridge(inventory, root, uuid, flags); - break; - - case LLAssetType::AT_CALLINGCARD: - if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLCallingCardBridge(inventory, root, uuid); - break; - - case LLAssetType::AT_SCRIPT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLItemBridge(inventory, root, uuid); - break; - - case LLAssetType::AT_OBJECT: - if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLObjectBridge(inventory, root, uuid, inv_type, flags); - break; - - case LLAssetType::AT_NOTECARD: - if(!(inv_type == LLInventoryType::IT_NOTECARD)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLNotecardBridge(inventory, root, uuid); - break; - - case LLAssetType::AT_ANIMATION: - if(!(inv_type == LLInventoryType::IT_ANIMATION)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLAnimationBridge(inventory, root, uuid); - break; - - case LLAssetType::AT_GESTURE: - if(!(inv_type == LLInventoryType::IT_GESTURE)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLGestureBridge(inventory, root, uuid); - break; - - case LLAssetType::AT_LSL_TEXT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLLSLTextBridge(inventory, root, uuid); - break; - - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - if(!(inv_type == LLInventoryType::IT_WEARABLE)) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, LLWearableType::inventoryFlagsToWearableType(flags)); - break; - case LLAssetType::AT_CATEGORY: - if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) - { - // Create a link folder handler instead - new_listener = new LLLinkFolderBridge(inventory, root, uuid); - } - else if (actual_asset_type == LLAssetType::AT_MARKETPLACE_FOLDER) - { - // Create a marketplace folder handler - new_listener = new LLMarketplaceFolderBridge(inventory, root, uuid); - } - else - { - new_listener = new LLFolderBridge(inventory, root, uuid); - } - break; - case LLAssetType::AT_LINK: - case LLAssetType::AT_LINK_FOLDER: - // Only should happen for broken links. - new_listener = new LLLinkItemBridge(inventory, root, uuid); - break; - case LLAssetType::AT_UNKNOWN: - new_listener = new LLUnknownItemBridge(inventory, root, uuid); - break; - case LLAssetType::AT_IMAGE_TGA: - case LLAssetType::AT_IMAGE_JPEG: - //LL_WARNS() << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << LL_ENDL; - break; - - case LLAssetType::AT_SETTINGS: - if (inv_type != LLInventoryType::IT_SETTINGS) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLSettingsBridge(inventory, root, uuid, LLSettingsType::fromInventoryFlags(flags)); - break; - - case LLAssetType::AT_MATERIAL: - if (inv_type != LLInventoryType::IT_MATERIAL) - { - LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; - } - new_listener = new LLMaterialBridge(inventory, root, uuid); - break; - - default: - LL_INFOS_ONCE() << "Unhandled asset type (llassetstorage.h): " - << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << LL_ENDL; - break; - } - - if (new_listener) - { - new_listener->mInvType = inv_type; - } - - return new_listener; -} - -void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) -{ - LLInventoryObject* obj = model->getObject(uuid); - if (obj) - { - remove_inventory_object(uuid, NULL); - } -} - -void LLInvFVBridge::removeObject(LLInventoryModel *model, const LLUUID &uuid) -{ - // Keep track of the parent - LLInventoryItem* itemp = model->getItem(uuid); - LLUUID parent_id = (itemp ? itemp->getParentUUID() : LLUUID::null); - // Remove the object - model->removeObject(uuid); - // Get the parent updated - if (parent_id.notNull()) - { - LLViewerInventoryCategory* parent_cat = model->getCategory(parent_id); - model->updateCategory(parent_cat); - model->notifyObservers(); - } -} - -bool LLInvFVBridge::canShare() const -{ - bool can_share = false; - - if (isAgentInventory()) - { - const LLInventoryModel* model = getInventoryModel(); - if (model) - { - const LLViewerInventoryItem *item = model->getItem(mUUID); - if (item) - { - if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item)) - { - can_share = LLGiveInventory::isInventoryGiveAcceptable(item); - } - } - else - { - // Categories can be given. - can_share = (model->getCategory(mUUID) != NULL); - } - - const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if ((mUUID == trash_id) || gInventory.isObjectDescendentOf(mUUID, trash_id)) - { - can_share = false; - } - } - } - - return can_share; -} - -bool LLInvFVBridge::canListOnMarketplace() const -{ - LLInventoryModel * model = getInventoryModel(); - - LLViewerInventoryCategory * cat = model->getCategory(mUUID); - if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) - { - return false; - } - - if (!isAgentInventory()) - { - return false; - } - - LLViewerInventoryItem * item = model->getItem(mUUID); - if (item) - { - if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) - { - return false; - } - - if (LLAssetType::AT_CALLINGCARD == item->getType()) - { - return false; - } - } - - return true; -} - -bool LLInvFVBridge::canListOnMarketplaceNow() const -{ - bool can_list = true; - - const LLInventoryObject* obj = getInventoryObject(); - can_list &= (obj != NULL); - - if (can_list) - { - const LLUUID& object_id = obj->getLinkedUUID(); - can_list = object_id.notNull(); - - if (can_list) - { - LLFolderViewFolder * object_folderp = mInventoryPanel.get() ? mInventoryPanel.get()->getFolderByID(object_id) : NULL; - if (object_folderp) - { - can_list = !static_cast<LLFolderBridge*>(object_folderp->getViewModelItem())->isLoading(); - } - } - - if (can_list) - { - std::string error_msg; - LLInventoryModel* model = getInventoryModel(); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - if (marketplacelistings_id.notNull()) - { - LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id); - LLInventoryCategory *cat = model->getCategory(mUUID); - if (cat) - { - can_list = can_move_folder_to_marketplace(master_folder, master_folder, cat, error_msg); - } - else - { - LLInventoryItem *item = model->getItem(mUUID); - can_list = (item ? can_move_item_to_marketplace(master_folder, master_folder, item, error_msg) : false); - } - } - else - { - can_list = false; - } - } - } - - return can_list; -} - -LLToolDragAndDrop::ESource LLInvFVBridge::getDragSource() const -{ - if (gInventory.isObjectDescendentOf(getUUID(), gInventory.getRootFolderID())) - { - return LLToolDragAndDrop::SOURCE_AGENT; - } - else if (gInventory.isObjectDescendentOf(getUUID(), gInventory.getLibraryRootFolderID())) - { - return LLToolDragAndDrop::SOURCE_LIBRARY; - } - - return LLToolDragAndDrop::SOURCE_VIEWER; -} - - - -// +=================================================+ -// | InventoryFVBridgeBuilder | -// +=================================================+ -LLInvFVBridge* LLInventoryFolderViewModelBuilder::createBridge(LLAssetType::EType asset_type, - LLAssetType::EType actual_asset_type, - LLInventoryType::EType inv_type, - LLInventoryPanel* inventory, - LLFolderViewModelInventory* view_model, - LLFolderView* root, - const LLUUID& uuid, - U32 flags /* = 0x00 */) const -{ - return LLInvFVBridge::createBridge(asset_type, - actual_asset_type, - inv_type, - inventory, - view_model, - root, - uuid, - flags); -} - -// +=================================================+ -// | LLItemBridge | -// +=================================================+ - -void LLItemBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("goto" == action) - { - gotoItem(); - } - - if ("open" == action || "open_original" == action) - { - openItem(); - return; - } - else if ("properties" == action) - { - showProperties(); - return; - } - else if ("purge" == action) - { - purgeItem(model, mUUID); - return; - } - else if ("restoreToWorld" == action) - { - restoreToWorld(); - return; - } - else if ("restore" == action) - { - restoreItem(); - return; - } - else if ("thumbnail" == action) - { - LLSD data(mUUID); - LLFloaterReg::showInstance("change_item_thumbnail", data); - return; - } - else if ("copy_uuid" == action) - { - // Single item only - LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); - if(!item) return; - LLUUID asset_id = item->getProtectedAssetUUID(); - std::string buffer; - asset_id.toString(buffer); - - gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer)); - return; - } - else if ("show_in_main_panel" == action) - { - LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true); - return; - } - else if ("cut" == action) - { - cutToClipboard(); - return; - } - else if ("copy" == action) - { - copyToClipboard(); - return; - } - else if ("paste" == action) - { - LLInventoryItem* itemp = model->getItem(mUUID); - if (!itemp) return; - - LLFolderViewItem* folder_view_itemp = mInventoryPanel.get()->getItemByID(itemp->getParentUUID()); - if (!folder_view_itemp) return; - - folder_view_itemp->getViewModelItem()->pasteFromClipboard(); - return; - } - else if ("paste_link" == action) - { - // Single item only - LLInventoryItem* itemp = model->getItem(mUUID); - if (!itemp) return; - - LLFolderViewItem* folder_view_itemp = mInventoryPanel.get()->getItemByID(itemp->getParentUUID()); - if (!folder_view_itemp) return; - - folder_view_itemp->getViewModelItem()->pasteLinkFromClipboard(); - return; - } - else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action)) - { - LLInventoryItem* itemp = model->getItem(mUUID); - if (!itemp) return; - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - // Note: For a single item, if it's not a copy, then it's a move - move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action)); - } - else if ("copy_slurl" == action) - { - LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); - if(item) - { - LLUUID asset_id = item->getAssetUUID(); - LLLandmark* landmark = gLandmarkList.getAsset(asset_id); - if (landmark) - { - LLVector3d global_pos; - landmark->getGlobalPos(global_pos); - LLLandmarkActions::getSLURLfromPosGlobal(global_pos, ©_slurl_to_clipboard_callback_inv, true); - } - } - } - else if ("show_on_map" == action) - { - doActionOnCurSelectedLandmark(boost::bind(&LLItemBridge::doShowOnMap, this, _1)); - } - else if ("marketplace_edit_listing" == action) - { - std::string url = LLMarketplaceData::instance().getListingURL(mUUID); - LLUrlAction::openURL(url); - } -} - -void LLItemBridge::doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb) -{ - LLViewerInventoryItem* cur_item = getItem(); - if(cur_item && cur_item->getInventoryType() == LLInventoryType::IT_LANDMARK) - { - LLLandmark* landmark = LLLandmarkActions::getLandmark(cur_item->getUUID(), cb); - if (landmark) - { - cb(landmark); - } - } -} - -void LLItemBridge::doShowOnMap(LLLandmark* landmark) -{ - LLVector3d landmark_global_pos; - // landmark has already been tested for NULL by calling routine - if (landmark->getGlobalPos(landmark_global_pos)) - { - LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); - if (!landmark_global_pos.isExactlyZero() && worldmap_instance) - { - worldmap_instance->trackLocation(landmark_global_pos); - LLFloaterReg::showInstance("world_map", "center"); - } - } -} - -void copy_slurl_to_clipboard_callback_inv(const std::string& slurl) -{ - gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl)); - LLSD args; - args["SLURL"] = slurl; - LLNotificationsUtil::add("CopySLURL", args); -} - -void LLItemBridge::selectItem() -{ - LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); - if(item && !item->isFinished()) - { - //item->fetchFromServer(); - LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false); - } -} - -void LLItemBridge::restoreItem() -{ - LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); - if(item) - { - LLInventoryModel* model = getInventoryModel(); - bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT); - - const LLUUID new_parent = model->findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType())); - // do not restamp on restore. - LLInvFVBridge::changeItemParent(model, item, new_parent, false); - } -} - -void LLItemBridge::restoreToWorld() -{ - //Similar functionality to the drag and drop rez logic - bool remove_from_inventory = false; - - LLViewerInventoryItem* itemp = static_cast<LLViewerInventoryItem*>(getItem()); - if (itemp) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("RezRestoreToWorld"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_InventoryData); - itemp->packMessage(msg); - msg->sendReliable(gAgent.getRegionHost()); - - //remove local inventory copy, sim will deal with permissions and removing the item - //from the actual inventory if its a no-copy etc - if(!itemp->getPermissions().allowCopyBy(gAgent.getID())) - { - remove_from_inventory = true; - } - - // Check if it's in the trash. (again similar to the normal rez logic) - const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id)) - { - remove_from_inventory = true; - } - } - - if(remove_from_inventory) - { - gInventory.deleteObject(itemp->getUUID()); - gInventory.notifyObservers(); - } -} - -void LLItemBridge::gotoItem() -{ - LLInventoryObject *obj = getInventoryObject(); - if (obj && obj->getIsLinkType()) - { - show_item_original(obj->getUUID()); - } -} - -LLUIImagePtr LLItemBridge::getIcon() const -{ - LLInventoryObject *obj = getInventoryObject(); - if (obj) - { - return LLInventoryIcon::getIcon(obj->getType(), - LLInventoryType::IT_NONE, - mIsLink); - } - - return LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT); -} - -LLUIImagePtr LLItemBridge::getIconOverlay() const -{ - if (getItem() && getItem()->getIsLinkType()) - { - return LLUI::getUIImage("Inv_Link"); - } - return NULL; -} - -PermissionMask LLItemBridge::getPermissionMask() const -{ - LLViewerInventoryItem* item = getItem(); - PermissionMask perm_mask = 0; - if (item) perm_mask = item->getPermissionMask(); - return perm_mask; -} - -void LLItemBridge::buildDisplayName() const -{ - if(getItem()) - { - mDisplayName.assign(getItem()->getName()); - } - else - { - mDisplayName.assign(LLStringUtil::null); - } - - mSearchableName.assign(mDisplayName); - mSearchableName.append(getLabelSuffix()); - LLStringUtil::toUpper(mSearchableName); - - //Name set, so trigger a sort - LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); - if(mParent && !sorter.isByDate()) - { - mParent->requestSort(); - } -} - -LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const -{ - U8 font = LLFontGL::NORMAL; - const LLViewerInventoryItem* item = getItem(); - - if (get_is_item_worn(mUUID)) - { - // LL_INFOS() << "BOLD" << LL_ENDL; - font |= LLFontGL::BOLD; - } - else if(item && item->getIsLinkType()) - { - font |= LLFontGL::ITALIC; - } - - return (LLFontGL::StyleFlags)font; -} - -std::string LLItemBridge::getLabelSuffix() const -{ - // String table is loaded before login screen and inventory items are - // loaded after login, so LLTrans should be ready. - static std::string NO_COPY = LLTrans::getString("no_copy_lbl"); - static std::string NO_MOD = LLTrans::getString("no_modify_lbl"); - static std::string NO_XFER = LLTrans::getString("no_transfer_lbl"); - static std::string LINK = LLTrans::getString("link"); - static std::string BROKEN_LINK = LLTrans::getString("broken_link"); - std::string suffix; - LLInventoryItem* item = getItem(); - if(item) - { - // Any type can have the link suffix... - bool broken_link = LLAssetType::lookupIsLinkType(item->getType()); - if (broken_link) return BROKEN_LINK; - - bool link = item->getIsLinkType(); - if (link) return LINK; - - // ...but it's a bit confusing to put nocopy/nomod/etc suffixes on calling cards. - if(LLAssetType::AT_CALLINGCARD != item->getType() - && item->getPermissions().getOwner() == gAgent.getID()) - { - bool copy = item->getPermissions().allowCopyBy(gAgent.getID()); - if (!copy) - { - suffix += " "; - suffix += NO_COPY; - } - bool mod = item->getPermissions().allowModifyBy(gAgent.getID()); - if (!mod) - { - suffix += suffix.empty() ? " " : ","; - suffix += NO_MOD; - } - bool xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, - gAgent.getID()); - if (!xfer) - { - suffix += suffix.empty() ? " " : ","; - suffix += NO_XFER; - } - } - } - return suffix; -} - -time_t LLItemBridge::getCreationDate() const -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - return item->getCreationDate(); - } - return 0; -} - - -bool LLItemBridge::isItemRenameable() const -{ - LLViewerInventoryItem* item = getItem(); - if(item) - { - // (For now) Don't allow calling card rename since that may confuse users as to - // what the calling card points to. - if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD) - { - return false; - } - - if (!item->isFinished()) // EXT-8662 - { - return false; - } - - if (isInboxFolder()) - { - return false; - } - - return (item->getPermissions().allowModifyBy(gAgent.getID())); - } - return false; -} - -bool LLItemBridge::renameItem(const std::string& new_name) -{ - if(!isItemRenameable()) - return false; - LLPreview::dirty(mUUID); - LLInventoryModel* model = getInventoryModel(); - if(!model) - return false; - LLViewerInventoryItem* item = getItem(); - if(item && (item->getName() != new_name)) - { - LLSD updates; - updates["name"] = new_name; - update_inventory_item(item->getUUID(),updates, NULL); - } - // return false because we either notified observers (& therefore - // rebuilt) or we didn't update. - return false; -} - -bool LLItemBridge::removeItem() -{ - if(!isItemRemovable()) - { - return false; - } - - // move it to the trash - LLInventoryModel* model = getInventoryModel(); - if(!model) return false; - const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - LLViewerInventoryItem* item = getItem(); - if (!item) return false; - if (item->getType() != LLAssetType::AT_LSL_TEXT) - { - LLPreview::hide(mUUID, true); - } - // 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.) - static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true); - if (!inventory_linking) - { - if (!item->getIsLinkType()) - { - LLInventoryModel::item_array_t item_array = gInventory.collectLinksTo(mUUID); - const U32 num_links = 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); - model->checkTrashOverflow(); - 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)) - { - // move to trash, and restamp - LLInvFVBridge::changeItemParent(model, item, trash_id, true); - // delete was successful - return true; - } - return false; -} - -bool LLItemBridge::isItemCopyable(bool can_copy_as_link) const -{ - LLViewerInventoryItem* item = getItem(); - if (!item) - { - return false; - } - // Can't copy worn objects. - // Worn objects are tied to their inworld conterparts - // Copy of modified worn object will return object with obsolete asset and inventory - if (get_is_item_worn(mUUID)) - { - return false; - } - - static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true); - return (can_copy_as_link && inventory_linking) - || (mIsLink && inventory_linking) - || item->getPermissions().allowCopyBy(gAgent.getID()); -} - -LLViewerInventoryItem* LLItemBridge::getItem() const -{ - LLViewerInventoryItem* item = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - item = (LLViewerInventoryItem*)model->getItem(mUUID); - } - return item; -} - -const LLUUID& LLItemBridge::getThumbnailUUID() const -{ - LLViewerInventoryItem* item = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - item = (LLViewerInventoryItem*)model->getItem(mUUID); - } - if (item) - { - return item->getThumbnailUUID(); - } - return LLUUID::null; -} - -bool LLItemBridge::isItemPermissive() const -{ - LLViewerInventoryItem* item = getItem(); - if(item) - { - return item->getIsFullPerm(); - } - return false; -} - -// +=================================================+ -// | LLFolderBridge | -// +=================================================+ - -LLHandle<LLFolderBridge> LLFolderBridge::sSelf; - -// Can be moved to another folder -bool LLFolderBridge::isItemMovable() const -{ - LLInventoryObject* obj = getInventoryObject(); - if(obj) - { - // If it's a protected type folder, we can't move it - if (LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType())) - return false; - return true; - } - return false; -} - -void LLFolderBridge::selectItem() -{ - LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID()); - if (cat) - { - cat->fetch(); - } -} - -void LLFolderBridge::buildDisplayName() const -{ - LLFolderType::EType preferred_type = getPreferredType(); - - // *TODO: to be removed when database supports multi language. This is a - // temporary attempt to display the inventory folder in the user locale. - // mantipov: *NOTE: be sure this code is synchronized with LLFriendCardsManager::findChildFolderUUID - // it uses the same way to find localized string - - // HACK: EXT - 6028 ([HARD CODED]? Inventory > Library > "Accessories" folder) - // Translation of Accessories folder in Library inventory folder - bool accessories = false; - if(getName() == "Accessories") - { - //To ensure that Accessories folder is in Library we have to check its parent folder. - //Due to parent LLFolderViewFloder is not set to this item yet we have to check its parent via Inventory Model - LLInventoryCategory* cat = gInventory.getCategory(getUUID()); - if(cat) - { - const LLUUID& parent_folder_id = cat->getParentUUID(); - accessories = (parent_folder_id == gInventory.getLibraryRootFolderID()); - } - } - - //"Accessories" inventory category has folder type FT_NONE. So, this folder - //can not be detected as protected with LLFolderType::lookupIsProtectedType - mDisplayName.assign(getName()); - if (accessories || LLFolderType::lookupIsProtectedType(preferred_type)) - { - LLTrans::findString(mDisplayName, std::string("InvFolder ") + getName(), LLSD()); - } - - mSearchableName.assign(mDisplayName); - mSearchableName.append(getLabelSuffix()); - LLStringUtil::toUpper(mSearchableName); - - //Name set, so trigger a sort - LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter(); - if(mParent && sorter.isFoldersByName()) - { - mParent->requestSort(); - } -} - -std::string LLFolderBridge::getLabelSuffix() const -{ - static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); - static LLCachedControl<bool> xui_debug(gSavedSettings, "DebugShowXUINames", 0); - - if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) - { - return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); - } - std::string suffix = ""; - if (xui_debug) - { - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(getUUID(), cats, items); - - LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID()); - if (cat) - { - LLStringUtil::format_map_t args; - args["[FOLDER_COUNT]"] = llformat("%d", cats->size()); - args["[ITEMS_COUNT]"] = llformat("%d", items->size()); - args["[VERSION]"] = llformat("%d", cat->getVersion()); - args["[VIEWER_DESCENDANT_COUNT]"] = llformat("%d", cats->size() + items->size()); - args["[SERVER_DESCENDANT_COUNT]"] = llformat("%d", cat->getDescendentCount()); - suffix = " " + LLTrans::getString("InventoryFolderDebug", args); - } - } - else if(mShowDescendantsCount) - { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(getUUID(), cat_array, item_array, true); - S32 count = item_array.size(); - if(count > 0) - { - std::ostringstream oss; - oss << count; - LLStringUtil::format_map_t args; - args["[ITEMS_COUNT]"] = oss.str(); - suffix = " " + LLTrans::getString("InventoryItemsCount", args); - } - } - - return LLInvFVBridge::getLabelSuffix() + suffix; -} - -LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const -{ - return LLFontGL::NORMAL; -} - -const LLUUID& LLFolderBridge::getThumbnailUUID() const -{ - LLViewerInventoryCategory* cat = getCategory(); - if (cat) - { - return cat->getThumbnailUUID(); - } - return LLUUID::null; -} - -void LLFolderBridge::update() -{ - // we know we have children but haven't fetched them (doesn't obey filter) - bool loading = !isUpToDate() && hasChildren() && mFolderViewItem->isOpen(); - - if (loading != mIsLoading) - { - if ( loading ) - { - // Measure how long we've been in the loading state - mTimeSinceRequestStart.reset(); - } - mIsLoading = loading; - - mFolderViewItem->refresh(); - } -} - - -// Iterate through a folder's children to determine if -// all the children are removable. -class LLIsItemRemovable : public LLFolderViewFunctor -{ -public: - LLIsItemRemovable() : mPassed(true) {} - virtual void doFolder(LLFolderViewFolder* folder) - { - mPassed &= folder->getViewModelItem()->isItemRemovable(); - } - virtual void doItem(LLFolderViewItem* item) - { - mPassed &= item->getViewModelItem()->isItemRemovable(); - } - bool mPassed; -}; - -// Can be destroyed (or moved to trash) -bool LLFolderBridge::isItemRemovable() const -{ - if (!get_is_category_removable(getInventoryModel(), mUUID)) - { - return false; - } - - LLInventoryPanel* panel = mInventoryPanel.get(); - LLFolderViewFolder* folderp = dynamic_cast<LLFolderViewFolder*>(panel ? panel->getItemByID(mUUID) : NULL); - if (folderp) - { - LLIsItemRemovable folder_test; - folderp->applyFunctorToChildren(folder_test); - if (!folder_test.mPassed) - { - return false; - } - } - - if (isMarketplaceListingsFolder() && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID))) - { - return false; - } - - return true; -} - -bool LLFolderBridge::isUpToDate() const -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return false; - LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); - if( !category ) - { - return false; - } - - return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; -} - -bool LLFolderBridge::isItemCopyable(bool can_copy_as_link) const -{ - if (can_copy_as_link && !LLFolderType::lookupIsProtectedType(getPreferredType())) - { - // Can copy and paste unprotected folders as links - return true; - } - - // Folders are copyable if items in them are, recursively, copyable. - - // Get the content of the folder - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(mUUID,cat_array,item_array); - - // Check the items - LLInventoryModel::item_array_t item_array_copy = *item_array; - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; - LLItemBridge item_br(mInventoryPanel.get(), mRoot, item->getUUID()); - if (!item_br.isItemCopyable(false)) - { - return false; - } - } - - // Check the folders - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLViewerInventoryCategory* category = *iter; - LLFolderBridge cat_br(mInventoryPanel.get(), mRoot, category->getUUID()); - if (!cat_br.isItemCopyable(false)) - { - return false; - } - } - - return true; -} - -bool LLFolderBridge::isClipboardPasteable() const -{ - if ( ! LLInvFVBridge::isClipboardPasteable() ) - return false; - - // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 - if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) ) - { - LLInventoryModel* model = getInventoryModel(); - if ( !model ) - { - return false; - } - - std::vector<LLUUID> objects; - LLClipboard::instance().pasteFromClipboard(objects); - const LLViewerInventoryCategory *current_cat = getCategory(); - - // Search for the direct descendent of current Friends subfolder among all pasted items, - // and return false if is found. - for(S32 i = objects.size() - 1; i >= 0; --i) - { - const LLUUID &obj_id = objects.at(i); - if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) - { - return false; - } - } - - } - return true; -} - -bool LLFolderBridge::isClipboardPasteableAsLink() const -{ - // Check normal paste-as-link permissions - if (!LLInvFVBridge::isClipboardPasteableAsLink()) - { - return false; - } - - const LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return false; - } - - const LLViewerInventoryCategory *current_cat = getCategory(); - if (current_cat) - { - const bool is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat ); - const LLUUID ¤t_cat_id = current_cat->getUUID(); - std::vector<LLUUID> objects; - LLClipboard::instance().pasteFromClipboard(objects); - S32 count = objects.size(); - for(S32 i = 0; i < count; i++) - { - const LLUUID &obj_id = objects.at(i); - const LLInventoryCategory *cat = model->getCategory(obj_id); - if (cat) - { - const LLUUID &cat_id = cat->getUUID(); - // Don't allow recursive pasting - if ((cat_id == current_cat_id) || - model->isObjectDescendentOf(current_cat_id, cat_id)) - { - return false; - } - } - // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 - if ( is_in_friend_folder ) - { - // If object is direct descendent of current Friends subfolder than return false. - // Note: We can't use 'const LLInventoryCategory *cat', because it may be null - // in case type of obj_id is LLInventoryItem. - if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) - { - return false; - } - } - } - } - return true; - -} - - -bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, - bool drop, - std::string& tooltip_msg, - bool is_link, - bool user_confirm, - LLPointer<LLInventoryCallback> cb) -{ - - LLInventoryModel* model = getInventoryModel(); - - 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 - - LLInventoryPanel* destination_panel = mInventoryPanel.get(); - if (!destination_panel) return false; - - LLInventoryFilter* filter = getInventoryFilter(); - if (!filter) return false; - - const LLUUID &cat_id = inv_cat->getUUID(); - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - const LLUUID from_folder_uuid = inv_cat->getParentUUID(); - - const bool move_is_into_current_outfit = (mUUID == current_outfit_id); - const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - const bool move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id); - - // check to make sure source is agent inventory, and is represented there. - LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - const bool is_agent_inventory = (model->getCategory(cat_id) != NULL) - && (LLToolDragAndDrop::SOURCE_AGENT == source); - - bool accept = false; - U64 filter_types = filter->getFilterTypes(); - bool use_filter = filter_types && (filter_types&LLInventoryFilter::FILTERTYPE_DATE || (filter_types&LLInventoryFilter::FILTERTYPE_OBJECT)==0); - - if (is_agent_inventory) - { - const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - - const bool move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); - const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const bool move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT); - const bool move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); - const bool move_is_into_lost_and_found = model->isObjectDescendentOf(mUUID, lost_and_found_id); - - //-------------------------------------------------------------------------------- - // Determine if folder can be moved. - // - - bool is_movable = true; - - if (is_movable && (marketplacelistings_id == cat_id)) - { - is_movable = false; - tooltip_msg = LLTrans::getString("TooltipOutboxCannotMoveRoot"); - } - if (is_movable && move_is_from_marketplacelistings && LLMarketplaceData::instance().getActivationState(cat_id)) - { - // If the incoming folder is listed and active (and is therefore either the listing or the version folder), - // then moving is *not* allowed - is_movable = false; - tooltip_msg = LLTrans::getString("TooltipOutboxDragActive"); - } - if (is_movable && (mUUID == cat_id)) - { - is_movable = false; - tooltip_msg = LLTrans::getString("TooltipDragOntoSelf"); - } - if (is_movable && (model->isObjectDescendentOf(mUUID, cat_id))) - { - is_movable = false; - tooltip_msg = LLTrans::getString("TooltipDragOntoOwnChild"); - } - if (is_movable && LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) - { - is_movable = false; - // tooltip? - } - - U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); - if (is_movable && move_is_into_outfit) - { - if (mUUID == my_outifts_id) - { - if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings) - { - tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory"); - is_movable = false; - } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) - { - is_movable = true; - } - else - { - tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); - is_movable = false; - } - } - else if(getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE) - { - is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)); - } - else - { - is_movable = false; - } - } - if(is_movable && move_is_into_current_outfit && is_link) - { - is_movable = false; - } - if (is_movable && move_is_into_lost_and_found) - { - is_movable = false; - } - if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE))) - { - is_movable = false; - // tooltip? - } - if (is_movable && (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)) - { - // One cannot move a folder into a stock folder - is_movable = false; - // tooltip? - } - - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - if (is_movable) - { - model->collectDescendents(cat_id, descendent_categories, descendent_items, false); - for (S32 i=0; i < descendent_categories.size(); ++i) - { - 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 - && move_is_into_current_outfit - && descendent_items.size() > max_items_to_wear) - { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(cat_id, - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); - - if (items.size() > max_items_to_wear) - { - // Can't move 'large' folders into current outfit: MAINT-4086 - is_movable = false; - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", max_items_to_wear); - tooltip_msg = LLTrans::getString("TooltipTooManyWearables",args); - } - } - if (is_movable && move_is_into_trash) - { - for (S32 i=0; i < descendent_items.size(); ++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. - } - } - } - if (is_movable && move_is_into_landmarks) - { - for (S32 i=0; i < descendent_items.size(); ++i) - { - LLViewerInventoryItem* item = descendent_items[i]; - - // Don't move anything except landmarks and categories into Landmarks folder. - // We use getType() instead of getActua;Type() to allow links to landmarks and folders. - if (LLAssetType::AT_LANDMARK != item->getType() && LLAssetType::AT_CATEGORY != item->getType()) - { - is_movable = false; - break; // It's generally movable, but not into Landmarks. - } - } - } - - if (is_movable && move_is_into_marketplacelistings) - { - const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); - LLViewerInventoryCategory * dest_folder = getCategory(); - S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount()); - is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size); - } - - if (is_movable && !move_is_into_landmarks) - { - LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(false); - is_movable = active_panel != NULL; - - // For a folder to pass the filter all its descendants are required to pass. - // We make this exception to allow reordering folders within an inventory panel, - // which has a filter applied, like Recent tab for example. - // There may be folders which are displayed because some of their descendants pass - // the filter, but other don't, and thus remain hidden. Without this check, - // such folders would not be allowed to be moved within a panel. - if (destination_panel == active_panel) - { - is_movable = true; - } - else - { - LLFolderView* active_folder_view = NULL; - - if (is_movable) - { - active_folder_view = active_panel->getRootFolder(); - is_movable = active_folder_view != NULL; - } - - if (is_movable && use_filter) - { - // Check whether the folder being dragged from active inventory panel - // passes the filter of the destination panel. - is_movable = check_category(model, cat_id, active_panel, filter); - } - } - } - // - //-------------------------------------------------------------------------------- - - accept = is_movable; - - if (accept && drop) - { - // Dropping in or out of marketplace needs (sometimes) confirmation - if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings)) - { - if (move_is_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(cat_id) || - LLMarketplaceData::instance().isListedAndActive(cat_id))) - { - if (LLMarketplaceData::instance().isListed(cat_id) || LLMarketplaceData::instance().isVersionFolder(cat_id)) - { - // Move the active version folder or listing folder itself outside marketplace listings will unlist the listing so ask that question specifically - LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); - } - else - { - // Any other case will simply modify but not unlist an active listed listing - LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); - } - return true; - } - if (move_is_from_marketplacelistings && LLMarketplaceData::instance().isVersionFolder(cat_id)) - { - // Moving the version folder from its location will deactivate it. Ask confirmation. - LLNotificationsUtil::add("ConfirmMerchantClearVersion", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); - return true; - } - if (move_is_into_marketplacelistings && LLMarketplaceData::instance().isInActiveFolder(mUUID)) - { - // Moving something in an active listed listing will modify it. Ask confirmation. - LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); - return true; - } - if (move_is_from_marketplacelistings && LLMarketplaceData::instance().isListed(cat_id)) - { - // Moving a whole listing folder will result in archival of SLM data. Ask confirmation. - LLNotificationsUtil::add("ConfirmListingCutOrDelete", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); - return true; - } - if (move_is_into_marketplacelistings && !move_is_from_marketplacelistings) - { - LLNotificationsUtil::add("ConfirmMerchantMoveInventory", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); - return true; - } - } - // Look for any gestures and deactivate them - if (move_is_into_trash) - { - for (S32 i=0; i < descendent_items.size(); i++) - { - LLInventoryItem* item = descendent_items[i]; - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item->getUUID())) - { - LLGestureMgr::instance().deactivateGesture(item->getUUID()); - } - } - } - - if (mUUID == my_outifts_id) - { - // Category can contains objects, - // create a new folder and populate it with links to original objects - dropToMyOutfits(inv_cat, cb); - } - // if target is current outfit folder we use link - else if (move_is_into_current_outfit && - (inv_cat->getPreferredType() == LLFolderType::FT_NONE || - inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) - { - // traverse category and add all contents to currently worn. - bool append = true; - LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append); - if (cb) cb->fire(inv_cat->getUUID()); - } - else if (move_is_into_marketplacelistings) - { - move_folder_to_marketplacelistings(inv_cat, mUUID); - if (cb) cb->fire(inv_cat->getUUID()); - } - else - { - if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX))) - { - set_dad_inbox_object(cat_id); - } - - // Reparent the folder and restamp children if it's moving - // into trash. - LLInvFVBridge::changeCategoryParent( - model, - (LLViewerInventoryCategory*)inv_cat, - mUUID, - move_is_into_trash); - if (cb) cb->fire(inv_cat->getUUID()); - } - if (move_is_from_marketplacelistings) - { - // If we are moving a folder at the listing folder level (i.e. its parent is the marketplace listings folder) - if (from_folder_uuid == marketplacelistings_id) - { - // Clear the folder from the marketplace in case it is a listing folder - if (LLMarketplaceData::instance().isListed(cat_id)) - { - LLMarketplaceData::instance().clearListing(cat_id); - } - } - else - { - // If we move from within an active (listed) listing, checks that it's still valid, if not, unlist - LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid); - if (version_folder_id.notNull()) - { - LLMarketplaceValidator::getInstance()->validateMarketplaceListings( - version_folder_id, - [version_folder_id](bool result) - { - if (!result) - { - LLMarketplaceData::instance().activateListing(version_folder_id, false); - } - } - ); - } - // In all cases, update the listing we moved from so suffix are updated - update_marketplace_category(from_folder_uuid); - if (cb) cb->fire(inv_cat->getUUID()); - } - } - } - } - else if (LLToolDragAndDrop::SOURCE_WORLD == source) - { - if (move_is_into_marketplacelistings) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - accept = false; - } - else - { - // Todo: fix me. moving from task inventory doesn't have a completion callback, - // yet making a copy creates new item id so this doesn't work right - std::function<void(S32, void*, const LLMoveInv*)> callback = [cb](S32, void*, const LLMoveInv* move_inv) mutable - { - two_uuids_list_t::const_iterator move_it; - for (move_it = move_inv->mMoveList.begin(); - move_it != move_inv->mMoveList.end(); - ++move_it) - { - if (cb) - { - cb->fire(move_it->second); - } - } - }; - accept = move_inv_category_world_to_agent(cat_id, mUUID, drop, callback, NULL, filter); - } - } - else if (LLToolDragAndDrop::SOURCE_LIBRARY == source) - { - if (move_is_into_marketplacelistings) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - accept = false; - } - else - { - // Accept folders that contain complete outfits. - accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id); - } - - if (accept && drop) - { - LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, true, false); - } - } - - return accept; -} - -void warn_move_inventory(LLViewerObject* object, std::shared_ptr<LLMoveInv> move_inv) -{ - const char* dialog = NULL; - if (object->flagScripted()) - { - dialog = "MoveInventoryFromScriptedObject"; - } - else - { - dialog = "MoveInventoryFromObject"; - } - - static LLNotificationPtr notification_ptr; - static std::shared_ptr<LLMoveInv> inv_ptr; - - // Notification blocks user from interacting with inventories so everything that comes after first message - // is part of this message - don'r show it again - // Note: workaround for MAINT-5495 untill proper refactoring and warning system for Drag&Drop can be made. - if (notification_ptr == NULL - || !notification_ptr->isActive() - || LLNotificationsUtil::find(notification_ptr->getID()) == NULL - || inv_ptr->mCategoryID != move_inv->mCategoryID - || inv_ptr->mObjectID != move_inv->mObjectID) - { - notification_ptr = LLNotificationsUtil::add(dialog, LLSD(), LLSD(), boost::bind(move_task_inventory_callback, _1, _2, move_inv)); - inv_ptr = move_inv; - } - else - { - // Notification is alive and not responded, operating inv_ptr should be safe so attach new data - two_uuids_list_t::iterator move_it; - for (move_it = move_inv->mMoveList.begin(); - move_it != move_inv->mMoveList.end(); - ++move_it) - { - inv_ptr->mMoveList.push_back(*move_it); - } - move_inv.reset(); - } -} - -// Move/copy all inventory items from the Contents folder of an in-world -// object to the agent's inventory, inside a given category. -bool move_inv_category_world_to_agent(const LLUUID& object_id, - const LLUUID& category_id, - bool drop, - std::function<void(S32, void*, const LLMoveInv*)> callback, - void* user_data, - LLInventoryFilter* filter) -{ - // Make sure the object exists. If we allowed dragging from - // anonymous objects, it would be possible to bypass - // permissions. - // content category has same ID as object itself - LLViewerObject* object = gObjectList.findObject(object_id); - if(!object) - { - LL_INFOS() << "Object not found for drop." << LL_ENDL; - return false; - } - - // this folder is coming from an object, as there is only one folder in an object, the root, - // we need to collect the entire contents and handle them as a group - LLInventoryObject::object_list_t inventory_objects; - object->getInventoryContents(inventory_objects); - - if (inventory_objects.empty()) - { - LL_INFOS() << "Object contents not found for drop." << LL_ENDL; - return false; - } - - bool accept = false; - bool is_move = false; - bool use_filter = false; - if (filter) - { - U64 filter_types = filter->getFilterTypes(); - use_filter = filter_types && (filter_types&LLInventoryFilter::FILTERTYPE_DATE || (filter_types&LLInventoryFilter::FILTERTYPE_OBJECT)==0); - } - - // coming from a task. Need to figure out if the person can - // move/copy this item. - LLInventoryObject::object_list_t::iterator it = inventory_objects.begin(); - LLInventoryObject::object_list_t::iterator end = inventory_objects.end(); - for ( ; it != end; ++it) - { - LLInventoryItem* item = dynamic_cast<LLInventoryItem*>(it->get()); - if (!item) - { - LL_WARNS() << "Invalid inventory item for drop" << LL_ENDL; - continue; - } - - // coming from a task. Need to figure out if the person can - // move/copy this item. - LLPermissions perm(item->getPermissions()); - if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) - && perm.allowTransferTo(gAgent.getID()))) -// || gAgent.isGodlike()) - { - accept = true; - } - else if(object->permYouOwner()) - { - // If the object cannot be copied, but the object the - // inventory is owned by the agent, then the item can be - // moved from the task to agent inventory. - is_move = true; - accept = true; - } - - if (accept && use_filter) - { - accept = filter->check(item); - } - - if (!accept) - { - break; - } - } - - if(drop && accept) - { - it = inventory_objects.begin(); - std::shared_ptr<LLMoveInv> move_inv(new LLMoveInv); - move_inv->mObjectID = object_id; - move_inv->mCategoryID = category_id; - move_inv->mCallback = callback; - move_inv->mUserData = user_data; - - for ( ; it != end; ++it) - { - two_uuids_t two(category_id, (*it)->getUUID()); - move_inv->mMoveList.push_back(two); - } - - if(is_move) - { - // Callback called from within here. - warn_move_inventory(object, move_inv); - } - else - { - LLNotification::Params params("MoveInventoryFromObject"); - params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); - LLNotifications::instance().forceResponse(params, 0); - } - } - return accept; -} - -void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) -{ - // Bail out immediately if no descendents - if( mComplete.empty() ) - { - LL_WARNS() << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << LL_ENDL; - if (clear_observer) - { - gInventory.removeObserver(this); - delete this; - } - return; - } - - // Copy the list of complete fetched folders while "this" is still valid - uuid_vec_t completed_folder = mComplete; - - // Clean up, and remove this as an observer now since recursive calls - // could notify observers and throw us into an infinite loop. - if (clear_observer) - { - gInventory.removeObserver(this); - delete this; - } - - for (uuid_vec_t::iterator current_folder = completed_folder.begin(); current_folder != completed_folder.end(); ++current_folder) - { - // Get the information on the fetched folder items and subfolders and fetch those - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(*current_folder, cat_array, item_array); - - S32 item_count(0); - if( item_array ) - { - item_count = item_array->size(); - } - - S32 cat_count(0); - if( cat_array ) - { - cat_count = cat_array->size(); - } - - // Move to next if current folder empty - if ((item_count == 0) && (cat_count == 0)) - { - continue; - } - - uuid_vec_t ids; - LLRightClickInventoryFetchObserver* outfit = NULL; - LLRightClickInventoryFetchDescendentsObserver* categories = NULL; - - // Fetch the items - if (item_count) - { - for (S32 i = 0; i < item_count; ++i) - { - ids.push_back(item_array->at(i)->getUUID()); - } - outfit = new LLRightClickInventoryFetchObserver(ids); - } - // Fetch the subfolders - if (cat_count) - { - for (S32 i = 0; i < cat_count; ++i) - { - ids.push_back(cat_array->at(i)->getUUID()); - } - categories = new LLRightClickInventoryFetchDescendentsObserver(ids); - } - - // Perform the item fetch - if (outfit) - { - outfit->startFetch(); - outfit->execute(); // Not interested in waiting and this will be right 99% of the time. - delete outfit; -//Uncomment the following code for laggy Inventory UI. - /* - if (outfit->isFinished()) - { - // everything is already here - call done. - outfit->execute(); - delete outfit; - } - else - { - // it's all on its way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - } - */ - } - // Perform the subfolders fetch : this is where we truly recurse down the folder hierarchy - if (categories) - { - categories->startFetch(); - if (categories->isFinished()) - { - // everything is already here - call done. - categories->execute(); - delete categories; - } - else - { - // it's all on its way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(categories); - } - } - } -} - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryWearObserver -// -// Observer for "copy and wear" operation to support knowing -// when the all of the contents have been added to inventory. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryCopyAndWearObserver : public LLInventoryObserver -{ -public: - LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count, bool folder_added=false, bool replace=false) : - mCatID(cat_id), mContentsCount(count), mFolderAdded(folder_added), mReplace(replace){} - virtual ~LLInventoryCopyAndWearObserver() {} - virtual void changed(U32 mask); - -protected: - LLUUID mCatID; - int mContentsCount; - bool mFolderAdded; - bool mReplace; -}; - - - -void LLInventoryCopyAndWearObserver::changed(U32 mask) -{ - if((mask & (LLInventoryObserver::ADD)) != 0) - { - if (!mFolderAdded) - { - const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); - - std::set<LLUUID>::const_iterator id_it = changed_items.begin(); - std::set<LLUUID>::const_iterator id_end = changed_items.end(); - for (;id_it != id_end; ++id_it) - { - if ((*id_it) == mCatID) - { - mFolderAdded = true; - break; - } - } - } - - if (mFolderAdded) - { - LLViewerInventoryCategory* category = gInventory.getCategory(mCatID); - if (NULL == category) - { - LL_WARNS() << "gInventory.getCategory(" << mCatID - << ") was NULL" << LL_ENDL; - } - else - { - if (category->getDescendentCount() == - mContentsCount) - { - gInventory.removeObserver(this); - LLAppearanceMgr::instance().wearInventoryCategory(category, false, !mReplace); - delete this; - } - } - } - - } -} - - - -void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("open" == action) - { - LLFolderViewFolder *f = dynamic_cast<LLFolderViewFolder *>(mInventoryPanel.get()->getItemByID(mUUID)); - if (f) - { - f->toggleOpen(); - } - - return; - } - else if ("thumbnail" == action) - { - LLSD data(mUUID); - LLFloaterReg::showInstance("change_item_thumbnail", data); - return; - } - else if ("paste" == action) - { - pasteFromClipboard(); - return; - } - else if ("paste_link" == action) - { - pasteLinkFromClipboard(); - return; - } - else if ("properties" == action) - { - showProperties(); - return; - } - else if ("replaceoutfit" == action) - { - modifyOutfit(false); - return; - } - else if ("addtooutfit" == action) - { - modifyOutfit(true); - return; - } - else if ("show_in_main_panel" == action) - { - LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true); - return; - } - else if ("cut" == action) - { - cutToClipboard(); - return; - } - else if ("copy" == action) - { - copyToClipboard(); - return; - } - else if ("removefromoutfit" == action) - { - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLViewerInventoryCategory* cat = getCategory(); - if(!cat) return; - - LLAppearanceMgr::instance().takeOffOutfit( cat->getLinkedUUID() ); - return; - } - else if ("copyoutfittoclipboard" == action) - { - copyOutfitToClipboard(); - } - else if ("purge" == action) - { - purgeItem(model, mUUID); - return; - } - else if ("restore" == action) - { - restoreItem(); - return; - } - else if ("marketplace_list" == action) - { - if (depth_nesting_in_marketplace(mUUID) == 1) - { - LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID); - mMessage = ""; - - LLMarketplaceValidator::getInstance()->validateMarketplaceListings( - version_folder_id, - [this](bool result) - { - // todo: might need to ensure bridge/mUUID exists or this will cause crashes - if (!result) - { - LLSD subs; - subs["[ERROR_CODE]"] = mMessage; - LLNotificationsUtil::add("MerchantListingFailed", subs); - } - else - { - LLMarketplaceData::instance().activateListing(mUUID, true); - } - }, - boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3) - ); - } - return; - } - else if ("marketplace_activate" == action) - { - if (depth_nesting_in_marketplace(mUUID) == 2) - { - mMessage = ""; - - LLMarketplaceValidator::getInstance()->validateMarketplaceListings( - mUUID, - [this](bool result) - { - if (!result) - { - LLSD subs; - subs["[ERROR_CODE]"] = mMessage; - LLNotificationsUtil::add("MerchantFolderActivationFailed", subs); - } - else - { - LLInventoryCategory* category = gInventory.getCategory(mUUID); - LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID); - } - }, - boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3), - false, - 2); - } - return; - } - else if ("marketplace_unlist" == action) - { - if (depth_nesting_in_marketplace(mUUID) == 1) - { - LLMarketplaceData::instance().activateListing(mUUID,false,1); - } - return; - } - else if ("marketplace_deactivate" == action) - { - if (depth_nesting_in_marketplace(mUUID) == 2) - { - LLInventoryCategory* category = gInventory.getCategory(mUUID); - LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), LLUUID::null, 1); - } - return; - } - else if ("marketplace_create_listing" == action) - { - mMessage = ""; - - // first run vithout fix_hierarchy, second run with fix_hierarchy - LLMarketplaceValidator::getInstance()->validateMarketplaceListings( - mUUID, - [this](bool result) - { - if (!result) - { - mMessage = ""; - - LLMarketplaceValidator::getInstance()->validateMarketplaceListings( - mUUID, - [this](bool result) - { - if (result) - { - LLNotificationsUtil::add("MerchantForceValidateListing"); - LLMarketplaceData::instance().createListing(mUUID); - } - else - { - LLSD subs; - subs["[ERROR_CODE]"] = mMessage; - LLNotificationsUtil::add("MerchantListingFailed", subs); - } - }, - boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3), - true); - } - else - { - LLMarketplaceData::instance().createListing(mUUID); - } - }, - boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3), - false); - - return; - } - else if ("marketplace_disassociate_listing" == action) - { - LLMarketplaceData::instance().clearListing(mUUID); - return; - } - else if ("marketplace_get_listing" == action) - { - // This is used only to exercise the SLM API but won't be shown to end users - LLMarketplaceData::instance().getListing(mUUID); - return; - } - else if ("marketplace_associate_listing" == action) - { - LLFloaterAssociateListing::show(mUUID); - return; - } - else if ("marketplace_check_listing" == action) - { - LLSD data(mUUID); - LLFloaterReg::showInstance("marketplace_validation", data); - return; - } - else if ("marketplace_edit_listing" == action) - { - std::string url = LLMarketplaceData::instance().getListingURL(mUUID); - if (!url.empty()) - { - LLUrlAction::openURL(url); - } - return; - } -#ifndef LL_RELEASE_FOR_DOWNLOAD - else if ("delete_system_folder" == action) - { - removeSystemFolder(); - } -#endif - else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action)) - { - LLInventoryCategory * cat = gInventory.getCategory(mUUID); - if (!cat) return; - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action))); - } -} - -void LLFolderBridge::gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level) -{ - if (log_level >= LLError::LEVEL_ERROR) - { - if (!mMessage.empty()) - { - // Currently, we do not gather all messages as it creates very long alerts - // Users can get to the whole list of errors on a listing using the "Check for Errors" audit button or "Check listing" right click menu - //mMessage += "\n"; - return; - } - // Take the leading spaces out... - std::string::size_type start = message.find_first_not_of(" "); - // Append the message - mMessage += message.substr(start, message.length() - start); - } -} - -void LLFolderBridge::copyOutfitToClipboard() -{ - std::string text; - - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(mUUID, cat_array, item_array); - - S32 item_count(0); - if( item_array ) - { - item_count = item_array->size(); - } - - if (item_count) - { - for (S32 i = 0; i < item_count;) - { - LLSD uuid =item_array->at(i)->getUUID(); - LLViewerInventoryItem* item = gInventory.getItem(uuid); - - i++; - if (item != NULL) - { - // Append a newline to all but the last line - text += i != item_count ? item->getName() + "\n" : item->getName(); - } - } - } - - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(text),0,text.size()); -} - -void LLFolderBridge::openItem() -{ - LL_DEBUGS() << "LLFolderBridge::openItem()" << LL_ENDL; - - LLInventoryPanel* panel = mInventoryPanel.get(); - if (!panel) - { - return; - } - LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return; - } - if (mUUID.isNull()) - { - return; - } - panel->onFolderOpening(mUUID); - bool fetching_inventory = model->fetchDescendentsOf(mUUID); - // Only change folder type if we have the folder contents. - if (!fetching_inventory) - { - // Disabling this for now, it's causing crash when new items are added to folders - // since folder type may change before new item item has finished processing. - // determineFolderType(); - } -} - -void LLFolderBridge::closeItem() -{ - determineFolderType(); -} - -void LLFolderBridge::determineFolderType() -{ - if (isUpToDate()) - { - LLInventoryModel* model = getInventoryModel(); - LLViewerInventoryCategory* category = model->getCategory(mUUID); - if (category) - { - category->determineFolderType(); - } - } -} - -bool LLFolderBridge::isItemRenameable() const -{ - return get_is_category_renameable(getInventoryModel(), mUUID); -} - -void LLFolderBridge::restoreItem() -{ - LLViewerInventoryCategory* cat; - cat = (LLViewerInventoryCategory*)getCategory(); - if(cat) - { - LLInventoryModel* model = getInventoryModel(); - const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType())); - // do not restamp children on restore - LLInvFVBridge::changeCategoryParent(model, cat, new_parent, false); - } -} - -LLFolderType::EType LLFolderBridge::getPreferredType() const -{ - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat) - { - preferred_type = cat->getPreferredType(); - } - - return preferred_type; -} - -// Icons for folders are based on the preferred type -LLUIImagePtr LLFolderBridge::getIcon() const -{ - return getFolderIcon(false); -} - -LLUIImagePtr LLFolderBridge::getIconOpen() const -{ - return getFolderIcon(true); -} - -LLUIImagePtr LLFolderBridge::getFolderIcon(bool is_open) const -{ - LLFolderType::EType preferred_type = getPreferredType(); - return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, is_open)); -} - -// static : use by LLLinkFolderBridge to get the closed type icons -LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) -{ - return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, false)); -} - -LLUIImagePtr LLFolderBridge::getIconOverlay() const -{ - if (getInventoryObject() && getInventoryObject()->getIsLinkType()) - { - return LLUI::getUIImage("Inv_Link"); - } - return NULL; -} - -bool LLFolderBridge::renameItem(const std::string& new_name) -{ - - LLScrollOnRenameObserver *observer = new LLScrollOnRenameObserver(mUUID, mRoot); - gInventory.addObserver(observer); - - rename_category(getInventoryModel(), mUUID, new_name); - - // return false because we either notified observers (& therefore - // rebuilt) or we didn't update. - return false; -} - -bool LLFolderBridge::removeItem() -{ - if(!isItemRemovable()) - { - return false; - } - const LLViewerInventoryCategory *cat = getCategory(); - - LLSD payload; - LLSD args; - args["FOLDERNAME"] = cat->getName(); - - LLNotification::Params params("ConfirmDeleteProtectedCategory"); - params.payload(payload).substitutions(args).functor.function(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2)); - LLNotifications::instance().forceResponse(params, 0); - return true; -} - - -bool LLFolderBridge::removeSystemFolder() -{ - const LLViewerInventoryCategory *cat = getCategory(); - if (!LLFolderType::lookupIsProtectedType(cat->getPreferredType())) - { - return false; - } - - LLSD payload; - LLSD args; - args["FOLDERNAME"] = cat->getName(); - - LLNotification::Params params("ConfirmDeleteProtectedCategory"); - params.payload(payload).substitutions(args).functor.function(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2)); - { - LLNotifications::instance().add(params); - } - return true; -} - -bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - // if they choose delete, do it. Otherwise, don't do anything - if(option == 0) - { - // move it to the trash - LLPreview::hide(mUUID); - getInventoryModel()->removeCategory(mUUID); - return true; - } - return false; -} - -//Recursively update the folder's creation date -void LLFolderBridge::updateHierarchyCreationDate(time_t date) -{ - if(getCreationDate() < date) - { - setCreationDate(date); - if(mParent) - { - static_cast<LLFolderBridge *>(mParent)->updateHierarchyCreationDate(date); - } - } -} - -void LLFolderBridge::pasteFromClipboard() -{ - LLInventoryModel* model = getInventoryModel(); - if (model && isClipboardPasteable()) - { - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - const bool paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - - bool cut_from_marketplacelistings = false; - if (LLClipboard::instance().isCutMode()) - { - //Items are not removed from folder on "cut", so we need update listing folder on "paste" operation - std::vector<LLUUID> objects; - LLClipboard::instance().pasteFromClipboard(objects); - for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) - { - const LLUUID& item_id = (*iter); - if(gInventory.isObjectDescendentOf(item_id, marketplacelistings_id) && (LLMarketplaceData::instance().isInActiveFolder(item_id) || - LLMarketplaceData::instance().isListedAndActive(item_id))) - { - cut_from_marketplacelistings = true; - break; - } - } - } - if (cut_from_marketplacelistings || (paste_into_marketplacelistings && !LLMarketplaceData::instance().isListed(mUUID) && LLMarketplaceData::instance().isInActiveFolder(mUUID))) - { - // Prompt the user if pasting in a marketplace active version listing (note that pasting right under the listing folder root doesn't need a prompt) - LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_pasteFromClipboard, this, _1, _2)); - } - else - { - // Otherwise just do the paste - perform_pasteFromClipboard(); - } - } -} - -// Callback for pasteFromClipboard if DAMA required... -void LLFolderBridge::callback_pasteFromClipboard(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - std::vector<LLUUID> objects; - std::set<LLUUID> parent_folders; - LLClipboard::instance().pasteFromClipboard(objects); - for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) - { - const LLInventoryObject* obj = gInventory.getObject(*iter); - parent_folders.insert(obj->getParentUUID()); - } - perform_pasteFromClipboard(); - for (std::set<LLUUID>::const_iterator iter = parent_folders.begin(); iter != parent_folders.end(); ++iter) - { - gInventory.addChangedMask(LLInventoryObserver::STRUCTURE, *iter); - } - - } -} - -void LLFolderBridge::perform_pasteFromClipboard() -{ - LLInventoryModel* model = getInventoryModel(); - if (model && isClipboardPasteable()) - { - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - - const bool move_is_into_current_outfit = (mUUID == current_outfit_id); - const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); - const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - const bool move_is_into_favorites = (mUUID == favorites_id); - const bool move_is_into_lost_and_found = model->isObjectDescendentOf(mUUID, lost_and_found_id); - - std::vector<LLUUID> objects; - LLClipboard::instance().pasteFromClipboard(objects); - - LLPointer<LLInventoryCallback> cb = NULL; - LLInventoryPanel* panel = mInventoryPanel.get(); - if (panel->getRootFolder()->isSingleFolderMode() && panel->getRootFolderID() == mUUID) - { - cb = new LLPasteIntoFolderCallback(mInventoryPanel); - } - - LLViewerInventoryCategory * dest_folder = getCategory(); - if (move_is_into_marketplacelistings) - { - std::string error_msg; - const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); - int index = 0; - for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) - { - const LLUUID& item_id = (*iter); - LLInventoryItem *item = model->getItem(item_id); - LLInventoryCategory *cat = model->getCategory(item_id); - - if (item && !can_move_item_to_marketplace(master_folder, dest_folder, item, error_msg, objects.size() - index, true)) - { - break; - } - if (cat && !can_move_folder_to_marketplace(master_folder, dest_folder, cat, error_msg, objects.size() - index, true, true)) - { - break; - } - ++index; - } - if (!error_msg.empty()) - { - LLSD subs; - subs["[ERROR_CODE]"] = error_msg; - LLNotificationsUtil::add("MerchantPasteFailed", subs); - return; - } - } - else - { - // Check that all items can be moved into that folder : for the moment, only stock folder mismatch is checked - for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) - { - const LLUUID& item_id = (*iter); - LLInventoryItem *item = model->getItem(item_id); - LLInventoryCategory *cat = model->getCategory(item_id); - - if ((item && !dest_folder->acceptItem(item)) || (cat && (dest_folder->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK))) - { - std::string error_msg = LLTrans::getString("TooltipOutboxMixedStock"); - LLSD subs; - subs["[ERROR_CODE]"] = error_msg; - LLNotificationsUtil::add("StockPasteFailed", subs); - return; - } - } - } - - const LLUUID parent_id(mUUID); - - for (std::vector<LLUUID>::const_iterator iter = objects.begin(); - iter != objects.end(); - ++iter) - { - const LLUUID& item_id = (*iter); - - LLInventoryItem *item = model->getItem(item_id); - LLInventoryObject *obj = model->getObject(item_id); - if (obj) - { - - if (move_is_into_lost_and_found) - { - if (LLAssetType::AT_CATEGORY == obj->getType()) - { - return; - } - } - if (move_is_into_outfit) - { - if (!move_is_into_my_outfits && item && can_move_to_outfit(item, move_is_into_current_outfit)) - { - dropToOutfit(item, move_is_into_current_outfit, cb); - } - else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType()) - { - LLInventoryCategory* cat = model->getCategory(item_id); - U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); - if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear)) - { - dropToMyOutfits(cat, cb); - } - else - { - LLNotificationsUtil::add("MyOutfitsPasteFailed"); - } - } - else - { - LLNotificationsUtil::add("MyOutfitsPasteFailed"); - } - } - else if (move_is_into_current_outfit) - { - if (item && can_move_to_outfit(item, move_is_into_current_outfit)) - { - dropToOutfit(item, move_is_into_current_outfit, cb); - } - else - { - LLNotificationsUtil::add("MyOutfitsPasteFailed"); - } - } - else if (move_is_into_favorites) - { - if (item && can_move_to_landmarks(item)) - { - if (LLClipboard::instance().isCutMode()) - { - LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item); - llassert(viitem); - if (viitem) - { - //changeItemParent() implicity calls dirtyFilter - changeItemParent(model, viitem, parent_id, false); - if (cb) cb->fire(item_id); - } - } - else - { - dropToFavorites(item, cb); - } - } - } - else if (LLClipboard::instance().isCutMode()) - { - // Do a move to "paste" a "cut" - // move_inventory_item() is not enough, as we have to update inventory locally too - if (LLAssetType::AT_CATEGORY == obj->getType()) - { - LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); - llassert(vicat); - if (vicat) - { - // Clear the cut folder from the marketplace if it is a listing folder - if (LLMarketplaceData::instance().isListed(item_id)) - { - LLMarketplaceData::instance().clearListing(item_id); - } - if (move_is_into_marketplacelistings) - { - move_folder_to_marketplacelistings(vicat, parent_id); - } - else - { - //changeCategoryParent() implicity calls dirtyFilter - changeCategoryParent(model, vicat, parent_id, false); - } - if (cb) cb->fire(item_id); - } - } - else - { - LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item); - llassert(viitem); - if (viitem) - { - if (move_is_into_marketplacelistings) - { - if (!move_item_to_marketplacelistings(viitem, parent_id)) - { - // Stop pasting into the marketplace as soon as we get an error - break; - } - } - else - { - //changeItemParent() implicity calls dirtyFilter - changeItemParent(model, viitem, parent_id, false); - } - if (cb) cb->fire(item_id); - } - } - } - else - { - // Do a "copy" to "paste" a regular copy clipboard - if (LLAssetType::AT_CATEGORY == obj->getType()) - { - LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); - llassert(vicat); - if (vicat) - { - if (move_is_into_marketplacelistings) - { - move_folder_to_marketplacelistings(vicat, parent_id, true); - } - else - { - copy_inventory_category(model, vicat, parent_id); - } - if (cb) cb->fire(item_id); - } - } - else - { - LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item); - llassert(viitem); - if (viitem) - { - if (move_is_into_marketplacelistings) - { - if (!move_item_to_marketplacelistings(viitem, parent_id, true)) - { - // Stop pasting into the marketplace as soon as we get an error - break; - } - if (cb) cb->fire(item_id); - } - else if (item->getIsLinkType()) - { - link_inventory_object(parent_id, - item_id, - cb); - } - else - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - parent_id, - std::string(), - cb); - } - } - } - } - } - } - // Change mode to paste for next paste - LLClipboard::instance().setCutMode(false); - } -} - -void LLFolderBridge::pasteLinkFromClipboard() -{ - LLInventoryModel* model = getInventoryModel(); - if(model) - { - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - - const bool move_is_into_current_outfit = (mUUID == current_outfit_id); - const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); - const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - - if (move_is_into_marketplacelistings) - { - // Notify user of failure somehow -- play error sound? modal dialog? - return; - } - - const LLUUID parent_id(mUUID); - - std::vector<LLUUID> objects; - LLClipboard::instance().pasteFromClipboard(objects); - - LLPointer<LLInventoryCallback> cb = NULL; - LLInventoryPanel* panel = mInventoryPanel.get(); - if (panel->getRootFolder()->isSingleFolderMode()) - { - cb = new LLPasteIntoFolderCallback(mInventoryPanel); - } - - for (std::vector<LLUUID>::const_iterator iter = objects.begin(); - iter != objects.end(); - ++iter) - { - const LLUUID &object_id = (*iter); - if (move_is_into_current_outfit || move_is_into_outfit) - { - LLInventoryItem *item = model->getItem(object_id); - if (item && can_move_to_outfit(item, move_is_into_current_outfit)) - { - dropToOutfit(item, move_is_into_current_outfit, cb); - } - } - else if (LLConstPointer<LLInventoryObject> obj = model->getObject(object_id)) - { - link_inventory_object(parent_id, obj, cb); - } - } - // Change mode to paste for next paste - LLClipboard::instance().setCutMode(false); - } -} - -void LLFolderBridge::staticFolderOptionsMenu() -{ - LLFolderBridge* selfp = sSelf.get(); - - if (selfp && selfp->mRoot) - { - selfp->mRoot->updateMenu(); - } -} - -bool LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) -{ - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - model->collectDescendentsIf(mUUID, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_type); - return !item_array.empty(); -} - -void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items) -{ - LLInventoryModel* model = getInventoryModel(); - llassert(model != NULL); - - const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - - if (outfits_id == mUUID) - { - items.push_back(std::string("New Outfit")); - } - - if (lost_and_found_id == mUUID) - { - // This is the lost+found folder. - items.push_back(std::string("Empty Lost And Found")); - - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(mUUID, cat_array, item_array); - // Enable Empty menu item only when there is something to act upon. - if (0 == cat_array->size() && 0 == item_array->size()) - { - disabled_items.push_back(std::string("Empty Lost And Found")); - } - - disabled_items.push_back(std::string("New Folder")); - disabled_items.push_back(std::string("upload_def")); - disabled_items.push_back(std::string("create_new")); - } - if (favorites == mUUID) - { - disabled_items.push_back(std::string("New Folder")); - } - if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - if (LLMarketplaceData::instance().isUpdating(mUUID)) - { - disabled_items.push_back(std::string("New Folder")); - disabled_items.push_back(std::string("Rename")); - disabled_items.push_back(std::string("Cut")); - disabled_items.push_back(std::string("Copy")); - disabled_items.push_back(std::string("Paste")); - disabled_items.push_back(std::string("Delete")); - } - } - if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) - { - disabled_items.push_back(std::string("New Folder")); - disabled_items.push_back(std::string("upload_def")); - disabled_items.push_back(std::string("create_new")); - } - if (marketplace_listings_id == mUUID) - { - disabled_items.push_back(std::string("New Folder")); - disabled_items.push_back(std::string("Rename")); - disabled_items.push_back(std::string("Cut")); - disabled_items.push_back(std::string("Delete")); - } - - if (isPanelActive("Favorite Items")) - { - disabled_items.push_back(std::string("Delete")); - } - if(trash_id == mUUID) - { - bool is_recent_panel = isPanelActive("Recent Items"); - - // This is the trash. - items.push_back(std::string("Empty Trash")); - - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(mUUID, cat_array, item_array); - LLViewerInventoryCategory *trash = getCategory(); - // Enable Empty menu item only when there is something to act upon. - // Also don't enable menu if folder isn't fully fetched - if ((0 == cat_array->size() && 0 == item_array->size()) - || is_recent_panel - || !trash - || trash->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN - || trash->getDescendentCount() == LLViewerInventoryCategory::VERSION_UNKNOWN - || gAgentAvatarp->hasAttachmentsInTrash()) - { - disabled_items.push_back(std::string("Empty Trash")); - } - - items.push_back(std::string("thumbnail")); - } - else if(isItemInTrash()) - { - // This is a folder in the trash. - items.clear(); // clear any items that used to exist - addTrashContextMenuOptions(items, disabled_items); - } - else if(isAgentInventory()) // do not allow creating in library - { - LLViewerInventoryCategory *cat = getCategory(); - // BAP removed protected check to re-enable standard ops in untyped folders. - // Not sure what the right thing is to do here. - if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) - { - if (!isInboxFolder() // don't allow creation in inbox - && outfits_id != mUUID) - { - // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. - if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) - { - items.push_back(std::string("New Folder")); - } - if (!isMarketplaceListingsFolder()) - { - items.push_back(std::string("upload_def")); - items.push_back(std::string("create_new")); - items.push_back(std::string("New Script")); - items.push_back(std::string("New Note")); - items.push_back(std::string("New Gesture")); - items.push_back(std::string("New Material")); - items.push_back(std::string("New Clothes")); - items.push_back(std::string("New Body Parts")); - items.push_back(std::string("New Settings")); - if (!LLEnvironment::instance().isInventoryEnabled()) - { - disabled_items.push_back("New Settings"); - } - } - } - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - // Want some but not all of the items from getClipboardEntries for outfits. - if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) - { - items.push_back(std::string("Rename")); - items.push_back(std::string("thumbnail")); - - addDeleteContextMenuOptions(items, disabled_items); - // EXT-4030: disallow deletion of currently worn outfit - const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); - if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory())) - { - disabled_items.push_back(std::string("Delete")); - } - } - } - - if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID) - { - items.push_back(std::string("Copy outfit list to clipboard")); - addOpenFolderMenuOptions(flags, items); - } - - //Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06 - mCallingCards = mWearables = false; - - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (checkFolderForContentsOfType(model, is_callingcard)) - { - mCallingCards=true; - } - - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) - { - mWearables=true; - } - } - else - { - // Mark wearables and allow copy from library - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - const LLInventoryCategory* category = model->getCategory(mUUID); - if (!category) return; - LLFolderType::EType type = category->getPreferredType(); - const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); - - LLFindWearables is_wearable; - LLIsType is_object(LLAssetType::AT_OBJECT); - LLIsType is_gesture(LLAssetType::AT_GESTURE); - - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture)) - { - mWearables = true; - } - - if (!is_system_folder) - { - items.push_back(std::string("Copy")); - if (!isItemCopyable()) - { - // For some reason there are items in library that can't be copied directly - disabled_items.push_back(std::string("Copy")); - } - } - } - - // Preemptively disable system folder removal if more than one item selected. - if ((flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Delete System Folder")); - } - - if (isAgentInventory() && !isMarketplaceListingsFolder()) - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - } - - - - // Add menu items that are dependent on the contents of the folder. - LLViewerInventoryCategory* category = (LLViewerInventoryCategory *) model->getCategory(mUUID); - if (category && (marketplace_listings_id != mUUID)) - { - uuid_vec_t folders; - folders.push_back(category->getUUID()); - - sSelf = getHandle(); - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders); - fetch->startFetch(); - if (fetch->isFinished()) - { - // Do not call execute() or done() here as if the folder is here, there's likely no point drilling down - // This saves lots of time as buildContextMenu() is called a lot - delete fetch; - buildContextMenuFolderOptions(flags, items, disabled_items); - } - 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); - } - } -} - -void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items) -{ - // Build folder specific options back up - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - - const LLInventoryCategory* category = model->getCategory(mUUID); - if(!category) return; - - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - if ((trash_id == mUUID) || isItemInTrash()) - { - addOpenFolderMenuOptions(flags, items); - return; - } - - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } - if (isMarketplaceListingsFolder()) 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_agent_inventory = isAgentInventory(); - - // Only enable calling-card related options for non-system folders. - if (!is_system_folder && is_agent_inventory && (mRoot != NULL)) - { - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard)) - { - items.push_back(std::string("Calling Card Separator")); - items.push_back(std::string("Conference Chat Folder")); - items.push_back(std::string("IM All Contacts In Folder")); - } - - if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren() && (type != LLFolderType::FT_OUTFIT)) - { - items.push_back(std::string("Ungroup folder items")); - } - } - else - { - disabled_items.push_back(std::string("New folder from selected")); - } - - //skip the rest options in single-folder mode - if (mRoot == NULL) - { - return; - } - - addOpenFolderMenuOptions(flags, items); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory) - { - items.push_back(std::string("Delete System Folder")); - } -#endif - - // wearables related functionality for folders. - //is_wearable - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - - if (mWearables || - checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) - { - // Only enable add/replace outfit for non-system folders. - if (!is_system_folder) - { - // Adding an outfit onto another (versus replacing) doesn't make sense. - if (type != LLFolderType::FT_OUTFIT) - { - items.push_back(std::string("Add To Outfit")); - if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) - { - disabled_items.push_back(std::string("Add To Outfit")); - } - } - - items.push_back(std::string("Replace Outfit")); - if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) - { - disabled_items.push_back(std::string("Replace Outfit")); - } - } - if (is_agent_inventory) - { - items.push_back(std::string("Folder Wearables Separator")); - // Note: If user tries to unwear "My Inventory", it's going to deactivate everything including gestures - // Might be safer to disable this for "My Inventory" - items.push_back(std::string("Remove From Outfit")); - if (type != LLFolderType::FT_ROOT_INVENTORY // Unless COF is empty, whih shouldn't be, warrantied to have worn items - && !LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) // expensive from root! - { - disabled_items.push_back(std::string("Remove From Outfit")); - } - } - items.push_back(std::string("Outfit Separator")); - - } -} - -// Flags unused -void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - sSelf.markDead(); - - // fetch contents of this folder, as context menu can depend on contents - // still, user would have to open context menu again to see the changes - gInventory.fetchDescendentsOf(getUUID()); - - - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - LL_DEBUGS() << "LLFolderBridge::buildContextMenu()" << LL_ENDL; - - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - - buildContextMenuOptions(flags, items, disabled_items); - hide_context_entries(menu, items, disabled_items); - - // Reposition the menu, in case we're adding items to an existing menu. - menu.needsArrange(); - menu.arrangeAndClear(); -} - -void LLFolderBridge::addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items) -{ - if ((flags & ITEM_IN_MULTI_SELECTION) == 0) - { - items.push_back(std::string("open_in_new_window")); - items.push_back(std::string("Open Folder Separator")); - items.push_back(std::string("Copy Separator")); - if(isPanelActive("comb_single_folder_inv")) - { - items.push_back(std::string("open_in_current_window")); - } - } -} - -bool LLFolderBridge::hasChildren() const -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return false; - LLInventoryModel::EHasChildren has_children; - has_children = gInventory.categoryHasChildren(mUUID); - return has_children != LLInventoryModel::CHILDREN_NO; -} - -bool LLFolderBridge::dragOrDrop(MASK mask, bool drop, - EDragAndDropType cargo_type, - void* cargo_data, - std::string& tooltip_msg) -{ - LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; - - static LLPointer<LLInventoryCallback> drop_cb = NULL; - LLInventoryPanel* panel = mInventoryPanel.get(); - LLToolDragAndDrop* drop_tool = LLToolDragAndDrop::getInstance(); - if (drop - && panel->getRootFolder()->isSingleFolderMode() - && panel->getRootFolderID() == mUUID - && drop_tool->getCargoIndex() == 0) - { - drop_cb = new LLPasteIntoFolderCallback(mInventoryPanel); - } - - - //LL_INFOS() << "LLFolderBridge::dragOrDrop()" << LL_ENDL; - bool accept = false; - switch(cargo_type) - { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_CALLINGCARD: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_CLOTHING: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - case DAD_MESH: - case DAD_SETTINGS: - case DAD_MATERIAL: - accept = dragItemIntoFolder(inv_item, drop, tooltip_msg, true, drop_cb); - break; - case DAD_LINK: - // DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER. - // If we have an item of AT_LINK_FOLDER type we should process the linked - // category being dragged or dropped into folder. - if (inv_item && LLAssetType::AT_LINK_FOLDER == inv_item->getActualType()) - { - LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID()); - if (linked_category) - { - accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, true, true, drop_cb); - } - } - else - { - accept = dragItemIntoFolder(inv_item, drop, tooltip_msg, true, drop_cb); - } - break; - case DAD_CATEGORY: - if (LLFriendCardsManager::instance().isAnyFriendCategory(mUUID)) - { - accept = false; - } - else - { - accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop, tooltip_msg, false, true, drop_cb); - } - break; - case DAD_ROOT_CATEGORY: - case DAD_NONE: - break; - default: - LL_WARNS() << "Unhandled cargo type for drag&drop " << cargo_type << LL_ENDL; - break; - } - - if (!drop || drop_tool->getCargoIndex() + 1 == drop_tool->getCargoCount()) - { - drop_cb = NULL; - } - return accept; -} - -LLViewerInventoryCategory* LLFolderBridge::getCategory() const -{ - LLViewerInventoryCategory* cat = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - cat = (LLViewerInventoryCategory*)model->getCategory(mUUID); - } - return cat; -} - - -// static -void LLFolderBridge::pasteClipboard(void* user_data) -{ - LLFolderBridge* self = (LLFolderBridge*)user_data; - if(self) self->pasteFromClipboard(); -} - -void LLFolderBridge::createNewShirt(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHIRT); -} - -void LLFolderBridge::createNewPants(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_PANTS); -} - -void LLFolderBridge::createNewShoes(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHOES); -} - -void LLFolderBridge::createNewSocks(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SOCKS); -} - -void LLFolderBridge::createNewJacket(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_JACKET); -} - -void LLFolderBridge::createNewSkirt(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIRT); -} - -void LLFolderBridge::createNewGloves(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_GLOVES); -} - -void LLFolderBridge::createNewUndershirt(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERSHIRT); -} - -void LLFolderBridge::createNewUnderpants(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERPANTS); -} - -void LLFolderBridge::createNewShape(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHAPE); -} - -void LLFolderBridge::createNewSkin(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIN); -} - -void LLFolderBridge::createNewHair(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_HAIR); -} - -void LLFolderBridge::createNewEyes(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_EYES); -} - -EInventorySortGroup LLFolderBridge::getSortGroup() const -{ - LLFolderType::EType preferred_type = getPreferredType(); - - if (preferred_type == LLFolderType::FT_TRASH) - { - return SG_TRASH_FOLDER; - } - - if(LLFolderType::lookupIsProtectedType(preferred_type)) - { - return SG_SYSTEM_FOLDER; - } - - return SG_NORMAL_FOLDER; -} - - -// static -void LLFolderBridge::createWearable(LLFolderBridge* bridge, LLWearableType::EType type) -{ - if(!bridge) return; - LLUUID parent_id = bridge->getUUID(); - LLAgentWearables::createWearable(type, false, parent_id); -} - -void LLFolderBridge::modifyOutfit(bool append) -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLViewerInventoryCategory* cat = getCategory(); - if(!cat) return; - - // checking amount of items to wear - U32 max_items = gSavedSettings.getU32("WearFolderLimit"); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(cat->getUUID(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - not_worn); - - if (items.size() > max_items) - { - LLSD args; - args["AMOUNT"] = llformat("%d", max_items); - LLNotificationsUtil::add("TooManyWearables", args); - return; - } - - if (isAgentInventory()) - { - LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append); - } - else - { - // Library, we need to copy content first - LLAppearanceMgr::instance().wearInventoryCategory(cat, true, append); - } -} - - -// +=================================================+ -// | LLMarketplaceFolderBridge | -// +=================================================+ - -// LLMarketplaceFolderBridge is a specialized LLFolderBridge for use in Marketplace Inventory panels -LLMarketplaceFolderBridge::LLMarketplaceFolderBridge(LLInventoryPanel* inventory, - LLFolderView* root, - const LLUUID& uuid) : -LLFolderBridge(inventory, root, uuid) -{ - m_depth = depth_nesting_in_marketplace(mUUID); - m_stockCountCache = COMPUTE_STOCK_NOT_EVALUATED; -} - -LLUIImagePtr LLMarketplaceFolderBridge::getIcon() const -{ - return getMarketplaceFolderIcon(false); -} - -LLUIImagePtr LLMarketplaceFolderBridge::getIconOpen() const -{ - return getMarketplaceFolderIcon(true); -} - -LLUIImagePtr LLMarketplaceFolderBridge::getMarketplaceFolderIcon(bool is_open) const -{ - LLFolderType::EType preferred_type = getPreferredType(); - if (!LLMarketplaceData::instance().isUpdating(getUUID())) - { - // Skip computation (expensive) if we're waiting for updates. Use the old value in that case. - m_depth = depth_nesting_in_marketplace(mUUID); - } - if ((preferred_type == LLFolderType::FT_NONE) && (m_depth == 2)) - { - // We override the type when in the marketplace listings folder and only for version folder - preferred_type = LLFolderType::FT_MARKETPLACE_VERSION; - } - return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, is_open)); -} - -std::string LLMarketplaceFolderBridge::getLabelSuffix() const -{ - static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); - - if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) - { - return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); - } - - std::string suffix = ""; - // Listing folder case - if (LLMarketplaceData::instance().isListed(getUUID())) - { - suffix = llformat("%d",LLMarketplaceData::instance().getListingID(getUUID())); - if (suffix.empty()) - { - suffix = LLTrans::getString("MarketplaceNoID"); - } - suffix = " (" + suffix + ")"; - if (LLMarketplaceData::instance().getActivationState(getUUID())) - { - suffix += " (" + LLTrans::getString("MarketplaceLive") + ")"; - } - } - // Version folder case - else if (LLMarketplaceData::instance().isVersionFolder(getUUID())) - { - suffix += " (" + LLTrans::getString("MarketplaceActive") + ")"; - } - // Add stock amount - bool updating = LLMarketplaceData::instance().isUpdating(getUUID()); - if (!updating) - { - // Skip computation (expensive) if we're waiting for update anyway. Use the old value in that case. - m_stockCountCache = compute_stock_count(getUUID()); - } - if (m_stockCountCache == 0) - { - suffix += " (" + LLTrans::getString("MarketplaceNoStock") + ")"; - } - else if (m_stockCountCache != COMPUTE_STOCK_INFINITE) - { - if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) - { - suffix += " (" + LLTrans::getString("MarketplaceStock"); - } - else - { - suffix += " (" + LLTrans::getString("MarketplaceMax"); - } - if (m_stockCountCache == COMPUTE_STOCK_NOT_EVALUATED) - { - suffix += "=" + LLTrans::getString("MarketplaceUpdating") + ")"; - } - else - { - suffix += "=" + llformat("%d", m_stockCountCache) + ")"; - } - } - // Add updating suffix - if (updating) - { - suffix += " (" + LLTrans::getString("MarketplaceUpdating") + ")"; - } - return LLInvFVBridge::getLabelSuffix() + suffix; -} - -LLFontGL::StyleFlags LLMarketplaceFolderBridge::getLabelStyle() const -{ - return (LLMarketplaceData::instance().getActivationState(getUUID()) ? LLFontGL::BOLD : LLFontGL::NORMAL); -} - - - - -// helper stuff -bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, std::shared_ptr<LLMoveInv> move_inv) -{ - LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData; - LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if(option == 0 && object) - { - if (cat_and_wear && cat_and_wear->mWear) // && !cat_and_wear->mFolderResponded) - { - LLInventoryObject::object_list_t inventory_objects; - object->getInventoryContents(inventory_objects); - int contents_count = inventory_objects.size(); - LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count, cat_and_wear->mFolderResponded, - cat_and_wear->mReplace); - - gInventory.addObserver(inventoryObserver); - } - - two_uuids_list_t::iterator move_it; - for (move_it = move_inv->mMoveList.begin(); - move_it != move_inv->mMoveList.end(); - ++move_it) - { - object->moveInventory(move_it->first, move_it->second); - } - - // update the UI. - dialog_refresh_all(); - } - - if (move_inv->mCallback) - { - move_inv->mCallback(option, move_inv->mUserData, move_inv.get()); - } - - move_inv.reset(); //since notification will persist - return false; -} - -void drop_to_favorites_cb(const LLUUID& id, LLPointer<LLInventoryCallback> cb1, LLPointer<LLInventoryCallback> cb2) -{ - cb1->fire(id); - cb2->fire(id); -} - -void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb) -{ - // 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_fav = new AddFavoriteLandmarkCallback(); - LLInventoryPanel* panel = mInventoryPanel.get(); - LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; - LLFolderViewModelItemInventory* view_model = drag_over_item ? static_cast<LLFolderViewModelItemInventory*>(drag_over_item->getViewModelItem()) : NULL; - if (view_model) - { - cb_fav.get()->setTargetLandmarkId(view_model->getUUID()); - } - - LLPointer <LLInventoryCallback> callback = cb_fav; - if (cb) - { - callback = new LLBoostFuncInventoryCallback(boost::bind(drop_to_favorites_cb, _1, cb, cb_fav)); - } - - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - mUUID, - std::string(), - callback); -} - -void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit, LLPointer<LLInventoryCallback> cb) -{ - if((inv_item->getInventoryType() == LLInventoryType::IT_TEXTURE) || (inv_item->getInventoryType() == LLInventoryType::IT_SNAPSHOT)) - { - const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - if(mUUID != my_outifts_id) - { - // Legacy: prior to thumbnails images in outfits were used for outfit gallery. - LLNotificationsUtil::add("ThumbnailOutfitPhoto"); - } - return; - } - - // 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_object(mUUID, LLConstPointer<LLInventoryObject>(inv_item), cb); - } -} - -void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLInventoryCallback> cb) -{ - // make a folder in the My Outfits directory. - const LLUUID dest_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - - // Note: creation will take time, so passing folder id to callback is slightly unreliable, - // but so is collecting and passing descendants' ids - inventory_func_type func = boost::bind(&LLFolderBridge::outfitFolderCreatedCallback, this, inv_cat->getUUID(), _1, cb); - gInventory.createNewCategory(dest_id, - LLFolderType::FT_OUTFIT, - inv_cat->getName(), - func, - inv_cat->getThumbnailUUID()); -} - -void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb) -{ - LLInventoryModel::cat_array_t* categories; - LLInventoryModel::item_array_t* items; - getInventoryModel()->getDirectDescendentsOf(cat_source_id, categories, items); - - LLInventoryObject::const_object_list_t link_array; - - - LLInventoryModel::item_array_t::iterator iter = items->begin(); - LLInventoryModel::item_array_t::iterator end = items->end(); - while (iter!=end) - { - const LLViewerInventoryItem* item = (*iter); - // By this point everything is supposed to be filtered, - // but there was a delay to create folder so something could have changed - LLInventoryType::EType inv_type = item->getInventoryType(); - if ((inv_type == LLInventoryType::IT_WEARABLE) || - (inv_type == LLInventoryType::IT_GESTURE) || - (inv_type == LLInventoryType::IT_ATTACHMENT) || - (inv_type == LLInventoryType::IT_OBJECT) || - (inv_type == LLInventoryType::IT_SNAPSHOT) || - (inv_type == LLInventoryType::IT_TEXTURE)) - { - link_array.push_back(LLConstPointer<LLInventoryObject>(item)); - } - iter++; - } - - if (!link_array.empty()) - { - link_inventory_array(cat_dest_id, link_array, cb); - } -} - -// Callback for drop item if DAMA required... -void LLFolderBridge::callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - std::string tooltip_msg; - dragItemIntoFolder(inv_item, true, tooltip_msg, false); - } -} - -// Callback for drop category if DAMA required... -void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) // YES - { - std::string tooltip_msg; - dragCategoryIntoFolder(inv_category, true, tooltip_msg, false, false); - } -} - -// 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, - std::string& tooltip_msg, - bool user_confirm, - LLPointer<LLInventoryCallback> cb) -{ - LLInventoryModel* model = getInventoryModel(); - - if (!model || !inv_item) return false; - if (!isAgentInventory()) return false; // cannot drag into library - if (!isAgentAvatarValid()) return false; - - LLInventoryPanel* destination_panel = mInventoryPanel.get(); - if (!destination_panel) return false; - - LLInventoryFilter* filter = getInventoryFilter(); - if (!filter) return false; - - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); - const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - const LLUUID from_folder_uuid = inv_item->getParentUUID(); - - const bool move_is_into_current_outfit = (mUUID == current_outfit_id); - const bool move_is_into_favorites = (mUUID == favorites_id); - const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); - const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const bool move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); - const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - const bool move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id); - - LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - bool accept = false; - U64 filter_types = filter->getFilterTypes(); - // We shouldn't allow to drop non recent items into recent tab (or some similar transactions) - // while we are allowing to interact with regular filtered inventory - bool use_filter = filter_types && (filter_types&LLInventoryFilter::FILTERTYPE_DATE || (filter_types&LLInventoryFilter::FILTERTYPE_OBJECT)==0); - LLViewerObject* object = NULL; - if(LLToolDragAndDrop::SOURCE_AGENT == source) - { - const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - - 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()); - - //-------------------------------------------------------------------------------- - // Determine if item can be moved. - // - - bool is_movable = true; - - switch (inv_item->getActualType()) - { - case LLAssetType::AT_CATEGORY: - is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType()); - break; - default: - break; - } - // Can't explicitly drag things out of the COF. - if (move_is_outof_current_outfit) - { - is_movable = false; - } - if (move_is_into_trash) - { - is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID()); - } - 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()); - } - - // - //-------------------------------------------------------------------------------- - - //-------------------------------------------------------------------------------- - // Determine if item can be moved & dropped - // Note: if user_confirm is false, we already went through those accept logic test and can skip them - - accept = true; - - if (user_confirm && !is_movable) - { - accept = false; - } - else if (user_confirm && (mUUID == inv_item->getParentUUID()) && !move_is_into_favorites) - { - accept = false; - } - else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit)) - { - accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); - } - else if (user_confirm && (move_is_into_favorites || move_is_into_landmarks)) - { - accept = can_move_to_landmarks(inv_item); - } - else if (user_confirm && move_is_into_marketplacelistings) - { - const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); - LLViewerInventoryCategory * dest_folder = getCategory(); - accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex()); - } - - // Check that the folder can accept this item based on folder/item type compatibility (e.g. stock folder compatibility) - if (user_confirm && accept) - { - LLViewerInventoryCategory * dest_folder = getCategory(); - accept = dest_folder->acceptItem(inv_item); - } - - LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(false); - - // Check whether the item being dragged from active inventory panel - // passes the filter of the destination panel. - if (user_confirm && accept && active_panel && use_filter) - { - LLFolderViewItem* fv_item = active_panel->getItemByID(inv_item->getUUID()); - if (!fv_item) return false; - - accept = filter->check(fv_item->getViewModelItem()); - } - - if (accept && drop) - { - if (inv_item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash) - { - 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). - // RN: a better solution would be to deselect automatically when an item is moved - // and then select any item that is dropped only in the panel that it is dropped in - if (active_panel && (destination_panel != active_panel)) - { - active_panel->unSelectAll(); - } - // Dropping in or out of marketplace needs (sometimes) confirmation - if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings)) - { - if ((move_is_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(inv_item->getUUID()) - || LLMarketplaceData::instance().isListedAndActive(inv_item->getUUID()))) || - (move_is_into_marketplacelistings && LLMarketplaceData::instance().isInActiveFolder(mUUID))) - { - LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropItemIntoFolder, this, _1, _2, inv_item)); - return true; - } - if (move_is_into_marketplacelistings && !move_is_from_marketplacelistings) - { - LLNotificationsUtil::add("ConfirmMerchantMoveInventory", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropItemIntoFolder, this, _1, _2, inv_item)); - return true; - } - } - - //-------------------------------------------------------------------------------- - // Destination folder logic - // - - // REORDER - // (only reorder the item in Favorites folder) - if ((mUUID == inv_item->getParentUUID()) && move_is_into_favorites) - { - LLFolderViewItem* itemp = destination_panel->getRootFolder()->getDraggingOverItem(); - if (itemp) - { - LLUUID srcItemId = inv_item->getUUID(); - LLUUID destItemId = static_cast<LLFolderViewModelItemInventory*>(itemp->getViewModelItem())->getUUID(); - LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(srcItemId, destItemId); - } - } - - // FAVORITES folder - // (copy the item) - else if (move_is_into_favorites) - { - dropToFavorites(inv_item, cb); - } - // 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, cb); - } - // MARKETPLACE LISTINGS folder - // Move the item - else if (move_is_into_marketplacelistings) - { - move_item_to_marketplacelistings(inv_item, mUUID); - if (cb) cb->fire(inv_item->getUUID()); - } - // NORMAL or TRASH folder - // (move the item, restamp if into trash) - else - { - // set up observer to select item once drag and drop from inbox is complete - if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX))) - { - set_dad_inbox_object(inv_item->getUUID()); - } - - LLInvFVBridge::changeItemParent( - model, - (LLViewerInventoryItem*)inv_item, - mUUID, - move_is_into_trash); - if (cb) cb->fire(inv_item->getUUID()); - } - - if (move_is_from_marketplacelistings) - { - // If we move from an active (listed) listing, checks that it's still valid, if not, unlist - LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid); - if (version_folder_id.notNull()) - { - LLMarketplaceValidator::getInstance()->validateMarketplaceListings( - version_folder_id, - [version_folder_id](bool result) - { - if (!result) - { - LLMarketplaceData::instance().activateListing(version_folder_id, false); - } - }); - } - } - - // - //-------------------------------------------------------------------------------- - } - } - else if (LLToolDragAndDrop::SOURCE_WORLD == source) - { - // Make sure the object exists. If we allowed dragging from - // anonymous objects, it would be possible to bypass - // permissions. - object = gObjectList.findObject(inv_item->getParentUUID()); - if (!object) - { - LL_INFOS() << "Object not found for drop." << LL_ENDL; - return false; - } - - // coming from a task. Need to figure out if the person can - // move/copy this item. - LLPermissions perm(inv_item->getPermissions()); - bool is_move = false; - if ((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) - && perm.allowTransferTo(gAgent.getID()))) - // || gAgent.isGodlike()) - { - accept = true; - } - else if(object->permYouOwner()) - { - // If the object cannot be copied, but the object the - // inventory is owned by the agent, then the item can be - // moved from the task to agent inventory. - 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; - } - // Don't allow to move a single item to Favorites or Landmarks - // if it is not a landmark or a link to a landmark. - else if ((move_is_into_favorites || move_is_into_landmarks) - && !can_move_to_landmarks(inv_item)) - { - accept = false; - } - else if (move_is_into_marketplacelistings) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - accept = false; - } - - // Check whether the item being dragged from in world - // passes the filter of the destination panel. - if (accept && use_filter) - { - accept = filter->check(inv_item); - } - - if (accept && drop) - { - LLUUID item_id = inv_item->getUUID(); - std::shared_ptr<LLMoveInv> move_inv (new LLMoveInv()); - move_inv->mObjectID = inv_item->getParentUUID(); - two_uuids_t item_pair(mUUID, item_id); - move_inv->mMoveList.push_back(item_pair); - if (cb) - { - move_inv->mCallback = [item_id, cb](S32, void*, const LLMoveInv* move_inv) mutable - { cb->fire(item_id); }; - } - move_inv->mUserData = NULL; - if(is_move) - { - warn_move_inventory(object, move_inv); - } - else - { - // store dad inventory item to select added one later. See EXT-4347 - set_dad_inventory_item(inv_item, mUUID); - - LLNotification::Params params("MoveInventoryFromObject"); - params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); - LLNotifications::instance().forceResponse(params, 0); - } - } - } - else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) - { - if (move_is_into_marketplacelistings) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - accept = false; - } - else if ((inv_item->getActualType() == LLAssetType::AT_SETTINGS) && !LLEnvironment::instance().isInventoryEnabled()) - { - tooltip_msg = LLTrans::getString("NoEnvironmentSettings"); - accept = false; - } - else - { - // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder - // because they must contain only links to wearable items. - accept = !(move_is_into_current_outfit || move_is_into_outfit); - } - - // Check whether the item being dragged from notecard - // passes the filter of the destination panel. - if (accept && use_filter) - { - accept = filter->check(inv_item); - } - - if (accept && drop) - { - copy_inventory_from_notecard(mUUID, // Drop to the chosen destination folder - LLToolDragAndDrop::getInstance()->getObjectID(), - LLToolDragAndDrop::getInstance()->getSourceID(), - inv_item); - } - } - else if(LLToolDragAndDrop::SOURCE_LIBRARY == source) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item; - if(item && item->isFinished()) - { - accept = true; - - if (move_is_into_marketplacelistings) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); - accept = false; - } - else if (move_is_into_current_outfit || move_is_into_outfit) - { - accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); - } - // Don't allow to move a single item to Favorites or Landmarks - // if it is not a landmark or a link to a landmark. - else if (move_is_into_favorites || move_is_into_landmarks) - { - accept = can_move_to_landmarks(inv_item); - } - - LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(false); - - // Check whether the item being dragged from the library - // passes the filter of the destination panel. - if (accept && active_panel && use_filter) - { - LLFolderViewItem* fv_item = active_panel->getItemByID(inv_item->getUUID()); - if (!fv_item) return false; - - accept = filter->check(fv_item->getViewModelItem()); - } - - if (accept && drop) - { - // FAVORITES folder - // (copy the item) - if (move_is_into_favorites) - { - dropToFavorites(inv_item, cb); - } - // 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, cb); - } - else - { - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - mUUID, - std::string(), - cb); - } - } - } - } - else - { - LL_WARNS() << "unhandled drag source" << LL_ENDL; - } - return accept; -} - -// static -bool check_category(LLInventoryModel* model, - const LLUUID& cat_id, - LLInventoryPanel* active_panel, - LLInventoryFilter* filter) -{ - if (!model || !active_panel || !filter) - return false; - - if (!filter->checkFolder(cat_id)) - { - return false; - } - - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - model->collectDescendents(cat_id, descendent_categories, descendent_items, true); - - S32 num_descendent_categories = descendent_categories.size(); - S32 num_descendent_items = descendent_items.size(); - - if (num_descendent_categories + num_descendent_items == 0) - { - // Empty folder should be checked as any other folder view item. - // If we are filtering by date the folder should not pass because - // it doesn't have its own creation date. See LLInvFVBridge::getCreationDate(). - return check_item(cat_id, active_panel, filter); - } - - for (S32 i = 0; i < num_descendent_categories; ++i) - { - LLInventoryCategory* category = descendent_categories[i]; - if(!check_category(model, category->getUUID(), active_panel, filter)) - { - return false; - } - } - - for (S32 i = 0; i < num_descendent_items; ++i) - { - LLViewerInventoryItem* item = descendent_items[i]; - if(!check_item(item->getUUID(), active_panel, filter)) - { - return false; - } - } - - return true; -} - -// static -bool check_item(const LLUUID& item_id, - LLInventoryPanel* active_panel, - LLInventoryFilter* filter) -{ - if (!active_panel || !filter) return false; - - LLFolderViewItem* fv_item = active_panel->getItemByID(item_id); - if (!fv_item) return false; - - return filter->check(fv_item->getViewModelItem()); -} - -// +=================================================+ -// | LLTextureBridge | -// +=================================================+ - -LLUIImagePtr LLTextureBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInvType); -} - -void LLTextureBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -} - -bool LLTextureBridge::canSaveTexture(void) -{ - const LLInventoryModel* model = getInventoryModel(); - if(!model) - { - return false; - } - - const LLViewerInventoryItem *item = model->getItem(mUUID); - if (item) - { - return item->checkPermissionsSet(PERM_ITEM_UNRESTRICTED); - } - return false; -} - -void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLTextureBridge::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - - addOpenRightClickMenuOption(items); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - items.push_back(std::string("Texture Separator")); - - if ((flags & ITEM_IN_MULTI_SELECTION) != 0) - { - items.push_back(std::string("Save Selected As")); - } - else - { - items.push_back(std::string("Save As")); - if (!canSaveTexture()) - { - disabled_items.push_back(std::string("Save As")); - } - } - - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -// virtual -void LLTextureBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("save_as" == action) - { - LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUID); - if (preview_texture) - { - preview_texture->openToSave(); - preview_texture->saveAs(); - } - } - else if ("save_selected_as" == action) - { - openItem(); - if (canSaveTexture()) - { - LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUID); - if (preview_texture) - { - preview_texture->saveMultipleToFile(mFileName); - } - } - else - { - LL_WARNS() << "You don't have permission to save " << getName() << " to disk." << LL_ENDL; - } - - } - else LLItemBridge::performAction(model, action); -} - -// +=================================================+ -// | LLSoundBridge | -// +=================================================+ - -void LLSoundBridge::openItem() -{ - const LLViewerInventoryItem* item = getItem(); - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -} - -void LLSoundBridge::openSoundPreview(void* which) -{ - LLSoundBridge *me = (LLSoundBridge *)which; - LLFloaterReg::showInstance("preview_sound", LLSD(me->mUUID), TAKE_FOCUS_YES); -} - -void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLSoundBridge::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - if (isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - items.push_back(std::string("Sound Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - - items.push_back(std::string("Sound Separator")); - items.push_back(std::string("Sound Play")); - } - - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -void LLSoundBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("sound_play" == action) - { - LLViewerInventoryItem* item = getItem(); - if(item) - { - send_sound_trigger(item->getAssetUUID(), SOUND_GAIN); - } - } - else if ("open" == action) - { - openSoundPreview((void*)this); - } - else LLItemBridge::performAction(model, action); -} - -// +=================================================+ -// | LLLandmarkBridge | -// +=================================================+ - -LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory, - LLFolderView* root, - const LLUUID& uuid, - U32 flags/* = 0x00*/) : - LLItemBridge(inventory, root, uuid) -{ - mVisited = false; - if (flags & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED) - { - mVisited = true; - } -} - -LLUIImagePtr LLLandmarkBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, false); -} - -void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - LL_DEBUGS() << "LLLandmarkBridge::buildContextMenu()" << LL_ENDL; - if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - items.push_back(std::string("Landmark Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - - items.push_back(std::string("Landmark Separator")); - items.push_back(std::string("url_copy")); - items.push_back(std::string("About Landmark")); - items.push_back(std::string("show_on_map")); - } - - // Disable "About Landmark" menu item for - // multiple landmarks selected. Only one landmark - // info panel can be shown at a time. - if ((flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("url_copy")); - disabled_items.push_back(std::string("About Landmark")); - } - - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -// Convenience function for the two functions below. -void teleport_via_landmark(const LLUUID& asset_id) -{ - gAgent.teleportViaLandmark( asset_id ); - - // we now automatically track the landmark you're teleporting to - // because you'll probably arrive at a telehub instead - LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); - if( floater_world_map ) - { - floater_world_map->trackLandmark( asset_id ); - } -} - -// virtual -void LLLandmarkBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("teleport" == action) - { - LLViewerInventoryItem* item = getItem(); - if(item) - { - teleport_via_landmark(item->getAssetUUID()); - } - } - else if ("about" == action) - { - LLViewerInventoryItem* item = getItem(); - if(item) - { - LLSD key; - key["type"] = "landmark"; - key["id"] = item->getUUID(); - - LLFloaterSidePanelContainer::showPanel("places", key); - } - } - else - { - LLItemBridge::performAction(model, action); - } -} - -static bool open_landmark_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - LLUUID asset_id = notification["payload"]["asset_id"].asUUID(); - if (option == 0) - { - teleport_via_landmark(asset_id); - } - - return false; -} -static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportFromLandmark", open_landmark_callback); - - -void LLLandmarkBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -} - - -// +=================================================+ -// | LLCallingCardObserver | -// +=================================================+ -class LLCallingCardObserver : public LLFriendObserver -{ -public: - LLCallingCardObserver(LLCallingCardBridge* bridge) : mBridgep(bridge) {} - virtual ~LLCallingCardObserver() { mBridgep = NULL; } - virtual void changed(U32 mask) - { - if (mask & LLFriendObserver::ONLINE) - { - mBridgep->refreshFolderViewItem(); - mBridgep->checkSearchBySuffixChanges(); - } - } -protected: - LLCallingCardBridge* mBridgep; -}; - -// +=================================================+ -// | LLCallingCardBridge | -// +=================================================+ - -LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory, - LLFolderView* root, - const LLUUID& uuid ) : - LLItemBridge(inventory, root, uuid) -{ - mObserver = new LLCallingCardObserver(this); - mCreatorUUID = getItem()->getCreatorUUID(); - LLAvatarTracker::instance().addParticularFriendObserver(mCreatorUUID, mObserver); -} - -LLCallingCardBridge::~LLCallingCardBridge() -{ - LLAvatarTracker::instance().removeParticularFriendObserver(mCreatorUUID, mObserver); - - delete mObserver; -} - -void LLCallingCardBridge::refreshFolderViewItem() -{ - LLInventoryPanel* panel = mInventoryPanel.get(); - LLFolderViewItem* itemp = panel ? panel->getItemByID(mUUID) : NULL; - if (itemp) - { - itemp->refresh(); - } -} - -void LLCallingCardBridge::checkSearchBySuffixChanges() -{ - if (!mDisplayName.empty()) - { - // changes in mDisplayName are processed by rename function and here it will be always same - // suffixes are also of fixed length, and we are processing change of one at a time, - // so it should be safe to use length (note: mSearchableName is capitalized) - S32 old_length = mSearchableName.length(); - S32 new_length = mDisplayName.length() + getLabelSuffix().length(); - if (old_length == new_length) - { - return; - } - mSearchableName.assign(mDisplayName); - mSearchableName.append(getLabelSuffix()); - LLStringUtil::toUpper(mSearchableName); - if (new_length<old_length) - { - LLInventoryFilter* filter = getInventoryFilter(); - if (filter && mPassedFilter && mSearchableName.find(filter->getFilterSubString()) == std::string::npos) - { - // string no longer contains substring - // we either have to update all parents manually or restart filter. - // dirtyFilter will not work here due to obsolete descendants' generations - getInventoryFilter()->setModified(LLFolderViewFilter::FILTER_MORE_RESTRICTIVE); - } - } - else - { - if (getInventoryFilter()) - { - // mSearchableName became longer, we gained additional suffix and need to repeat filter check. - dirtyFilter(); - } - } - } -} - -// virtual -void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("begin_im" == action) - { - LLViewerInventoryItem *item = getItem(); - if (item && (item->getCreatorUUID() != gAgent.getID()) && - (!item->getCreatorUUID().isNull())) - { - std::string callingcard_name = LLCacheName::getDefaultName(); - LLAvatarName av_name; - if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name)) - { - callingcard_name = av_name.getCompleteName(); - } - LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID()); - if (session_id != LLUUID::null) - { - LLFloaterIMContainer::getInstance()->showConversation(session_id); - } - } - } - else if ("lure" == action) - { - LLViewerInventoryItem *item = getItem(); - if (item && (item->getCreatorUUID() != gAgent.getID()) && - (!item->getCreatorUUID().isNull())) - { - LLAvatarActions::offerTeleport(item->getCreatorUUID()); - } - } - else if ("request_lure" == action) - { - LLViewerInventoryItem *item = getItem(); - if (item && (item->getCreatorUUID() != gAgent.getID()) && - (!item->getCreatorUUID().isNull())) - { - LLAvatarActions::teleportRequest(item->getCreatorUUID()); - } - } - - else LLItemBridge::performAction(model, action); -} - -LLUIImagePtr LLCallingCardBridge::getIcon() const -{ - bool online = false; - LLViewerInventoryItem* item = getItem(); - if(item) - { - online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()); - } - return LLInventoryIcon::getIcon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, false); -} - -std::string LLCallingCardBridge::getLabelSuffix() const -{ - LLViewerInventoryItem* item = getItem(); - if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) ) - { - return LLItemBridge::getLabelSuffix() + " online"; - } - else - { - return LLItemBridge::getLabelSuffix(); - } -} - -void LLCallingCardBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* - LLViewerInventoryItem* item = getItem(); - if(item && !item->getCreatorUUID().isNull()) - { - LLAvatarActions::showProfile(item->getCreatorUUID()); - } -*/ -} - -void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLCallingCardBridge::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - if ((flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Open")); - } - addOpenRightClickMenuOption(items); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - LLInventoryItem* item = getItem(); - bool good_card = (item - && (LLUUID::null != item->getCreatorUUID()) - && (item->getCreatorUUID() != gAgent.getID())); - bool user_online = false; - if (item) - { - user_online = (LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID())); - } - items.push_back(std::string("Send Instant Message Separator")); - items.push_back(std::string("Send Instant Message")); - items.push_back(std::string("Offer Teleport...")); - items.push_back(std::string("Request Teleport...")); - items.push_back(std::string("Conference Chat")); - - if (!good_card) - { - disabled_items.push_back(std::string("Send Instant Message")); - } - if (!good_card || !user_online) - { - disabled_items.push_back(std::string("Offer Teleport...")); - disabled_items.push_back(std::string("Request Teleport...")); - disabled_items.push_back(std::string("Conference Chat")); - } - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -bool LLCallingCardBridge::dragOrDrop(MASK mask, bool drop, - EDragAndDropType cargo_type, - void* cargo_data, - std::string& tooltip_msg) -{ - LLViewerInventoryItem* item = getItem(); - bool rv = false; - if(item) - { - // check the type - switch(cargo_type) - { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_CLOTHING: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - case DAD_MESH: - case DAD_SETTINGS: - case DAD_MATERIAL: - { - LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; - const LLPermissions& perm = inv_item->getPermissions(); - if(gInventory.getItem(inv_item->getUUID()) - && perm.allowOperationBy(PERM_TRANSFER, gAgent.getID())) - { - rv = true; - if(drop) - { - LLGiveInventory::doGiveInventoryItem(item->getCreatorUUID(), - (LLInventoryItem*)cargo_data); - } - } - else - { - // It's not in the user's inventory (it's probably in - // an object's contents), so disallow dragging it here. - // You can't give something you don't yet have. - rv = false; - } - break; - } - case DAD_CATEGORY: - { - LLInventoryCategory* inv_cat = (LLInventoryCategory*)cargo_data; - if( gInventory.getCategory( inv_cat->getUUID() ) ) - { - rv = true; - if(drop) - { - LLGiveInventory::doGiveInventoryCategory( - item->getCreatorUUID(), - inv_cat); - } - } - else - { - // It's not in the user's inventory (it's probably in - // an object's contents), so disallow dragging it here. - // You can't give something you don't yet have. - rv = false; - } - break; - } - default: - break; - } - } - return rv; -} - -// +=================================================+ -// | LLNotecardBridge | -// +=================================================+ - -void LLNotecardBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -} - -void LLNotecardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLNotecardBridge::buildContextMenu()" << LL_ENDL; - - if (isMarketplaceListingsFolder()) - { - menuentry_vec_t items; - menuentry_vec_t disabled_items; - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - hide_context_entries(menu, items, disabled_items); - } - else - { - LLItemBridge::buildContextMenu(menu, flags); - } -} - -// +=================================================+ -// | LLGestureBridge | -// +=================================================+ - -LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const -{ - if( LLGestureMgr::instance().isGestureActive(mUUID) ) - { - return LLFontGL::BOLD; - } - else - { - return LLFontGL::NORMAL; - } -} - -std::string LLGestureBridge::getLabelSuffix() const -{ - if( LLGestureMgr::instance().isGestureActive(mUUID) ) - { - LLStringUtil::format_map_t args; - args["[GESLABEL]"] = LLItemBridge::getLabelSuffix(); - return LLTrans::getString("ActiveGesture", args); - } - else - { - return LLItemBridge::getLabelSuffix(); - } -} - -// virtual -void LLGestureBridge::performAction(LLInventoryModel* model, std::string action) -{ - if (isAddAction(action)) - { - LLGestureMgr::instance().activateGesture(mUUID); - - LLViewerInventoryItem* item = gInventory.getItem(mUUID); - if (!item) return; - - // Since we just changed the suffix to indicate (active) - // the server doesn't need to know, just the viewer. - gInventory.updateItem(item); - gInventory.notifyObservers(); - } - else if ("deactivate" == action || isRemoveAction(action)) - { - LLGestureMgr::instance().deactivateGesture(mUUID); - - LLViewerInventoryItem* item = gInventory.getItem(mUUID); - if (!item) return; - - // Since we just changed the suffix to indicate (active) - // the server doesn't need to know, just the viewer. - gInventory.updateItem(item); - gInventory.notifyObservers(); - } - else if("play" == action) - { - if(!LLGestureMgr::instance().isGestureActive(mUUID)) - { - // we need to inform server about gesture activating to be consistent with LLPreviewGesture and LLGestureComboList. - bool inform_server = true; - bool deactivate_similar = false; - LLGestureMgr::instance().setGestureLoadedCallback(mUUID, boost::bind(&LLGestureBridge::playGesture, mUUID)); - LLViewerInventoryItem* item = gInventory.getItem(mUUID); - llassert(item); - if (item) - { - LLGestureMgr::instance().activateGestureWithAsset(mUUID, item->getAssetUUID(), inform_server, deactivate_similar); - } - } - else - { - playGesture(mUUID); - } - } - else LLItemBridge::performAction(model, action); -} - -void LLGestureBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); - preview->setFocus(true); - } -*/ -} - -bool LLGestureBridge::removeItem() -{ - // Grab class information locally since *this may be deleted - // within this function. Not a great pattern... - const LLInventoryModel* model = getInventoryModel(); - if(!model) - { - return false; - } - const LLUUID item_id = mUUID; - - // This will also force close the preview window, if it exists. - // This may actually delete *this, if mUUID is in the COF. - LLGestureMgr::instance().deactivateGesture(item_id); - - // If deactivateGesture deleted *this, then return out immediately. - if (!model->getObject(item_id)) - { - return true; - } - - return LLItemBridge::removeItem(); -} - -void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLGestureBridge::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - - addOpenRightClickMenuOption(items); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - items.push_back(std::string("Gesture Separator")); - if (LLGestureMgr::instance().isGestureActive(getUUID())) - { - items.push_back(std::string("Deactivate")); - } - else - { - items.push_back(std::string("Activate")); - } - items.push_back(std::string("PlayGesture")); - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -// static -void LLGestureBridge::playGesture(const LLUUID& item_id) -{ - if (LLGestureMgr::instance().isGesturePlaying(item_id)) - { - LLGestureMgr::instance().stopGesture(item_id); - } - else - { - LLGestureMgr::instance().playGesture(item_id); - } -} - - -// +=================================================+ -// | LLAnimationBridge | -// +=================================================+ - -void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - LL_DEBUGS() << "LLAnimationBridge::buildContextMenu()" << LL_ENDL; - if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - items.push_back(std::string("Animation Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - - items.push_back(std::string("Animation Separator")); - items.push_back(std::string("Animation Play")); - items.push_back(std::string("Animation Audition")); - } - - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -// virtual -void LLAnimationBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ((action == "playworld") || (action == "playlocal")) - { - if (getItem()) - { - LLSD::String activate = "NONE"; - if ("playworld" == action) activate = "Inworld"; - if ("playlocal" == action) activate = "Locally"; - - LLPreviewAnim* preview = LLFloaterReg::showTypedInstance<LLPreviewAnim>("preview_anim", LLSD(mUUID)); - if (preview) - { - preview->play(activate); - } - } - } - else - { - LLItemBridge::performAction(model, action); - } -} - -void LLAnimationBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); - } -*/ -} - -// +=================================================+ -// | LLObjectBridge | -// +=================================================+ - -// static -LLUUID LLObjectBridge::sContextMenuItemID; - -LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory, - LLFolderView* root, - const LLUUID& uuid, - LLInventoryType::EType type, - U32 flags) : - LLItemBridge(inventory, root, uuid) -{ - mAttachPt = (flags & 0xff); // low bye of inventory flags - mIsMultiObject = is_flag_set(flags, LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS); - mInvType = type; -} - -LLUIImagePtr LLObjectBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject); -} - -LLInventoryObject* LLObjectBridge::getObject() const -{ - LLInventoryObject* object = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - object = (LLInventoryObject*)model->getObject(mUUID); - } - return object; -} - -// virtual -void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) -{ - if (isAddAction(action)) - { - LLUUID object_id = mUUID; - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(object_id); - if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID())) - { - rez_attachment(item, NULL, true); // Replace if "Wear"ing. - } - else if(item && item->isFinished()) - { - // must be in library. copy it to our inventory and put it on. - LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0)); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - gFocusMgr.setKeyboardFocus(NULL); - } - else if ("wear_add" == action) - { - LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding. - } - else if ("touch" == action) - { - handle_attachment_touch(mUUID); - } - else if ("edit" == action) - { - handle_attachment_edit(mUUID); - } - else if (isRemoveAction(action)) - { - LLAppearanceMgr::instance().removeItemFromAvatar(mUUID); - } - else LLItemBridge::performAction(model, action); -} - -void LLObjectBridge::openItem() -{ - // 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; - if (gAgentAvatarp->getAttachedPointName(mUUID, attachment_point_name)) - { - LLStringUtil::format_map_t args; - args["[ATTACHMENT_POINT]"] = LLTrans::getString(attachment_point_name); - - return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args); - } - else - { - LLStringUtil::format_map_t args; - args["[ATTACHMENT_ERROR]"] = LLTrans::getString(attachment_point_name); - return LLItemBridge::getLabelSuffix() + LLTrans::getString("AttachmentErrorMessage", args); - } - } - return LLItemBridge::getLabelSuffix(); -} - -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) -{ - const LLUUID& item_id = item->getLinkedUUID(); - - // Check for duplicate request. - if (isAgentAvatarValid() && - gAgentAvatarp->isWearingAttachment(item_id)) - { - LL_WARNS() << "ATT duplicate attachment request, ignoring" << LL_ENDL; - return; - } - - S32 attach_pt = 0; - if (isAgentAvatarValid() && attachment) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) - { - if (iter->second == attachment) - { - attach_pt = iter->first; - break; - } - } - } - - 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 (replace && - (attachment && attachment->getNumObjects() > 0)) - { - LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez); - } - else - { - LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); - } -} - -bool confirm_attachment_rez(const LLSD& notification, const LLSD& response) -{ - if (!gAgentAvatarp->canAttachMoreObjects()) - { - LLSD args; - args["MAX_ATTACHMENTS"] = llformat("%d", gAgentAvatarp->getMaxAttachments()); - LLNotificationsUtil::add("MaxAttachmentsOnOutfit", args); - return false; - } - - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0/*YES*/) - { - LLUUID item_id = notification["payload"]["item_id"].asUUID(); - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - - if (itemp) - { - // 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(); - bool is_add = notification["payload"]["is_add"].asBoolean(); - - LL_DEBUGS("Avatar") << "ATT calling addAttachmentRequest " << (itemp ? itemp->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; - LLAttachmentsMgr::instance().addAttachmentRequest(item_id, attachment_pt, is_add); - } - } - return false; -} -static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_attachment_rez); - -void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - menuentry_vec_t items; - menuentry_vec_t disabled_items; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - LLObjectBridge::sContextMenuItemID = mUUID; - - LLInventoryItem *item = getItem(); - if(item) - { - if (!isAgentAvatarValid()) return; - - if( get_is_item_worn( mUUID ) ) - { - items.push_back(std::string("Wearable And Object Separator")); - - items.push_back(std::string("Attachment Touch")); - if ( ((flags & FIRST_SELECTED_ITEM) == 0) || !enable_attachment_touch(mUUID) ) - { - disabled_items.push_back(std::string("Attachment Touch")); - } - - items.push_back(std::string("Wearable Edit")); - if ( ((flags & FIRST_SELECTED_ITEM) == 0) || !get_is_item_editable(mUUID) ) - { - disabled_items.push_back(std::string("Wearable Edit")); - } - - items.push_back(std::string("Detach From Yourself")); - } - else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder()) - { - 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 - //items.push_back(std::string("Restore to Last Position")); - - if (!gAgentAvatarp->canAttachMoreObjects()) - { - 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")); - } - LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", true); - LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", true); - if (attach_menu - && (attach_menu->getChildCount() == 0) - && attach_hud_menu - && (attach_hud_menu->getChildCount() == 0) - && isAgentAvatarValid()) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - LLMenuItemCallGL::Params p; - std::string submenu_name = attachment->getName(); - if (LLTrans::getString(submenu_name) != "") - { - p.name = (" ")+LLTrans::getString(submenu_name)+" "; - } - else - { - p.name = submenu_name; - } - LLSD cbparams; - cbparams["index"] = curiter->first; - 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"; - p.on_enable.parameter = cbparams; - LLView* parent = attachment->getIsHUDAttachment() ? attach_hud_menu : attach_menu; - LLUICtrlFactory::create<LLMenuItemCallGL>(p, parent); - items.push_back(p.name); - } - } - } - } - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -bool LLObjectBridge::renameItem(const std::string& new_name) -{ - if(!isItemRenameable()) - return false; - LLPreview::dirty(mUUID); - LLInventoryModel* model = getInventoryModel(); - if(!model) - return false; - LLViewerInventoryItem* item = getItem(); - if(item && (item->getName() != new_name)) - { - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - new_item->rename(new_name); - new_item->updateServer(false); - model->updateItem(new_item); - model->notifyObservers(); - buildDisplayName(); - - if (isAgentAvatarValid()) - { - LLViewerObject* obj = gAgentAvatarp->getWornAttachment( item->getUUID() ); - if(obj) - { - LLSelectMgr::getInstance()->deselectAll(); - LLSelectMgr::getInstance()->addAsIndividual( obj, SELECT_ALL_TES, false ); - LLSelectMgr::getInstance()->selectionSetObjectName( new_name ); - LLSelectMgr::getInstance()->deselectAll(); - } - } - } - // return false because we either notified observers (& therefore - // rebuilt) or we didn't update. - return false; -} - -// +=================================================+ -// | LLLSLTextBridge | -// +=================================================+ - -void LLLSLTextBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -} - -// +=================================================+ -// | LLWearableBridge | -// +=================================================+ - -LLWearableBridge::LLWearableBridge(LLInventoryPanel* inventory, - LLFolderView* root, - const LLUUID& uuid, - LLAssetType::EType asset_type, - LLInventoryType::EType inv_type, - LLWearableType::EType wearable_type) : - LLItemBridge(inventory, root, uuid), - mAssetType( asset_type ), - mWearableType(wearable_type) -{ - mInvType = inv_type; -} - -bool LLWearableBridge::renameItem(const std::string& new_name) -{ - if (get_is_item_worn(mUUID)) - { - gAgentWearables.setWearableName( mUUID, new_name ); - } - return LLItemBridge::renameItem(new_name); -} - -std::string LLWearableBridge::getLabelSuffix() const -{ - if (get_is_item_worn(mUUID)) - { - // e.g. "(worn)" - return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); - } - else - { - return LLItemBridge::getLabelSuffix(); - } -} - -LLUIImagePtr LLWearableBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(mAssetType, mInvType, mWearableType, false); -} - -// virtual -void LLWearableBridge::performAction(LLInventoryModel* model, std::string action) -{ - if (isAddAction(action)) - { - wearOnAvatar(); - } - else if ("wear_add" == action) - { - wearAddOnAvatar(); - } - else if ("edit" == action) - { - editOnAvatar(); - return; - } - else if (isRemoveAction(action)) - { - removeFromAvatar(); - return; - } - else LLItemBridge::performAction(model, action); -} - -void LLWearableBridge::openItem() -{ - performAction(getInventoryModel(), - get_is_item_worn(mUUID) ? "take_off" : "wear"); -} - -void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLWearableBridge::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if (isMarketplaceListingsFolder()) - { - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - } - else - { // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere - bool can_open = ((flags & SUPPRESS_OPEN_ITEM) != SUPPRESS_OPEN_ITEM); - - // If we have clothing, don't add "Open" as it's the same action as "Wear" SL-18976 - LLViewerInventoryItem* item = getItem(); - if (can_open && item) - { - can_open = (item->getType() != LLAssetType::AT_CLOTHING) && - (item->getType() != LLAssetType::AT_BODYPART); - } - if (isLinkedObjectMissing()) - { - can_open = false; - } - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - - if (can_open) - { - addOpenRightClickMenuOption(items); - } - else - { - 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); - - items.push_back(std::string("Wearable And Object Separator")); - items.push_back(std::string("Wearable Edit")); - - if (((flags & FIRST_SELECTED_ITEM) == 0) || (item && !gAgentWearables.isWearableModifiable(item->getUUID()))) - { - disabled_items.push_back(std::string("Wearable Edit")); - } - // 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 And Object Wear")); - disabled_items.push_back(std::string("Wearable Add")); - disabled_items.push_back(std::string("Wearable Edit")); - } - - // Disable wear and take off based on whether the item is worn. - if(item) - { - switch (item->getType()) - { - case LLAssetType::AT_CLOTHING: - items.push_back(std::string("Take Off")); - // Fallthrough since clothing and bodypart share wear options - case LLAssetType::AT_BODYPART: - if (get_is_item_worn(item->getUUID())) - { - 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 And Object Wear")); - disabled_items.push_back(std::string("Take Off")); - disabled_items.push_back(std::string("Wearable Edit")); - } - - if (LLWearableType::getInstance()->getAllowMultiwear(mWearableType)) - { - items.push_back(std::string("Wearable Add")); - if (!gAgentWearables.canAddWearable(mWearableType)) - { - disabled_items.push_back(std::string("Wearable Add")); - } - } - break; - default: - break; - } - } - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -// Called from menus -// static -bool LLWearableBridge::canWearOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(!self) return false; - if(!self->isAgentInventory()) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); - if(!item || !item->isFinished()) return false; - } - return (!get_is_item_worn(self->mUUID)); -} - -// Called from menus -// static -void LLWearableBridge::onWearOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(!self) return; - self->wearOnAvatar(); -} - -void LLWearableBridge::wearOnAvatar() -{ - // TODO: investigate wearables may not be loaded at this point EXT-8231 - - LLViewerInventoryItem* item = getItem(); - if(item) - { - LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true); - } -} - -void LLWearableBridge::wearAddOnAvatar() -{ - // TODO: investigate wearables may not be loaded at this point EXT-8231 - - LLViewerInventoryItem* item = getItem(); - if(item) - { - LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, false); - } -} - -// static -void LLWearableBridge::onWearOnAvatarArrived( LLViewerWearable* wearable, void* userdata ) -{ - LLUUID* item_id = (LLUUID*) userdata; - if(wearable) - { - LLViewerInventoryItem* item = NULL; - item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); - if(item) - { - if(item->getAssetUUID() == wearable->getAssetID()) - { - gAgentWearables.setWearableItem(item, wearable); - gInventory.notifyObservers(); - //self->getFolderItem()->refreshFromRoot(); - } - else - { - LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; - } - } - } - delete item_id; -} - -// static -// BAP remove the "add" code path once everything is fully COF-ified. -void LLWearableBridge::onWearAddOnAvatarArrived( LLViewerWearable* wearable, void* userdata ) -{ - LLUUID* item_id = (LLUUID*) userdata; - if(wearable) - { - LLViewerInventoryItem* item = NULL; - item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); - if(item) - { - if(item->getAssetUUID() == wearable->getAssetID()) - { - bool do_append = true; - gAgentWearables.setWearableItem(item, wearable, do_append); - gInventory.notifyObservers(); - //self->getFolderItem()->refreshFromRoot(); - } - else - { - LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; - } - } - } - delete item_id; -} - -// static -bool LLWearableBridge::canEditOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(!self) return false; - - return (get_is_item_worn(self->mUUID)); -} - -// static -void LLWearableBridge::onEditOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(self) - { - self->editOnAvatar(); - } -} - -void LLWearableBridge::editOnAvatar() -{ - LLAgentWearables::editWearable(mUUID); -} - -// static -bool LLWearableBridge::canRemoveFromAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if( self && (LLAssetType::AT_BODYPART != self->mAssetType) ) - { - return get_is_item_worn( self->mUUID ); - } - return false; -} - -void LLWearableBridge::removeFromAvatar() -{ - LL_WARNS() << "safe to remove?" << LL_ENDL; - if (get_is_item_worn(mUUID)) - { - LLAppearanceMgr::instance().removeItemFromAvatar(mUUID); - } -} - - -// +=================================================+ -// | LLLinkItemBridge | -// +=================================================+ -// For broken item links - -std::string LLLinkItemBridge::sPrefix("Link: "); - -void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - // *TODO: Translate - LL_DEBUGS() << "LLLink::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - items.push_back(std::string("Find Original")); - disabled_items.push_back(std::string("Find Original")); - - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Properties")); - addDeleteContextMenuOptions(items, disabled_items); - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -// +=================================================+ -// | LLSettingsBridge | -// +=================================================+ - -LLSettingsBridge::LLSettingsBridge(LLInventoryPanel* inventory, - LLFolderView* root, - const LLUUID& uuid, - LLSettingsType::type_e settings_type): - LLItemBridge(inventory, root, uuid), - mSettingsType(settings_type) -{ -} - -LLUIImagePtr LLSettingsBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_SETTINGS, LLInventoryType::IT_SETTINGS, mSettingsType, false); -} - -void LLSettingsBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("apply_settings_local" == action) - { - // Single item only - LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); - if (!item) - return; - LLUUID asset_id = item->getAssetUUID(); - LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, asset_id, LLEnvironment::TRANSITION_INSTANT); - LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT); - } - else if ("apply_settings_parcel" == action) - { - // Single item only - LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); - if (!item) - return; - LLUUID asset_id = item->getAssetUUID(); - std::string name = item->getName(); - - U32 flags(0); - - if (!item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())) - flags |= LLSettingsBase::FLAG_NOMOD; - if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) - flags |= LLSettingsBase::FLAG_NOTRANS; - - LLParcel *parcel = LLViewerParcelMgr::instance().getAgentOrSelectedParcel(); - if (!parcel) - { - LL_WARNS("INVENTORY") << "could not identify parcel." << LL_ENDL; - return; - } - S32 parcel_id = parcel->getLocalID(); - - LL_DEBUGS("ENVIRONMENT") << "Applying asset ID " << asset_id << " to parcel " << parcel_id << LL_ENDL; - LLEnvironment::instance().updateParcel(parcel_id, asset_id, name, LLEnvironment::NO_TRACK, -1, -1, flags); - LLEnvironment::instance().setSharedEnvironment(); - } - else - LLItemBridge::performAction(model, action); -} - -void LLSettingsBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - if (item->getPermissions().getOwner() != gAgent.getID()) - LLNotificationsUtil::add("NoEditFromLibrary"); - else - LLInvFVBridgeAction::doAction(item->getType(), mUUID, getInventoryModel()); - } -} - -void LLSettingsBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLSettingsBridge::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - if (isMarketplaceListingsFolder()) - { - menuentry_vec_t items; - menuentry_vec_t disabled_items; - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - hide_context_entries(menu, items, disabled_items); - } - else if (isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Share")); - if (!canShare()) - { - disabled_items.push_back(std::string("Share")); - } - - addOpenRightClickMenuOption(items); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - items.push_back("Settings Separator"); - items.push_back("Settings Apply Local"); - - items.push_back("Settings Apply Parcel"); - if (!canUpdateParcel()) - disabled_items.push_back("Settings Apply Parcel"); - - items.push_back("Settings Apply Region"); - if (!canUpdateRegion()) - disabled_items.push_back("Settings Apply Region"); - } - addLinkReplaceMenuOption(items, disabled_items); - hide_context_entries(menu, items, disabled_items); -} - -bool LLSettingsBridge::renameItem(const std::string& new_name) -{ - /*TODO: change internal settings name? */ - return LLItemBridge::renameItem(new_name); -} - -bool LLSettingsBridge::isItemRenameable() const -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - return (item->getPermissions().allowModifyBy(gAgent.getID())); - } - return false; -} - -bool LLSettingsBridge::canUpdateParcel() const -{ - return LLEnvironment::instance().canAgentUpdateParcelEnvironment(); -} - -bool LLSettingsBridge::canUpdateRegion() const -{ - return LLEnvironment::instance().canAgentUpdateRegionEnvironment(); -} - - -// +=================================================+ -// | LLMaterialBridge | -// +=================================================+ - -void LLMaterialBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -} - -void LLMaterialBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - LL_DEBUGS() << "LLMaterialBridge::buildContextMenu()" << LL_ENDL; - - if (isMarketplaceListingsFolder()) - { - menuentry_vec_t items; - menuentry_vec_t disabled_items; - addMarketplaceContextMenuOptions(flags, items, disabled_items); - items.push_back(std::string("Properties")); - getClipboardEntries(false, items, disabled_items, flags); - hide_context_entries(menu, items, disabled_items); - } - else - { - LLItemBridge::buildContextMenu(menu, flags); - } -} - - -// +=================================================+ -// | LLLinkBridge | -// +=================================================+ -// For broken folder links. -std::string LLLinkFolderBridge::sPrefix("Link: "); -LLUIImagePtr LLLinkFolderBridge::getIcon() const -{ - LLFolderType::EType folder_type = LLFolderType::FT_NONE; - const LLInventoryObject *obj = getInventoryObject(); - if (obj) - { - LLViewerInventoryCategory* cat = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - cat = (LLViewerInventoryCategory*)model->getCategory(obj->getLinkedUUID()); - if (cat) - { - folder_type = cat->getPreferredType(); - } - } - } - return LLFolderBridge::getIcon(folder_type); -} - -void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - // *TODO: Translate - LL_DEBUGS() << "LLLink::buildContextMenu()" << LL_ENDL; - menuentry_vec_t items; - menuentry_vec_t disabled_items; - - if (isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else - { - items.push_back(std::string("Find Original")); - addDeleteContextMenuOptions(items, disabled_items); - } - hide_context_entries(menu, items, disabled_items); -} -void LLLinkFolderBridge::performAction(LLInventoryModel* model, std::string action) -{ - if ("goto" == action) - { - gotoItem(); - return; - } - LLItemBridge::performAction(model,action); -} -void LLLinkFolderBridge::gotoItem() -{ - LLItemBridge::gotoItem(); - - const LLUUID &cat_uuid = getFolderID(); - if (!cat_uuid.isNull()) - { - LLFolderViewItem *base_folder = LLInventoryPanel::getActiveInventoryPanel()->getItemByID(cat_uuid); - if (base_folder) - { - base_folder->setOpen(true); - } - } -} -const LLUUID &LLLinkFolderBridge::getFolderID() const -{ - if (LLViewerInventoryItem *link_item = getItem()) - { - if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory()) - { - const LLUUID& cat_uuid = cat->getUUID(); - return cat_uuid; - } - } - return LLUUID::null; -} - -void LLUnknownItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - menuentry_vec_t items; - menuentry_vec_t disabled_items; - items.push_back(std::string("Properties")); - items.push_back(std::string("Rename")); - hide_context_entries(menu, items, disabled_items); -} - -LLUIImagePtr LLUnknownItemBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_UNKNOWN, mInvType); -} - - -/******************************************************************************** - ** - ** BRIDGE ACTIONS - **/ - -// static -void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type, - const LLUUID& uuid, - LLInventoryModel* 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(); - delete action; - } -} - -// static -void LLInvFVBridgeAction::doAction(const LLUUID& uuid, LLInventoryModel* model) -{ - llassert(model); - LLViewerInventoryItem* item = model->getItem(uuid); - llassert(item); - if (item) - { - LLAssetType::EType asset_type = item->getType(); - LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); - if(action) - { - action->doIt(); - delete action; - } - } -} - -LLViewerInventoryItem* LLInvFVBridgeAction::getItem() const -{ - if (mModel) - return (LLViewerInventoryItem*)mModel->getItem(mUUID); - return NULL; -} - -class LLTextureBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - if (getItem()) - { - LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLTextureBridgeAction(){} -protected: - LLTextureBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - -class LLSoundBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - send_sound_trigger(item->getAssetUUID(), SOUND_GAIN); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLSoundBridgeAction(){} -protected: - LLSoundBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - -class LLLandmarkBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - // Opening (double-clicking) a landmark immediately teleports, - // but warns you the first time. - LLSD payload; - payload["asset_id"] = item->getAssetUUID(); - - LLSD args; - args["LOCATION"] = item->getName(); - - LLNotificationsUtil::add("TeleportFromLandmark", args, payload); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLLandmarkBridgeAction(){} -protected: - LLLandmarkBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - -class LLCallingCardBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item && item->getCreatorUUID().notNull()) - { - LLAvatarActions::showProfile(item->getCreatorUUID()); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLCallingCardBridgeAction(){} -protected: - LLCallingCardBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} - -}; - -class LLNotecardBridgeAction -: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLNotecardBridgeAction(){} -protected: - LLNotecardBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - -class LLGestureBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); - preview->setFocus(true); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLGestureBridgeAction(){} -protected: - LLGestureBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - -class LLAnimationBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLAnimationBridgeAction(){} -protected: - LLAnimationBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - -class LLObjectBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - attachOrDetach(); - } - virtual ~LLObjectBridgeAction(){} -protected: - LLObjectBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} - void attachOrDetach(); -}; - -void LLObjectBridgeAction::attachOrDetach() -{ - if (get_is_item_worn(mUUID)) - { - LLAppearanceMgr::instance().removeItemFromAvatar(mUUID); - } - else - { - LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding. - } -} - -class LLLSLTextBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES); - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLLSLTextBridgeAction(){} -protected: - LLLSLTextBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - -class LLWearableBridgeAction: public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - wearOnAvatar(); - } - - virtual ~LLWearableBridgeAction(){} -protected: - LLWearableBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} - bool isItemInTrash() const; - // return true if the item is in agent inventory. if false, it - // must be lost or in the inventory library. - bool isAgentInventory() const; - void wearOnAvatar(); -}; - -bool LLWearableBridgeAction::isItemInTrash() const -{ - if(!mModel) return false; - const LLUUID trash_id = mModel->findCategoryUUIDForType(LLFolderType::FT_TRASH); - return mModel->isObjectDescendentOf(mUUID, trash_id); -} - -bool LLWearableBridgeAction::isAgentInventory() const -{ - if(!mModel) return false; - if(gInventory.getRootFolderID() == mUUID) return true; - return mModel->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); -} - -void LLWearableBridgeAction::wearOnAvatar() -{ - // TODO: investigate wearables may not be loaded at this point EXT-8231 - - LLViewerInventoryItem* item = getItem(); - if(item) - { - if (get_is_item_worn(mUUID)) - { - if(item->getType() != LLAssetType::AT_BODYPART) - { - LLAppearanceMgr::instance().removeItemFromAvatar(item->getUUID()); - } - } - else - { - LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true); - } - } -} - -class LLSettingsBridgeAction - : public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - virtual void doIt() - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLSettingsType::type_e type = item->getSettingsType(); - switch (type) - { - case LLSettingsType::ST_SKY: - LLFloaterReg::showInstance("env_fixed_environmentent_sky", LLSDMap("inventory_id", item->getUUID()), TAKE_FOCUS_YES); - break; - case LLSettingsType::ST_WATER: - LLFloaterReg::showInstance("env_fixed_environmentent_water", LLSDMap("inventory_id", item->getUUID()), TAKE_FOCUS_YES); - break; - case LLSettingsType::ST_DAYCYCLE: - LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("inventory_id", item->getUUID())("edit_context", "inventory"), TAKE_FOCUS_YES); - break; - default: - break; - } - } - LLInvFVBridgeAction::doIt(); - } - virtual ~LLSettingsBridgeAction(){} -protected: - LLSettingsBridgeAction(const LLUUID& id, LLInventoryModel* model) : LLInvFVBridgeAction(id, model) {} -}; - -class LLMaterialBridgeAction : public LLInvFVBridgeAction -{ - friend class LLInvFVBridgeAction; -public: - void doIt() override - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("material_editor", LLSD(item->getUUID()), TAKE_FOCUS_YES); - } - LLInvFVBridgeAction::doIt(); - } - ~LLMaterialBridgeAction() = default; -private: - LLMaterialBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} -}; - - -LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, - const LLUUID& uuid, - LLInventoryModel* model) -{ - LLInvFVBridgeAction* action = NULL; - switch(asset_type) - { - case LLAssetType::AT_TEXTURE: - action = new LLTextureBridgeAction(uuid,model); - break; - case LLAssetType::AT_SOUND: - action = new LLSoundBridgeAction(uuid,model); - break; - case LLAssetType::AT_LANDMARK: - action = new LLLandmarkBridgeAction(uuid,model); - break; - case LLAssetType::AT_CALLINGCARD: - action = new LLCallingCardBridgeAction(uuid,model); - break; - case LLAssetType::AT_OBJECT: - action = new LLObjectBridgeAction(uuid,model); - break; - case LLAssetType::AT_NOTECARD: - action = new LLNotecardBridgeAction(uuid,model); - break; - case LLAssetType::AT_ANIMATION: - action = new LLAnimationBridgeAction(uuid,model); - break; - case LLAssetType::AT_GESTURE: - action = new LLGestureBridgeAction(uuid,model); - break; - case LLAssetType::AT_LSL_TEXT: - action = new LLLSLTextBridgeAction(uuid,model); - break; - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - action = new LLWearableBridgeAction(uuid,model); - break; - case LLAssetType::AT_SETTINGS: - action = new LLSettingsBridgeAction(uuid, model); - break; - case LLAssetType::AT_MATERIAL: - action = new LLMaterialBridgeAction(uuid, model); - break; - default: - break; - } - return action; -} - -/** Bridge Actions - ** - ********************************************************************************/ - -/************************************************************************/ -/* Recent Inventory Panel related classes */ -/************************************************************************/ -void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - menuentry_vec_t disabled_items, items; - buildContextMenuOptions(flags, items, disabled_items); - - 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, - LLFolderViewModelInventory* view_model, - LLFolderView* root, - const LLUUID& uuid, - U32 flags /*= 0x00*/ ) const -{ - LLInvFVBridge* new_listener = NULL; - if (asset_type == LLAssetType::AT_CATEGORY - && actual_asset_type != LLAssetType::AT_LINK_FOLDER) - { - new_listener = new LLRecentItemsFolderBridge(inv_type, inventory, root, uuid); - } - else - { - new_listener = LLInventoryFolderViewModelBuilder::createBridge(asset_type, - actual_asset_type, - inv_type, - inventory, - view_model, - root, - uuid, - flags); - } - return new_listener; -} - -LLFolderViewGroupedItemBridge::LLFolderViewGroupedItemBridge() -{ -} - -void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu) -{ - uuid_vec_t ids; - menuentry_vec_t disabled_items; - if (get_selection_item_uuids(selected_items, ids)) - { - if (!LLAppearanceMgr::instance().canAddWearables(ids) && canWearSelected(ids)) - { - 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")); - } - } - disable_context_entries_if_present(menu, disabled_items); -} - -bool LLFolderViewGroupedItemBridge::canWearSelected(const uuid_vec_t& item_ids) const -{ - for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) - { - const LLViewerInventoryItem* item = gInventory.getItem(*it); - if (!item || (item->getType() >= LLAssetType::AT_COUNT) || (item->getType() <= LLAssetType::AT_NONE)) - { - return false; - } - } - return true; -} -// EOF +/**
+ * @file llinventorybridge.cpp
+ * @brief Implementation of the Inventory-Folder-View-Bridge classes.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llinventorybridge.h"
+
+// external projects
+#include "lltransfersourceasset.h"
+#include "llavatarnamecache.h" // IDEVO
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llagentwearables.h"
+#include "llappearancemgr.h"
+#include "llattachmentsmgr.h"
+#include "llavataractions.h"
+#include "llfavoritesbar.h" // management of favorites folder
+#include "llfloateropenobject.h"
+#include "llfloaterreg.h"
+#include "llfloatermarketplacelistings.h"
+#include "llfloatersidepanelcontainer.h"
+#include "llsidepanelinventory.h"
+#include "llfloaterworldmap.h"
+#include "llfolderview.h"
+#include "llfriendcard.h"
+#include "llgesturemgr.h"
+#include "llgiveinventory.h"
+#include "llfloaterimcontainer.h"
+#include "llimview.h"
+#include "llclipboard.h"
+#include "llinventorydefines.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryicon.h"
+#include "llinventorymodel.h"
+#include "llinventorymodelbackgroundfetch.h"
+#include "llinventorypanel.h"
+#include "llmarketplacefunctions.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llpreviewanim.h"
+#include "llpreviewgesture.h"
+#include "llpreviewtexture.h"
+#include "llselectmgr.h"
+#include "llsidepanelappearance.h"
+#include "lltooldraganddrop.h"
+#include "lltrans.h"
+#include "llurlaction.h"
+#include "llviewerassettype.h"
+#include "llviewerfoldertype.h"
+#include "llviewermenu.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+#include "llwearablelist.h"
+#include "llwearableitemslist.h"
+#include "lllandmarkactions.h"
+#include "llpanellandmarks.h"
+#include "llviewerparcelmgr.h"
+#include "llparcel.h"
+
+#include "llenvironment.h"
+
+#include <boost/shared_ptr.hpp>
+
+void copy_slurl_to_clipboard_callback_inv(const std::string& slurl);
+
+const F32 SOUND_GAIN = 1.0f;
+const F32 FOLDER_LOADING_MESSAGE_DELAY = 0.5f; // Seconds to wait before showing the LOADING... text in folder views
+
+using namespace LLOldEvents;
+
+// Function declarations
+bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
+void teleport_via_landmark(const LLUUID& asset_id);
+static bool check_category(LLInventoryModel* model,
+ const LLUUID& cat_id,
+ LLInventoryPanel* active_panel,
+ LLInventoryFilter* filter);
+static bool check_item(const LLUUID& item_id,
+ LLInventoryPanel* active_panel,
+ LLInventoryFilter* filter);
+
+// Helper functions
+
+bool isAddAction(const std::string& action)
+{
+ return ("wear" == action || "attach" == action || "activate" == action);
+}
+
+bool isRemoveAction(const std::string& action)
+{
+ return ("take_off" == action || "detach" == action);
+}
+
+bool isMarketplaceSendAction(const std::string& action)
+{
+ return ("send_to_marketplace" == action);
+}
+
+bool isPanelActive(const std::string& panel_name)
+{
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(false);
+ return (active_panel && (active_panel->getName() == panel_name));
+}
+
+// Used by LLFolderBridge as callback for directory fetching recursion
+class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
+{
+public:
+ LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) {}
+ ~LLRightClickInventoryFetchDescendentsObserver() {}
+ virtual void execute(bool clear_observer = false);
+ virtual void done()
+ {
+ execute(true);
+ }
+};
+
+// Used by LLFolderBridge as callback for directory content items fetching
+class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver
+{
+public:
+ LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : LLInventoryFetchItemsObserver(ids) { };
+ ~LLRightClickInventoryFetchObserver() {}
+ void execute(bool clear_observer = false)
+ {
+ if (clear_observer)
+ {
+ gInventory.removeObserver(this);
+ delete this;
+ }
+ // we've downloaded all the items, so repaint the dialog
+ LLFolderBridge::staticFolderOptionsMenu();
+ }
+ virtual void done()
+ {
+ execute(true);
+ }
+};
+
+class LLPasteIntoFolderCallback: public LLInventoryCallback
+{
+public:
+ LLPasteIntoFolderCallback(LLHandle<LLInventoryPanel>& handle)
+ : mInventoryPanel(handle)
+ {
+ }
+ ~LLPasteIntoFolderCallback()
+ {
+ processItems();
+ }
+
+ void fire(const LLUUID& inv_item)
+ {
+ mChangedIds.push_back(inv_item);
+ }
+
+ void processItems()
+ {
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ bool has_elements = false;
+ for (LLUUID& inv_item : mChangedIds)
+ {
+ LLInventoryItem* item = gInventory.getItem(inv_item);
+ if (item && panel)
+ {
+ LLUUID root_id = panel->getRootFolderID();
+
+ if (inv_item == root_id)
+ {
+ return;
+ }
+
+ LLFolderViewItem* item = panel->getItemByID(inv_item);
+ if (item)
+ {
+ if (!has_elements)
+ {
+ panel->clearSelection();
+ panel->getRootFolder()->clearSelection();
+ panel->getRootFolder()->requestArrange();
+ panel->getRootFolder()->update();
+ has_elements = true;
+ }
+ panel->getRootFolder()->changeSelection(item, true);
+ }
+ }
+ }
+
+ if (has_elements)
+ {
+ panel->getRootFolder()->scrollToShowSelection();
+ }
+ }
+private:
+ LLHandle<LLInventoryPanel> mInventoryPanel;
+ std::vector<LLUUID> mChangedIds;
+};
+
+// +=================================================+
+// | LLInvFVBridge |
+// +=================================================+
+
+LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+ mUUID(uuid),
+ mRoot(root),
+ mInvType(LLInventoryType::IT_NONE),
+ mIsLink(false),
+ LLFolderViewModelItemInventory(inventory->getRootViewModel())
+{
+ mInventoryPanel = inventory->getInventoryPanelHandle();
+ const LLInventoryObject* obj = getInventoryObject();
+ mIsLink = obj && obj->getIsLinkType();
+}
+
+const std::string& LLInvFVBridge::getName() const
+{
+ const LLInventoryObject* obj = getInventoryObject();
+ if(obj)
+ {
+ return obj->getName();
+ }
+ return LLStringUtil::null;
+}
+
+const std::string& LLInvFVBridge::getDisplayName() const
+{
+ if(mDisplayName.empty())
+ {
+ buildDisplayName();
+ }
+ return mDisplayName;
+}
+
+std::string LLInvFVBridge::getSearchableDescription() const
+{
+ return get_searchable_description(getInventoryModel(), mUUID);
+}
+
+std::string LLInvFVBridge::getSearchableCreatorName() const
+{
+ return get_searchable_creator_name(getInventoryModel(), mUUID);
+}
+
+std::string LLInvFVBridge::getSearchableUUIDString() const
+{
+ return get_searchable_UUID(getInventoryModel(), mUUID);
+}
+
+// Folders have full perms
+PermissionMask LLInvFVBridge::getPermissionMask() const
+{
+ return PERM_ALL;
+}
+
+// virtual
+LLFolderType::EType LLInvFVBridge::getPreferredType() const
+{
+ return LLFolderType::FT_NONE;
+}
+
+
+// Folders don't have creation dates.
+time_t LLInvFVBridge::getCreationDate() const
+{
+ LLInventoryObject* objectp = getInventoryObject();
+ if (objectp)
+ {
+ return objectp->getCreationDate();
+ }
+ return (time_t)0;
+}
+
+void LLInvFVBridge::setCreationDate(time_t creation_date_utc)
+{
+ LLInventoryObject* objectp = getInventoryObject();
+ if (objectp)
+ {
+ objectp->setCreationDate(creation_date_utc);
+ }
+}
+
+
+// Can be destroyed (or moved to trash)
+bool LLInvFVBridge::isItemRemovable(bool check_worn) const
+{
+ return get_is_item_removable(getInventoryModel(), mUUID, check_worn);
+}
+
+// Can be moved to another folder
+bool LLInvFVBridge::isItemMovable() const
+{
+ return true;
+}
+
+bool LLInvFVBridge::isLink() const
+{
+ return mIsLink;
+}
+
+bool LLInvFVBridge::isLibraryItem() const
+{
+ return gInventory.isObjectDescendentOf(getUUID(),gInventory.getLibraryRootFolderID());
+}
+
+/*virtual*/
+/**
+ * @brief Adds this item into clipboard storage
+ */
+bool LLInvFVBridge::cutToClipboard()
+{
+ const LLInventoryObject* obj = gInventory.getObject(mUUID);
+ if (obj && isItemMovable() && isItemRemovable())
+ {
+ const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const bool cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id);
+
+ if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) ||
+ LLMarketplaceData::instance().isListedAndActive(mUUID)))
+ {
+ LLUUID parent_uuid = obj->getParentUUID();
+ bool result = perform_cutToClipboard();
+ gInventory.addChangedMask(LLInventoryObserver::STRUCTURE, parent_uuid);
+ return result;
+ }
+ else
+ {
+ // Otherwise just perform the cut
+ return perform_cutToClipboard();
+ }
+ }
+ return false;
+}
+
+// virtual
+bool LLInvFVBridge::isCutToClipboard()
+{
+ if (LLClipboard::instance().isCutMode())
+ {
+ return LLClipboard::instance().isOnClipboard(mUUID);
+ }
+ return false;
+}
+
+// Callback for cutToClipboard if DAMA required...
+bool LLInvFVBridge::callback_cutToClipboard(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0) // YES
+ {
+ return perform_cutToClipboard();
+ }
+ return false;
+}
+
+bool LLInvFVBridge::perform_cutToClipboard()
+{
+ const LLInventoryObject* obj = gInventory.getObject(mUUID);
+ if (obj && isItemMovable() && isItemRemovable())
+ {
+ LLClipboard::instance().setCutMode(true);
+ return LLClipboard::instance().addToClipboard(mUUID);
+ }
+ return false;
+}
+
+bool LLInvFVBridge::copyToClipboard() const
+{
+ const LLInventoryObject* obj = gInventory.getObject(mUUID);
+ if (obj && isItemCopyable())
+ {
+ return LLClipboard::instance().addToClipboard(mUUID);
+ }
+ return false;
+}
+
+void LLInvFVBridge::showProperties()
+{
+ if (isMarketplaceListingsFolder())
+ {
+ LLFloaterReg::showInstance("item_properties", LLSD().with("id",mUUID),true);
+ // Force it to show on top as this floater has a tendency to hide when confirmation dialog shows up
+ LLFloater* floater_properties = LLFloaterReg::findInstance("item_properties", LLSD().with("id",mUUID));
+ if (floater_properties)
+ {
+ floater_properties->setVisibleAndFrontmost();
+ }
+ }
+ else
+ {
+ show_item_profile(mUUID);
+ }
+}
+
+void LLInvFVBridge::navigateToFolder(bool new_window, bool change_mode)
+{
+ if(new_window)
+ {
+ mInventoryPanel.get()->openSingleViewInventory(mUUID);
+ }
+ else
+ {
+ if(change_mode)
+ {
+ LLInventoryPanel::setSFViewAndOpenFolder(mInventoryPanel.get(), mUUID);
+ }
+ else
+ {
+ LLInventorySingleFolderPanel* panel = dynamic_cast<LLInventorySingleFolderPanel*>(mInventoryPanel.get());
+ if (!panel || !getInventoryModel() || mUUID.isNull())
+ {
+ return;
+ }
+
+ panel->changeFolderRoot(mUUID);
+ }
+
+ }
+}
+
+void LLInvFVBridge::removeBatch(std::vector<LLFolderViewModelItem*>& batch)
+{
+ // Deactivate gestures when moving them into Trash
+ LLInvFVBridge* bridge;
+ LLInventoryModel* model = getInventoryModel();
+ LLViewerInventoryItem* item = NULL;
+ LLViewerInventoryCategory* cat = NULL;
+ LLInventoryModel::cat_array_t descendent_categories;
+ LLInventoryModel::item_array_t descendent_items;
+ S32 count = batch.size();
+ S32 i,j;
+ for(i = 0; i < count; ++i)
+ {
+ bridge = (LLInvFVBridge*)(batch[i]);
+ if(!bridge || !bridge->isItemRemovable()) continue;
+ item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
+ if (item)
+ {
+ if(LLAssetType::AT_GESTURE == item->getType())
+ {
+ LLGestureMgr::instance().deactivateGesture(item->getUUID());
+ }
+ }
+ }
+ for(i = 0; i < count; ++i)
+ {
+ bridge = (LLInvFVBridge*)(batch[i]);
+ if(!bridge || !bridge->isItemRemovable()) continue;
+ cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
+ if (cat)
+ {
+ gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, false );
+ for (j=0; j<descendent_items.size(); j++)
+ {
+ if(LLAssetType::AT_GESTURE == descendent_items[j]->getType())
+ {
+ LLGestureMgr::instance().deactivateGesture(descendent_items[j]->getUUID());
+ }
+ }
+ }
+ }
+ removeBatchNoCheck(batch);
+ model->checkTrashOverflow();
+}
+
+void LLInvFVBridge::removeBatchNoCheck(std::vector<LLFolderViewModelItem*>& batch)
+{
+ // this method moves a bunch of items and folders to the trash. As
+ // per design guidelines for the inventory model, the message is
+ // built and the accounting is performed first. After all of that,
+ // we call LLInventoryModel::moveObject() to move everything
+ // around.
+ LLInvFVBridge* bridge;
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return;
+ LLMessageSystem* msg = gMessageSystem;
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ LLViewerInventoryItem* item = NULL;
+ uuid_vec_t move_ids;
+ LLInventoryModel::update_map_t update;
+ bool start_new_message = true;
+ S32 count = batch.size();
+ S32 i;
+
+ // first, hide any 'preview' floaters that correspond to the items
+ // being deleted.
+ for(i = 0; i < count; ++i)
+ {
+ bridge = (LLInvFVBridge*)(batch[i]);
+ if(!bridge || !bridge->isItemRemovable()) continue;
+ item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
+ if(item)
+ {
+ LLPreview::hide(item->getUUID());
+ }
+ }
+
+ // do the inventory move to trash
+
+ for(i = 0; i < count; ++i)
+ {
+ bridge = (LLInvFVBridge*)(batch[i]);
+ if(!bridge || !bridge->isItemRemovable()) continue;
+ item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
+ if(item)
+ {
+ if(item->getParentUUID() == trash_id) continue;
+ move_ids.push_back(item->getUUID());
+ --update[item->getParentUUID()];
+ ++update[trash_id];
+ if(start_new_message)
+ {
+ start_new_message = false;
+ msg->newMessageFast(_PREHASH_MoveInventoryItem);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addBOOLFast(_PREHASH_Stamp, true);
+ }
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
+ msg->addUUIDFast(_PREHASH_FolderID, trash_id);
+ msg->addString("NewName", NULL);
+ if(msg->isSendFullFast(_PREHASH_InventoryData))
+ {
+ start_new_message = true;
+ gAgent.sendReliableMessage();
+ gInventory.accountForUpdate(update);
+ update.clear();
+ }
+ }
+ }
+ if(!start_new_message)
+ {
+ start_new_message = true;
+ gAgent.sendReliableMessage();
+ gInventory.accountForUpdate(update);
+ update.clear();
+ }
+
+ for(i = 0; i < count; ++i)
+ {
+ bridge = (LLInvFVBridge*)(batch[i]);
+ if(!bridge || !bridge->isItemRemovable()) continue;
+ LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
+ if(cat)
+ {
+ if(cat->getParentUUID() == trash_id) continue;
+ move_ids.push_back(cat->getUUID());
+ --update[cat->getParentUUID()];
+ ++update[trash_id];
+ if(start_new_message)
+ {
+ start_new_message = false;
+ msg->newMessageFast(_PREHASH_MoveInventoryFolder);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addBOOL("Stamp", true);
+ }
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID());
+ msg->addUUIDFast(_PREHASH_ParentID, trash_id);
+ if(msg->isSendFullFast(_PREHASH_InventoryData))
+ {
+ start_new_message = true;
+ gAgent.sendReliableMessage();
+ gInventory.accountForUpdate(update);
+ update.clear();
+ }
+ }
+ }
+ if(!start_new_message)
+ {
+ gAgent.sendReliableMessage();
+ gInventory.accountForUpdate(update);
+ }
+
+ // move everything.
+ uuid_vec_t::iterator it = move_ids.begin();
+ uuid_vec_t::iterator end = move_ids.end();
+ for(; it != end; ++it)
+ {
+ gInventory.moveObject((*it), trash_id);
+ LLViewerInventoryItem* item = gInventory.getItem(*it);
+ if (item)
+ {
+ model->updateItem(item);
+ }
+ }
+
+ // notify inventory observers.
+ model->notifyObservers();
+}
+
+bool LLInvFVBridge::isClipboardPasteable() const
+{
+ // Return false on degenerated cases: empty clipboard, no inventory, no agent
+ if (!LLClipboard::instance().hasContents() || !isAgentInventory())
+ {
+ return false;
+ }
+ LLInventoryModel* model = getInventoryModel();
+ if (!model)
+ {
+ return false;
+ }
+
+ // In cut mode, whatever is on the clipboard is always pastable
+ if (LLClipboard::instance().isCutMode())
+ {
+ return true;
+ }
+
+ // In normal mode, we need to check each element of the clipboard to know if we can paste or not
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ S32 count = objects.size();
+ for(S32 i = 0; i < count; i++)
+ {
+ const LLUUID &item_id = objects.at(i);
+
+ // Folders are pastable if all items in there are copyable
+ const LLInventoryCategory *cat = model->getCategory(item_id);
+ if (cat)
+ {
+ LLFolderBridge cat_br(mInventoryPanel.get(), mRoot, item_id);
+ if (!cat_br.isItemCopyable(false))
+ return false;
+ // Skip to the next item in the clipboard
+ continue;
+ }
+
+ // Each item must be copyable to be pastable
+ LLItemBridge item_br(mInventoryPanel.get(), mRoot, item_id);
+ if (!item_br.isItemCopyable(false))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LLInvFVBridge::isClipboardPasteableAsLink() const
+{
+ if (!LLClipboard::instance().hasContents() || !isAgentInventory())
+ {
+ return false;
+ }
+ const LLInventoryModel* model = getInventoryModel();
+ if (!model)
+ {
+ return false;
+ }
+
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ S32 count = objects.size();
+ for(S32 i = 0; i < count; i++)
+ {
+ const LLInventoryItem *item = model->getItem(objects.at(i));
+ if (item)
+ {
+ if (!LLAssetType::lookupCanLink(item->getActualType()))
+ {
+ return false;
+ }
+
+ if (gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getLibraryRootFolderID()))
+ {
+ return false;
+ }
+ }
+ const LLViewerInventoryCategory *cat = model->getCategory(objects.at(i));
+ if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void disable_context_entries_if_present(LLMenuGL& menu,
+ const menuentry_vec_t &disabled_entries)
+{
+ const LLView::child_list_t *list = menu.getChildList();
+ for (LLView::child_list_t::const_iterator itor = list->begin();
+ itor != list->end();
+ ++itor)
+ {
+ LLView *menu_item = (*itor);
+ std::string name = menu_item->getName();
+
+ // descend into split menus:
+ LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item);
+ if ((name == "More") && branchp)
+ {
+ disable_context_entries_if_present(*branchp->getBranch(), disabled_entries);
+ }
+
+ bool found = false;
+ menuentry_vec_t::const_iterator itor2;
+ for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2)
+ {
+ if (*itor2 == name)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ 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);
+
+ menu_item->setEnabled(false);
+ }
+ }
+}
+void hide_context_entries(LLMenuGL& menu,
+ const menuentry_vec_t &entries_to_show,
+ const menuentry_vec_t &disabled_entries)
+{
+ const LLView::child_list_t *list = menu.getChildList();
+
+ // For removing double separators or leading separator. Start at true so that
+ // if the first element is a separator, it will not be shown.
+ bool is_previous_entry_separator = true;
+
+ for (LLView::child_list_t::const_iterator itor = list->begin();
+ itor != list->end();
+ ++itor)
+ {
+ LLView *menu_item = (*itor);
+ std::string name = menu_item->getName();
+
+ // descend into split menus:
+ LLMenuItemBranchGL* branchp = dynamic_cast<LLMenuItemBranchGL*>(menu_item);
+ if (((name == "More") || (name == "create_new")) && branchp)
+ {
+ hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries);
+ }
+
+ bool found = false;
+
+ menuentry_vec_t::const_iterator itor2 = std::find(entries_to_show.begin(), entries_to_show.end(), name);
+ if (itor2 != entries_to_show.end())
+ {
+ found = true;
+ }
+
+ // Don't allow multiple separators in a row (e.g. such as if there are no items
+ // between two separators).
+ if (found)
+ {
+ const bool is_entry_separator = (dynamic_cast<LLMenuItemSeparatorGL *>(menu_item) != NULL);
+ found = !(is_entry_separator && is_previous_entry_separator);
+ is_previous_entry_separator = is_entry_separator;
+ }
+
+ if (!found)
+ {
+ if (!menu_item->getLastVisible())
+ {
+ menu_item->setVisible(false);
+ }
+
+ if (menu_item->getEnabled())
+ {
+ // These should stay enabled unless specifically disabled
+ const menuentry_vec_t exceptions = {
+ "Detach From Yourself",
+ "Wearable And Object Wear",
+ "Wearable Add",
+ };
+
+ menuentry_vec_t::const_iterator itor2 = std::find(exceptions.begin(), exceptions.end(), name);
+ if (itor2 == exceptions.end())
+ {
+ menu_item->setEnabled(false);
+ }
+ }
+ }
+ else
+ {
+ 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);
+
+ bool enabled = true;
+ for (itor2 = disabled_entries.begin(); enabled && (itor2 != disabled_entries.end()); ++itor2)
+ {
+ enabled &= (*itor2 != name);
+ }
+
+ menu_item->setEnabled(enabled);
+ }
+ }
+}
+
+// Helper for commonly-used entries
+void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
+ menuentry_vec_t &items,
+ menuentry_vec_t &disabled_items, U32 flags)
+{
+ const LLInventoryObject *obj = getInventoryObject();
+ bool single_folder_root = (mRoot == NULL);
+
+ if (obj)
+ {
+
+ if (obj->getType() != LLAssetType::AT_CATEGORY)
+ {
+ items.push_back(std::string("Copy Separator"));
+ }
+ items.push_back(std::string("Copy"));
+ if (!isItemCopyable())
+ {
+ disabled_items.push_back(std::string("Copy"));
+ }
+
+ if (isAgentInventory() && !single_folder_root)
+ {
+ items.push_back(std::string("New folder from selected"));
+ items.push_back(std::string("Subfolder Separator"));
+ std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs();
+ uuid_vec_t ids;
+ std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids));
+ if (!is_only_items_selected(ids) && !is_only_cats_selected(ids))
+ {
+ disabled_items.push_back(std::string("New folder from selected"));
+ }
+ }
+
+ if (obj->getIsLinkType())
+ {
+ items.push_back(std::string("Find Original"));
+ if (isLinkedObjectMissing())
+ {
+ disabled_items.push_back(std::string("Find Original"));
+ }
+
+ items.push_back(std::string("Cut"));
+ if (!isItemMovable() || !canMenuCut())
+ {
+ disabled_items.push_back(std::string("Cut"));
+ }
+ }
+ else
+ {
+ if (LLAssetType::lookupCanLink(obj->getType()))
+ {
+ items.push_back(std::string("Find Links"));
+ }
+
+ if (!isInboxFolder() && !single_folder_root)
+ {
+ items.push_back(std::string("Rename"));
+ if (!isItemRenameable() || ((flags & FIRST_SELECTED_ITEM) == 0))
+ {
+ disabled_items.push_back(std::string("Rename"));
+ }
+ }
+
+ items.push_back(std::string("thumbnail"));
+ if (isLibraryItem())
+ {
+ disabled_items.push_back(std::string("thumbnail"));
+ }
+
+ LLViewerInventoryItem *inv_item = gInventory.getItem(mUUID);
+ if (show_asset_id)
+ {
+ items.push_back(std::string("Copy Asset UUID"));
+
+ bool is_asset_knowable = false;
+
+ if (inv_item)
+ {
+ is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(inv_item->getType());
+ }
+ if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308
+ || (! ( isItemPermissive() || gAgent.isGodlike() ) )
+ || (flags & FIRST_SELECTED_ITEM) == 0)
+ {
+ disabled_items.push_back(std::string("Copy Asset UUID"));
+ }
+ }
+
+ if(!single_folder_root)
+ {
+ items.push_back(std::string("Cut"));
+ if (!isItemMovable() || !canMenuCut())
+ {
+ disabled_items.push_back(std::string("Cut"));
+ }
+
+ if (canListOnMarketplace() && !isMarketplaceListingsFolder() && !isInboxFolder())
+ {
+ items.push_back(std::string("Marketplace Separator"));
+
+ if (gMenuHolder->getChild<LLView>("MarketplaceListings")->getVisible())
+ {
+ items.push_back(std::string("Marketplace Copy"));
+ items.push_back(std::string("Marketplace Move"));
+ if (!canListOnMarketplaceNow())
+ {
+ disabled_items.push_back(std::string("Marketplace Copy"));
+ disabled_items.push_back(std::string("Marketplace Move"));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Don't allow items to be pasted directly into the COF or the inbox
+ if (!isCOFFolder() && !isInboxFolder())
+ {
+ items.push_back(std::string("Paste"));
+ }
+ if (!isClipboardPasteable() || ((flags & FIRST_SELECTED_ITEM) == 0))
+ {
+ disabled_items.push_back(std::string("Paste"));
+ }
+
+ static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);
+ if (inventory_linking)
+ {
+ items.push_back(std::string("Paste As Link"));
+ if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0)
+ {
+ disabled_items.push_back(std::string("Paste As Link"));
+ }
+ }
+
+ if (obj->getType() != LLAssetType::AT_CATEGORY)
+ {
+ items.push_back(std::string("Paste Separator"));
+ }
+
+ if(!single_folder_root)
+ {
+ addDeleteContextMenuOptions(items, disabled_items);
+ }
+
+ if (!isPanelActive("All Items") && !isPanelActive("comb_single_folder_inv"))
+ {
+ items.push_back(std::string("Show in Main Panel"));
+ }
+}
+
+void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLInvFVBridge::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+
+ addOpenRightClickMenuOption(items);
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+bool get_selection_item_uuids(LLFolderView::selected_items_t& selected_items, uuid_vec_t& ids)
+{
+ uuid_vec_t results;
+ S32 non_item = 0;
+ for(LLFolderView::selected_items_t::iterator it = selected_items.begin(); it != selected_items.end(); ++it)
+ {
+ LLItemBridge *view_model = dynamic_cast<LLItemBridge *>((*it)->getViewModelItem());
+
+ if(view_model && view_model->getUUID().notNull())
+ {
+ results.push_back(view_model->getUUID());
+ }
+ else
+ {
+ non_item++;
+ }
+ }
+ if (non_item == 0)
+ {
+ ids = results;
+ return true;
+ }
+ return false;
+}
+
+void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items,
+ menuentry_vec_t &disabled_items)
+{
+ const LLInventoryObject *obj = getInventoryObject();
+ if (obj && obj->getIsLinkType())
+ {
+ items.push_back(std::string("Find Original"));
+ if (isLinkedObjectMissing())
+ {
+ disabled_items.push_back(std::string("Find Original"));
+ }
+ }
+ items.push_back(std::string("Purge Item"));
+ if (!isItemRemovable())
+ {
+ disabled_items.push_back(std::string("Purge Item"));
+ }
+ items.push_back(std::string("Restore Item"));
+}
+
+void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
+ menuentry_vec_t &disabled_items)
+{
+
+ const LLInventoryObject *obj = getInventoryObject();
+
+ // Don't allow delete as a direct option from COF folder.
+ if (obj && obj->getIsLinkType() && isCOFFolder() && get_is_item_worn(mUUID))
+ {
+ return;
+ }
+
+ items.push_back(std::string("Delete"));
+
+ if (isPanelActive("Favorite Items") || !canMenuDelete())
+ {
+ disabled_items.push_back(std::string("Delete"));
+ }
+}
+
+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"));
+}
+
+void LLInvFVBridge::addMarketplaceContextMenuOptions(U32 flags,
+ menuentry_vec_t &items,
+ menuentry_vec_t &disabled_items)
+{
+ S32 depth = depth_nesting_in_marketplace(mUUID);
+ if (depth == 1)
+ {
+ // Options available at the Listing Folder level
+ items.push_back(std::string("Marketplace Create Listing"));
+ items.push_back(std::string("Marketplace Associate Listing"));
+ items.push_back(std::string("Marketplace Check Listing"));
+ items.push_back(std::string("Marketplace List"));
+ items.push_back(std::string("Marketplace Unlist"));
+ if (LLMarketplaceData::instance().isUpdating(mUUID,depth) || ((flags & FIRST_SELECTED_ITEM) == 0))
+ {
+ // During SLM update, disable all marketplace related options
+ // Also disable all if multiple selected items
+ disabled_items.push_back(std::string("Marketplace Create Listing"));
+ disabled_items.push_back(std::string("Marketplace Associate Listing"));
+ disabled_items.push_back(std::string("Marketplace Check Listing"));
+ disabled_items.push_back(std::string("Marketplace List"));
+ disabled_items.push_back(std::string("Marketplace Unlist"));
+ }
+ else
+ {
+ if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
+ {
+ items.push_back(std::string("Marketplace Get Listing"));
+ }
+ if (LLMarketplaceData::instance().isListed(mUUID))
+ {
+ disabled_items.push_back(std::string("Marketplace Create Listing"));
+ disabled_items.push_back(std::string("Marketplace Associate Listing"));
+ if (LLMarketplaceData::instance().getVersionFolder(mUUID).isNull())
+ {
+ disabled_items.push_back(std::string("Marketplace List"));
+ disabled_items.push_back(std::string("Marketplace Unlist"));
+ }
+ else
+ {
+ if (LLMarketplaceData::instance().getActivationState(mUUID))
+ {
+ disabled_items.push_back(std::string("Marketplace List"));
+ }
+ else
+ {
+ disabled_items.push_back(std::string("Marketplace Unlist"));
+ }
+ }
+ }
+ else
+ {
+ disabled_items.push_back(std::string("Marketplace List"));
+ disabled_items.push_back(std::string("Marketplace Unlist"));
+ if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
+ {
+ disabled_items.push_back(std::string("Marketplace Get Listing"));
+ }
+ }
+ }
+ }
+ if (depth == 2)
+ {
+ // Options available at the Version Folder levels and only for folders
+ LLInventoryCategory* cat = gInventory.getCategory(mUUID);
+ if (cat && LLMarketplaceData::instance().isListed(cat->getParentUUID()))
+ {
+ items.push_back(std::string("Marketplace Activate"));
+ items.push_back(std::string("Marketplace Deactivate"));
+ if (LLMarketplaceData::instance().isUpdating(mUUID,depth) || ((flags & FIRST_SELECTED_ITEM) == 0))
+ {
+ // During SLM update, disable all marketplace related options
+ // Also disable all if multiple selected items
+ disabled_items.push_back(std::string("Marketplace Activate"));
+ disabled_items.push_back(std::string("Marketplace Deactivate"));
+ }
+ else
+ {
+ if (LLMarketplaceData::instance().isVersionFolder(mUUID))
+ {
+ disabled_items.push_back(std::string("Marketplace Activate"));
+ if (LLMarketplaceData::instance().getActivationState(mUUID))
+ {
+ disabled_items.push_back(std::string("Marketplace Deactivate"));
+ }
+ }
+ else
+ {
+ disabled_items.push_back(std::string("Marketplace Deactivate"));
+ }
+ }
+ }
+ }
+
+ items.push_back(std::string("Marketplace Edit Listing"));
+ LLUUID listing_folder_id = nested_parent_id(mUUID,depth);
+ LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(listing_folder_id);
+
+ if (depth >= 2)
+ {
+ // Prevent creation of new folders if the max count has been reached on this version folder (active or not)
+ LLUUID local_version_folder_id = nested_parent_id(mUUID,depth-1);
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+ gInventory.collectDescendents(local_version_folder_id, categories, items, false);
+ LLCachedControl<U32> max_depth(gSavedSettings, "InventoryOutboxMaxFolderDepth", 4);
+ LLCachedControl<U32> max_count(gSavedSettings, "InventoryOutboxMaxFolderCount", 20);
+ if (categories.size() >= max_count
+ || depth > (max_depth + 1))
+ {
+ disabled_items.push_back(std::string("New Folder"));
+ }
+ }
+
+ // Options available at all levels on items and categories
+ if (!LLMarketplaceData::instance().isListed(listing_folder_id) || version_folder_id.isNull())
+ {
+ disabled_items.push_back(std::string("Marketplace Edit Listing"));
+ }
+
+ // Separator
+ items.push_back(std::string("Marketplace Listings Separator"));
+}
+
+void LLInvFVBridge::addLinkReplaceMenuOption(menuentry_vec_t& items, menuentry_vec_t& disabled_items)
+{
+ const LLInventoryObject* obj = getInventoryObject();
+
+ if (isAgentInventory() && obj && obj->getType() != LLAssetType::AT_CATEGORY && obj->getType() != LLAssetType::AT_LINK_FOLDER)
+ {
+ items.push_back(std::string("Replace Links"));
+
+ if (mRoot->getSelectedCount() != 1)
+ {
+ disabled_items.push_back(std::string("Replace Links"));
+ }
+ }
+}
+
+bool LLInvFVBridge::canMenuDelete()
+{
+ return isItemRemovable(false);
+}
+
+bool LLInvFVBridge::canMenuCut()
+{
+ return isItemRemovable(true);
+}
+
+// *TODO: remove this
+bool LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
+{
+ bool rv = false;
+
+ const LLInventoryObject* obj = getInventoryObject();
+
+ if(obj)
+ {
+ *type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
+ if(*type == DAD_NONE)
+ {
+ return false;
+ }
+
+ *id = obj->getUUID();
+ //object_ids.push_back(obj->getUUID());
+
+ if (*type == DAD_CATEGORY)
+ {
+ LLInventoryModelBackgroundFetch::instance().start(obj->getUUID());
+ }
+
+ rv = true;
+ }
+
+ return rv;
+}
+
+LLInventoryObject* LLInvFVBridge::getInventoryObject() const
+{
+ LLInventoryObject* obj = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ obj = (LLInventoryObject*)model->getObject(mUUID);
+ }
+ return obj;
+}
+
+LLInventoryModel* LLInvFVBridge::getInventoryModel() const
+{
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ return panel ? panel->getModel() : NULL;
+}
+
+LLInventoryFilter* LLInvFVBridge::getInventoryFilter() const
+{
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ return panel ? &(panel->getFilter()) : NULL;
+}
+
+bool LLInvFVBridge::isItemInTrash() const
+{
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ return model->isObjectDescendentOf(mUUID, trash_id);
+}
+
+bool LLInvFVBridge::isLinkedObjectInTrash() const
+{
+ if (isItemInTrash()) return true;
+
+ const LLInventoryObject *obj = getInventoryObject();
+ if (obj && obj->getIsLinkType())
+ {
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id);
+ }
+ return false;
+}
+
+bool LLInvFVBridge::isItemInOutfits() const
+{
+ const LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+
+ const LLUUID my_outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ return isCOFFolder() || (my_outfits_cat == mUUID) || model->isObjectDescendentOf(mUUID, my_outfits_cat);
+}
+
+bool LLInvFVBridge::isLinkedObjectMissing() const
+{
+ const LLInventoryObject *obj = getInventoryObject();
+ if (!obj)
+ {
+ return true;
+ }
+ if (obj->getIsLinkType() && LLAssetType::lookupIsLinkType(obj->getType()))
+ {
+ return true;
+ }
+ return false;
+}
+
+bool LLInvFVBridge::isAgentInventory() const
+{
+ const LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+ if(gInventory.getRootFolderID() == mUUID) return true;
+ return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
+}
+
+bool LLInvFVBridge::isCOFFolder() const
+{
+ return LLAppearanceMgr::instance().getIsInCOF(mUUID);
+}
+
+// *TODO : Suppress isInboxFolder() once Merchant Outbox is fully deprecated
+bool LLInvFVBridge::isInboxFolder() const
+{
+ const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
+
+ if (inbox_id.isNull())
+ {
+ return false;
+ }
+
+ return gInventory.isObjectDescendentOf(mUUID, inbox_id);
+}
+
+bool LLInvFVBridge::isMarketplaceListingsFolder() const
+{
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+
+ if (folder_id.isNull())
+ {
+ return false;
+ }
+
+ return gInventory.isObjectDescendentOf(mUUID, folder_id);
+}
+
+bool LLInvFVBridge::isItemPermissive() const
+{
+ return false;
+}
+
+// static
+void LLInvFVBridge::changeItemParent(LLInventoryModel* model,
+ LLViewerInventoryItem* item,
+ const LLUUID& new_parent_id,
+ bool restamp)
+{
+ model->changeItemParent(item, new_parent_id, restamp);
+}
+
+// static
+void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
+ LLViewerInventoryCategory* cat,
+ const LLUUID& new_parent_id,
+ bool restamp)
+{
+ model->changeCategoryParent(cat, new_parent_id, restamp);
+}
+
+LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
+ LLAssetType::EType actual_asset_type,
+ LLInventoryType::EType inv_type,
+ LLInventoryPanel* inventory,
+ LLFolderViewModelInventory* view_model,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags)
+{
+ LLInvFVBridge* new_listener = NULL;
+ switch(asset_type)
+ {
+ case LLAssetType::AT_TEXTURE:
+ if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLTextureBridge(inventory, root, uuid, inv_type);
+ break;
+
+ case LLAssetType::AT_SOUND:
+ if(!(inv_type == LLInventoryType::IT_SOUND))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLSoundBridge(inventory, root, uuid);
+ break;
+
+ case LLAssetType::AT_LANDMARK:
+ if(!(inv_type == LLInventoryType::IT_LANDMARK))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLLandmarkBridge(inventory, root, uuid, flags);
+ break;
+
+ case LLAssetType::AT_CALLINGCARD:
+ if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLCallingCardBridge(inventory, root, uuid);
+ break;
+
+ case LLAssetType::AT_SCRIPT:
+ if(!(inv_type == LLInventoryType::IT_LSL))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLItemBridge(inventory, root, uuid);
+ break;
+
+ case LLAssetType::AT_OBJECT:
+ if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLObjectBridge(inventory, root, uuid, inv_type, flags);
+ break;
+
+ case LLAssetType::AT_NOTECARD:
+ if(!(inv_type == LLInventoryType::IT_NOTECARD))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLNotecardBridge(inventory, root, uuid);
+ break;
+
+ case LLAssetType::AT_ANIMATION:
+ if(!(inv_type == LLInventoryType::IT_ANIMATION))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLAnimationBridge(inventory, root, uuid);
+ break;
+
+ case LLAssetType::AT_GESTURE:
+ if(!(inv_type == LLInventoryType::IT_GESTURE))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLGestureBridge(inventory, root, uuid);
+ break;
+
+ case LLAssetType::AT_LSL_TEXT:
+ if(!(inv_type == LLInventoryType::IT_LSL))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLLSLTextBridge(inventory, root, uuid);
+ break;
+
+ case LLAssetType::AT_CLOTHING:
+ case LLAssetType::AT_BODYPART:
+ if(!(inv_type == LLInventoryType::IT_WEARABLE))
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, LLWearableType::inventoryFlagsToWearableType(flags));
+ break;
+ case LLAssetType::AT_CATEGORY:
+ if (actual_asset_type == LLAssetType::AT_LINK_FOLDER)
+ {
+ // Create a link folder handler instead
+ new_listener = new LLLinkFolderBridge(inventory, root, uuid);
+ }
+ else if (actual_asset_type == LLAssetType::AT_MARKETPLACE_FOLDER)
+ {
+ // Create a marketplace folder handler
+ new_listener = new LLMarketplaceFolderBridge(inventory, root, uuid);
+ }
+ else
+ {
+ new_listener = new LLFolderBridge(inventory, root, uuid);
+ }
+ break;
+ case LLAssetType::AT_LINK:
+ case LLAssetType::AT_LINK_FOLDER:
+ // Only should happen for broken links.
+ new_listener = new LLLinkItemBridge(inventory, root, uuid);
+ break;
+ case LLAssetType::AT_UNKNOWN:
+ new_listener = new LLUnknownItemBridge(inventory, root, uuid);
+ break;
+ case LLAssetType::AT_IMAGE_TGA:
+ case LLAssetType::AT_IMAGE_JPEG:
+ //LL_WARNS() << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << LL_ENDL;
+ break;
+
+ case LLAssetType::AT_SETTINGS:
+ if (inv_type != LLInventoryType::IT_SETTINGS)
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLSettingsBridge(inventory, root, uuid, LLSettingsType::fromInventoryFlags(flags));
+ break;
+
+ case LLAssetType::AT_MATERIAL:
+ if (inv_type != LLInventoryType::IT_MATERIAL)
+ {
+ LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL;
+ }
+ new_listener = new LLMaterialBridge(inventory, root, uuid);
+ break;
+
+ default:
+ LL_INFOS_ONCE() << "Unhandled asset type (llassetstorage.h): "
+ << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << LL_ENDL;
+ break;
+ }
+
+ if (new_listener)
+ {
+ new_listener->mInvType = inv_type;
+ }
+
+ return new_listener;
+}
+
+void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
+{
+ LLInventoryObject* obj = model->getObject(uuid);
+ if (obj)
+ {
+ remove_inventory_object(uuid, NULL);
+ }
+}
+
+void LLInvFVBridge::removeObject(LLInventoryModel *model, const LLUUID &uuid)
+{
+ // Keep track of the parent
+ LLInventoryItem* itemp = model->getItem(uuid);
+ LLUUID parent_id = (itemp ? itemp->getParentUUID() : LLUUID::null);
+ // Remove the object
+ model->removeObject(uuid);
+ // Get the parent updated
+ if (parent_id.notNull())
+ {
+ LLViewerInventoryCategory* parent_cat = model->getCategory(parent_id);
+ model->updateCategory(parent_cat);
+ model->notifyObservers();
+ }
+}
+
+bool LLInvFVBridge::canShare() const
+{
+ bool can_share = false;
+
+ if (isAgentInventory())
+ {
+ const LLInventoryModel* model = getInventoryModel();
+ if (model)
+ {
+ const LLViewerInventoryItem *item = model->getItem(mUUID);
+ if (item)
+ {
+ if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item))
+ {
+ can_share = LLGiveInventory::isInventoryGiveAcceptable(item);
+ }
+ }
+ else
+ {
+ // Categories can be given.
+ can_share = (model->getCategory(mUUID) != NULL);
+ }
+
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if ((mUUID == trash_id) || gInventory.isObjectDescendentOf(mUUID, trash_id))
+ {
+ can_share = false;
+ }
+ }
+ }
+
+ return can_share;
+}
+
+bool LLInvFVBridge::canListOnMarketplace() const
+{
+ LLInventoryModel * model = getInventoryModel();
+
+ LLViewerInventoryCategory * cat = model->getCategory(mUUID);
+ if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+ {
+ return false;
+ }
+
+ if (!isAgentInventory())
+ {
+ return false;
+ }
+
+ LLViewerInventoryItem * item = model->getItem(mUUID);
+ if (item)
+ {
+ if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
+ {
+ return false;
+ }
+
+ if (LLAssetType::AT_CALLINGCARD == item->getType())
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool LLInvFVBridge::canListOnMarketplaceNow() const
+{
+ bool can_list = true;
+
+ const LLInventoryObject* obj = getInventoryObject();
+ can_list &= (obj != NULL);
+
+ if (can_list)
+ {
+ const LLUUID& object_id = obj->getLinkedUUID();
+ can_list = object_id.notNull();
+
+ if (can_list)
+ {
+ LLFolderViewFolder * object_folderp = mInventoryPanel.get() ? mInventoryPanel.get()->getFolderByID(object_id) : NULL;
+ if (object_folderp)
+ {
+ can_list = !static_cast<LLFolderBridge*>(object_folderp->getViewModelItem())->isLoading();
+ }
+ }
+
+ if (can_list)
+ {
+ std::string error_msg;
+ LLInventoryModel* model = getInventoryModel();
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ if (marketplacelistings_id.notNull())
+ {
+ LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id);
+ LLInventoryCategory *cat = model->getCategory(mUUID);
+ if (cat)
+ {
+ can_list = can_move_folder_to_marketplace(master_folder, master_folder, cat, error_msg);
+ }
+ else
+ {
+ LLInventoryItem *item = model->getItem(mUUID);
+ can_list = (item ? can_move_item_to_marketplace(master_folder, master_folder, item, error_msg) : false);
+ }
+ }
+ else
+ {
+ can_list = false;
+ }
+ }
+ }
+
+ return can_list;
+}
+
+LLToolDragAndDrop::ESource LLInvFVBridge::getDragSource() const
+{
+ if (gInventory.isObjectDescendentOf(getUUID(), gInventory.getRootFolderID()))
+ {
+ return LLToolDragAndDrop::SOURCE_AGENT;
+ }
+ else if (gInventory.isObjectDescendentOf(getUUID(), gInventory.getLibraryRootFolderID()))
+ {
+ return LLToolDragAndDrop::SOURCE_LIBRARY;
+ }
+
+ return LLToolDragAndDrop::SOURCE_VIEWER;
+}
+
+
+
+// +=================================================+
+// | InventoryFVBridgeBuilder |
+// +=================================================+
+LLInvFVBridge* LLInventoryFolderViewModelBuilder::createBridge(LLAssetType::EType asset_type,
+ LLAssetType::EType actual_asset_type,
+ LLInventoryType::EType inv_type,
+ LLInventoryPanel* inventory,
+ LLFolderViewModelInventory* view_model,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags /* = 0x00 */) const
+{
+ return LLInvFVBridge::createBridge(asset_type,
+ actual_asset_type,
+ inv_type,
+ inventory,
+ view_model,
+ root,
+ uuid,
+ flags);
+}
+
+// +=================================================+
+// | LLItemBridge |
+// +=================================================+
+
+void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("goto" == action)
+ {
+ gotoItem();
+ }
+
+ if ("open" == action || "open_original" == action)
+ {
+ openItem();
+ return;
+ }
+ else if ("properties" == action)
+ {
+ showProperties();
+ return;
+ }
+ else if ("purge" == action)
+ {
+ purgeItem(model, mUUID);
+ return;
+ }
+ else if ("restoreToWorld" == action)
+ {
+ restoreToWorld();
+ return;
+ }
+ else if ("restore" == action)
+ {
+ restoreItem();
+ return;
+ }
+ else if ("thumbnail" == action)
+ {
+ LLSD data(mUUID);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
+ return;
+ }
+ else if ("copy_uuid" == action)
+ {
+ // Single item only
+ LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
+ if(!item) return;
+ LLUUID asset_id = item->getProtectedAssetUUID();
+ std::string buffer;
+ asset_id.toString(buffer);
+
+ gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(buffer));
+ return;
+ }
+ else if ("show_in_main_panel" == action)
+ {
+ LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true);
+ return;
+ }
+ else if ("cut" == action)
+ {
+ cutToClipboard();
+ return;
+ }
+ else if ("copy" == action)
+ {
+ copyToClipboard();
+ return;
+ }
+ else if ("paste" == action)
+ {
+ LLInventoryItem* itemp = model->getItem(mUUID);
+ if (!itemp) return;
+
+ LLFolderViewItem* folder_view_itemp = mInventoryPanel.get()->getItemByID(itemp->getParentUUID());
+ if (!folder_view_itemp) return;
+
+ folder_view_itemp->getViewModelItem()->pasteFromClipboard();
+ return;
+ }
+ else if ("paste_link" == action)
+ {
+ // Single item only
+ LLInventoryItem* itemp = model->getItem(mUUID);
+ if (!itemp) return;
+
+ LLFolderViewItem* folder_view_itemp = mInventoryPanel.get()->getItemByID(itemp->getParentUUID());
+ if (!folder_view_itemp) return;
+
+ folder_view_itemp->getViewModelItem()->pasteLinkFromClipboard();
+ return;
+ }
+ else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
+ {
+ LLInventoryItem* itemp = model->getItem(mUUID);
+ if (!itemp) return;
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ // Note: For a single item, if it's not a copy, then it's a move
+ move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action));
+ }
+ else if ("copy_slurl" == action)
+ {
+ LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
+ if(item)
+ {
+ LLUUID asset_id = item->getAssetUUID();
+ LLLandmark* landmark = gLandmarkList.getAsset(asset_id);
+ if (landmark)
+ {
+ LLVector3d global_pos;
+ landmark->getGlobalPos(global_pos);
+ LLLandmarkActions::getSLURLfromPosGlobal(global_pos, ©_slurl_to_clipboard_callback_inv, true);
+ }
+ }
+ }
+ else if ("show_on_map" == action)
+ {
+ doActionOnCurSelectedLandmark(boost::bind(&LLItemBridge::doShowOnMap, this, _1));
+ }
+ else if ("marketplace_edit_listing" == action)
+ {
+ std::string url = LLMarketplaceData::instance().getListingURL(mUUID);
+ LLUrlAction::openURL(url);
+ }
+}
+
+void LLItemBridge::doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb)
+{
+ LLViewerInventoryItem* cur_item = getItem();
+ if(cur_item && cur_item->getInventoryType() == LLInventoryType::IT_LANDMARK)
+ {
+ LLLandmark* landmark = LLLandmarkActions::getLandmark(cur_item->getUUID(), cb);
+ if (landmark)
+ {
+ cb(landmark);
+ }
+ }
+}
+
+void LLItemBridge::doShowOnMap(LLLandmark* landmark)
+{
+ LLVector3d landmark_global_pos;
+ // landmark has already been tested for NULL by calling routine
+ if (landmark->getGlobalPos(landmark_global_pos))
+ {
+ LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
+ if (!landmark_global_pos.isExactlyZero() && worldmap_instance)
+ {
+ worldmap_instance->trackLocation(landmark_global_pos);
+ LLFloaterReg::showInstance("world_map", "center");
+ }
+ }
+}
+
+void copy_slurl_to_clipboard_callback_inv(const std::string& slurl)
+{
+ gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl));
+ LLSD args;
+ args["SLURL"] = slurl;
+ LLNotificationsUtil::add("CopySLURL", args);
+}
+
+void LLItemBridge::selectItem()
+{
+ LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
+ if(item && !item->isFinished())
+ {
+ //item->fetchFromServer();
+ LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false);
+ }
+}
+
+void LLItemBridge::restoreItem()
+{
+ LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
+ if(item)
+ {
+ LLInventoryModel* model = getInventoryModel();
+ bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
+
+ const LLUUID new_parent = model->findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
+ // do not restamp on restore.
+ LLInvFVBridge::changeItemParent(model, item, new_parent, false);
+ }
+}
+
+void LLItemBridge::restoreToWorld()
+{
+ //Similar functionality to the drag and drop rez logic
+ bool remove_from_inventory = false;
+
+ LLViewerInventoryItem* itemp = static_cast<LLViewerInventoryItem*>(getItem());
+ if (itemp)
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("RezRestoreToWorld");
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ itemp->packMessage(msg);
+ msg->sendReliable(gAgent.getRegionHost());
+
+ //remove local inventory copy, sim will deal with permissions and removing the item
+ //from the actual inventory if its a no-copy etc
+ if(!itemp->getPermissions().allowCopyBy(gAgent.getID()))
+ {
+ remove_from_inventory = true;
+ }
+
+ // Check if it's in the trash. (again similar to the normal rez logic)
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id))
+ {
+ remove_from_inventory = true;
+ }
+ }
+
+ if(remove_from_inventory)
+ {
+ gInventory.deleteObject(itemp->getUUID());
+ gInventory.notifyObservers();
+ }
+}
+
+void LLItemBridge::gotoItem()
+{
+ LLInventoryObject *obj = getInventoryObject();
+ if (obj && obj->getIsLinkType())
+ {
+ show_item_original(obj->getUUID());
+ }
+}
+
+LLUIImagePtr LLItemBridge::getIcon() const
+{
+ LLInventoryObject *obj = getInventoryObject();
+ if (obj)
+ {
+ return LLInventoryIcon::getIcon(obj->getType(),
+ LLInventoryType::IT_NONE,
+ mIsLink);
+ }
+
+ return LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT);
+}
+
+LLUIImagePtr LLItemBridge::getIconOverlay() const
+{
+ if (getItem() && getItem()->getIsLinkType())
+ {
+ return LLUI::getUIImage("Inv_Link");
+ }
+ return NULL;
+}
+
+PermissionMask LLItemBridge::getPermissionMask() const
+{
+ LLViewerInventoryItem* item = getItem();
+ PermissionMask perm_mask = 0;
+ if (item) perm_mask = item->getPermissionMask();
+ return perm_mask;
+}
+
+void LLItemBridge::buildDisplayName() const
+{
+ if(getItem())
+ {
+ mDisplayName.assign(getItem()->getName());
+ }
+ else
+ {
+ mDisplayName.assign(LLStringUtil::null);
+ }
+
+ mSearchableName.assign(mDisplayName);
+ mSearchableName.append(getLabelSuffix());
+ LLStringUtil::toUpper(mSearchableName);
+
+ //Name set, so trigger a sort
+ LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter();
+ if(mParent && !sorter.isByDate())
+ {
+ mParent->requestSort();
+ }
+}
+
+LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
+{
+ U8 font = LLFontGL::NORMAL;
+ const LLViewerInventoryItem* item = getItem();
+
+ if (get_is_item_worn(mUUID))
+ {
+ // LL_INFOS() << "BOLD" << LL_ENDL;
+ font |= LLFontGL::BOLD;
+ }
+ else if(item && item->getIsLinkType())
+ {
+ font |= LLFontGL::ITALIC;
+ }
+
+ return (LLFontGL::StyleFlags)font;
+}
+
+std::string LLItemBridge::getLabelSuffix() const
+{
+ // String table is loaded before login screen and inventory items are
+ // loaded after login, so LLTrans should be ready.
+ static std::string NO_COPY = LLTrans::getString("no_copy_lbl");
+ static std::string NO_MOD = LLTrans::getString("no_modify_lbl");
+ static std::string NO_XFER = LLTrans::getString("no_transfer_lbl");
+ static std::string LINK = LLTrans::getString("link");
+ static std::string BROKEN_LINK = LLTrans::getString("broken_link");
+ std::string suffix;
+ LLInventoryItem* item = getItem();
+ if(item)
+ {
+ // Any type can have the link suffix...
+ bool broken_link = LLAssetType::lookupIsLinkType(item->getType());
+ if (broken_link) return BROKEN_LINK;
+
+ bool link = item->getIsLinkType();
+ if (link) return LINK;
+
+ // ...but it's a bit confusing to put nocopy/nomod/etc suffixes on calling cards.
+ if(LLAssetType::AT_CALLINGCARD != item->getType()
+ && item->getPermissions().getOwner() == gAgent.getID())
+ {
+ bool copy = item->getPermissions().allowCopyBy(gAgent.getID());
+ if (!copy)
+ {
+ suffix += " ";
+ suffix += NO_COPY;
+ }
+ bool mod = item->getPermissions().allowModifyBy(gAgent.getID());
+ if (!mod)
+ {
+ suffix += suffix.empty() ? " " : ",";
+ suffix += NO_MOD;
+ }
+ bool xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
+ gAgent.getID());
+ if (!xfer)
+ {
+ suffix += suffix.empty() ? " " : ",";
+ suffix += NO_XFER;
+ }
+ }
+ }
+ return suffix;
+}
+
+time_t LLItemBridge::getCreationDate() const
+{
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ return item->getCreationDate();
+ }
+ return 0;
+}
+
+
+bool LLItemBridge::isItemRenameable() const
+{
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ // (For now) Don't allow calling card rename since that may confuse users as to
+ // what the calling card points to.
+ if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
+ {
+ return false;
+ }
+
+ if (!item->isFinished()) // EXT-8662
+ {
+ return false;
+ }
+
+ if (isInboxFolder())
+ {
+ return false;
+ }
+
+ return (item->getPermissions().allowModifyBy(gAgent.getID()));
+ }
+ return false;
+}
+
+bool LLItemBridge::renameItem(const std::string& new_name)
+{
+ if(!isItemRenameable())
+ return false;
+ LLPreview::dirty(mUUID);
+ LLInventoryModel* model = getInventoryModel();
+ if(!model)
+ return false;
+ LLViewerInventoryItem* item = getItem();
+ if(item && (item->getName() != new_name))
+ {
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_item(item->getUUID(),updates, NULL);
+ }
+ // return false because we either notified observers (& therefore
+ // rebuilt) or we didn't update.
+ return false;
+}
+
+bool LLItemBridge::removeItem()
+{
+ if(!isItemRemovable())
+ {
+ return false;
+ }
+
+ // move it to the trash
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+ const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ LLViewerInventoryItem* item = getItem();
+ if (!item) return false;
+ if (item->getType() != LLAssetType::AT_LSL_TEXT)
+ {
+ LLPreview::hide(mUUID, true);
+ }
+ // 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.)
+ static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);
+ if (!inventory_linking)
+ {
+ if (!item->getIsLinkType())
+ {
+ LLInventoryModel::item_array_t item_array = gInventory.collectLinksTo(mUUID);
+ const U32 num_links = 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);
+ model->checkTrashOverflow();
+ 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))
+ {
+ // move to trash, and restamp
+ LLInvFVBridge::changeItemParent(model, item, trash_id, true);
+ // delete was successful
+ return true;
+ }
+ return false;
+}
+
+bool LLItemBridge::isItemCopyable(bool can_copy_as_link) const
+{
+ LLViewerInventoryItem* item = getItem();
+ if (!item)
+ {
+ return false;
+ }
+ // Can't copy worn objects.
+ // Worn objects are tied to their inworld conterparts
+ // Copy of modified worn object will return object with obsolete asset and inventory
+ if (get_is_item_worn(mUUID))
+ {
+ return false;
+ }
+
+ static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);
+ return (can_copy_as_link && inventory_linking)
+ || (mIsLink && inventory_linking)
+ || item->getPermissions().allowCopyBy(gAgent.getID());
+}
+
+LLViewerInventoryItem* LLItemBridge::getItem() const
+{
+ LLViewerInventoryItem* item = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ item = (LLViewerInventoryItem*)model->getItem(mUUID);
+ }
+ return item;
+}
+
+const LLUUID& LLItemBridge::getThumbnailUUID() const
+{
+ LLViewerInventoryItem* item = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ item = (LLViewerInventoryItem*)model->getItem(mUUID);
+ }
+ if (item)
+ {
+ return item->getThumbnailUUID();
+ }
+ return LLUUID::null;
+}
+
+bool LLItemBridge::isItemPermissive() const
+{
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ return item->getIsFullPerm();
+ }
+ return false;
+}
+
+// +=================================================+
+// | LLFolderBridge |
+// +=================================================+
+
+LLHandle<LLFolderBridge> LLFolderBridge::sSelf;
+
+// Can be moved to another folder
+bool LLFolderBridge::isItemMovable() const
+{
+ LLInventoryObject* obj = getInventoryObject();
+ if(obj)
+ {
+ // If it's a protected type folder, we can't move it
+ if (LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType()))
+ return false;
+ return true;
+ }
+ return false;
+}
+
+void LLFolderBridge::selectItem()
+{
+ LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID());
+ if (cat)
+ {
+ cat->fetch();
+ }
+}
+
+void LLFolderBridge::buildDisplayName() const
+{
+ LLFolderType::EType preferred_type = getPreferredType();
+
+ // *TODO: to be removed when database supports multi language. This is a
+ // temporary attempt to display the inventory folder in the user locale.
+ // mantipov: *NOTE: be sure this code is synchronized with LLFriendCardsManager::findChildFolderUUID
+ // it uses the same way to find localized string
+
+ // HACK: EXT - 6028 ([HARD CODED]? Inventory > Library > "Accessories" folder)
+ // Translation of Accessories folder in Library inventory folder
+ bool accessories = false;
+ if(getName() == "Accessories")
+ {
+ //To ensure that Accessories folder is in Library we have to check its parent folder.
+ //Due to parent LLFolderViewFloder is not set to this item yet we have to check its parent via Inventory Model
+ LLInventoryCategory* cat = gInventory.getCategory(getUUID());
+ if(cat)
+ {
+ const LLUUID& parent_folder_id = cat->getParentUUID();
+ accessories = (parent_folder_id == gInventory.getLibraryRootFolderID());
+ }
+ }
+
+ //"Accessories" inventory category has folder type FT_NONE. So, this folder
+ //can not be detected as protected with LLFolderType::lookupIsProtectedType
+ mDisplayName.assign(getName());
+ if (accessories || LLFolderType::lookupIsProtectedType(preferred_type))
+ {
+ LLTrans::findString(mDisplayName, std::string("InvFolder ") + getName(), LLSD());
+ }
+
+ mSearchableName.assign(mDisplayName);
+ mSearchableName.append(getLabelSuffix());
+ LLStringUtil::toUpper(mSearchableName);
+
+ //Name set, so trigger a sort
+ LLInventorySort sorter = static_cast<LLFolderViewModelInventory&>(mRootViewModel).getSorter();
+ if(mParent && sorter.isFoldersByName())
+ {
+ mParent->requestSort();
+ }
+}
+
+std::string LLFolderBridge::getLabelSuffix() const
+{
+ static LLCachedControl<bool> xui_debug(gSavedSettings, "DebugShowXUINames", 0);
+
+ if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= FOLDER_LOADING_MESSAGE_DELAY)
+ {
+ return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str());
+ }
+ std::string suffix = "";
+ if (xui_debug)
+ {
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(getUUID(), cats, items);
+
+ LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID());
+ if (cat)
+ {
+ LLStringUtil::format_map_t args;
+ args["[FOLDER_COUNT]"] = llformat("%d", cats->size());
+ args["[ITEMS_COUNT]"] = llformat("%d", items->size());
+ args["[VERSION]"] = llformat("%d", cat->getVersion());
+ args["[VIEWER_DESCENDANT_COUNT]"] = llformat("%d", cats->size() + items->size());
+ args["[SERVER_DESCENDANT_COUNT]"] = llformat("%d", cat->getDescendentCount());
+ suffix = " " + LLTrans::getString("InventoryFolderDebug", args);
+ }
+ }
+ else if(mShowDescendantsCount)
+ {
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectDescendents(getUUID(), cat_array, item_array, true);
+ S32 count = item_array.size();
+ if(count > 0)
+ {
+ std::ostringstream oss;
+ oss << count;
+ LLStringUtil::format_map_t args;
+ args["[ITEMS_COUNT]"] = oss.str();
+ suffix = " " + LLTrans::getString("InventoryItemsCount", args);
+ }
+ }
+
+ return LLInvFVBridge::getLabelSuffix() + suffix;
+}
+
+LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const
+{
+ return LLFontGL::NORMAL;
+}
+
+const LLUUID& LLFolderBridge::getThumbnailUUID() const
+{
+ LLViewerInventoryCategory* cat = getCategory();
+ if (cat)
+ {
+ return cat->getThumbnailUUID();
+ }
+ return LLUUID::null;
+}
+
+void LLFolderBridge::update()
+{
+ // we know we have children but haven't fetched them (doesn't obey filter)
+ bool loading = !isUpToDate() && hasChildren() && mFolderViewItem->isOpen();
+
+ if (loading != mIsLoading)
+ {
+ if ( loading )
+ {
+ // Measure how long we've been in the loading state
+ mTimeSinceRequestStart.reset();
+ }
+ mIsLoading = loading;
+
+ mFolderViewItem->refresh();
+ }
+}
+
+// Can be destroyed (or moved to trash)
+bool LLFolderBridge::isItemRemovable(bool check_worn) const
+{
+ if (!get_is_category_and_children_removable(getInventoryModel(), mUUID, check_worn))
+ {
+ return false;
+ }
+
+ if (isMarketplaceListingsFolder()
+ && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID)))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool LLFolderBridge::isUpToDate() const
+{
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ if( !category )
+ {
+ return false;
+ }
+
+ return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;
+}
+
+bool LLFolderBridge::isItemCopyable(bool can_copy_as_link) const
+{
+ if (can_copy_as_link && !LLFolderType::lookupIsProtectedType(getPreferredType()))
+ {
+ // Can copy and paste unprotected folders as links
+ return true;
+ }
+
+ // Folders are copyable if items in them are, recursively, copyable.
+
+ // Get the content of the folder
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(mUUID,cat_array,item_array);
+
+ // Check the items
+ LLInventoryModel::item_array_t item_array_copy = *item_array;
+ for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
+ {
+ LLInventoryItem* item = *iter;
+ LLItemBridge item_br(mInventoryPanel.get(), mRoot, item->getUUID());
+ if (!item_br.isItemCopyable(false))
+ {
+ return false;
+ }
+ }
+
+ // Check the folders
+ LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
+ for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
+ {
+ LLViewerInventoryCategory* category = *iter;
+ LLFolderBridge cat_br(mInventoryPanel.get(), mRoot, category->getUUID());
+ if (!cat_br.isItemCopyable(false))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool LLFolderBridge::isClipboardPasteable() const
+{
+ if ( ! LLInvFVBridge::isClipboardPasteable() )
+ return false;
+
+ // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
+ if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) )
+ {
+ LLInventoryModel* model = getInventoryModel();
+ if ( !model )
+ {
+ return false;
+ }
+
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ const LLViewerInventoryCategory *current_cat = getCategory();
+
+ // Search for the direct descendent of current Friends subfolder among all pasted items,
+ // and return false if is found.
+ for(S32 i = objects.size() - 1; i >= 0; --i)
+ {
+ const LLUUID &obj_id = objects.at(i);
+ if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
+ {
+ return false;
+ }
+ }
+
+ }
+ return true;
+}
+
+bool LLFolderBridge::isClipboardPasteableAsLink() const
+{
+ // Check normal paste-as-link permissions
+ if (!LLInvFVBridge::isClipboardPasteableAsLink())
+ {
+ return false;
+ }
+
+ const LLInventoryModel* model = getInventoryModel();
+ if (!model)
+ {
+ return false;
+ }
+
+ const LLViewerInventoryCategory *current_cat = getCategory();
+ if (current_cat)
+ {
+ const bool is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat );
+ const LLUUID ¤t_cat_id = current_cat->getUUID();
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ S32 count = objects.size();
+ for(S32 i = 0; i < count; i++)
+ {
+ const LLUUID &obj_id = objects.at(i);
+ const LLInventoryCategory *cat = model->getCategory(obj_id);
+ if (cat)
+ {
+ const LLUUID &cat_id = cat->getUUID();
+ // Don't allow recursive pasting
+ if ((cat_id == current_cat_id) ||
+ model->isObjectDescendentOf(current_cat_id, cat_id))
+ {
+ return false;
+ }
+ }
+ // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599
+ if ( is_in_friend_folder )
+ {
+ // If object is direct descendent of current Friends subfolder than return false.
+ // Note: We can't use 'const LLInventoryCategory *cat', because it may be null
+ // in case type of obj_id is LLInventoryItem.
+ if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) )
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+
+}
+
+
+bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
+ bool drop,
+ std::string& tooltip_msg,
+ bool is_link,
+ bool user_confirm,
+ LLPointer<LLInventoryCallback> cb)
+{
+
+ LLInventoryModel* model = getInventoryModel();
+
+ 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
+
+ LLInventoryPanel* destination_panel = mInventoryPanel.get();
+ if (!destination_panel) return false;
+
+ LLInventoryFilter* filter = getInventoryFilter();
+ if (!filter) return false;
+
+ const LLUUID &cat_id = inv_cat->getUUID();
+ const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID from_folder_uuid = inv_cat->getParentUUID();
+
+ const bool move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
+ const bool move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id);
+
+ // check to make sure source is agent inventory, and is represented there.
+ LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
+ const bool is_agent_inventory = (model->getCategory(cat_id) != NULL)
+ && (LLToolDragAndDrop::SOURCE_AGENT == source);
+
+ bool accept = false;
+ U64 filter_types = filter->getFilterTypes();
+ bool use_filter = filter_types && (filter_types&LLInventoryFilter::FILTERTYPE_DATE || (filter_types&LLInventoryFilter::FILTERTYPE_OBJECT)==0);
+
+ if (is_agent_inventory)
+ {
+ const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
+
+ const bool move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
+ const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
+ const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const bool move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT);
+ const bool move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
+ const bool move_is_into_lost_and_found = model->isObjectDescendentOf(mUUID, lost_and_found_id);
+
+ //--------------------------------------------------------------------------------
+ // Determine if folder can be moved.
+ //
+
+ bool is_movable = true;
+
+ if (is_movable && (marketplacelistings_id == cat_id))
+ {
+ is_movable = false;
+ tooltip_msg = LLTrans::getString("TooltipOutboxCannotMoveRoot");
+ }
+ if (is_movable && move_is_from_marketplacelistings && LLMarketplaceData::instance().getActivationState(cat_id))
+ {
+ // If the incoming folder is listed and active (and is therefore either the listing or the version folder),
+ // then moving is *not* allowed
+ is_movable = false;
+ tooltip_msg = LLTrans::getString("TooltipOutboxDragActive");
+ }
+ if (is_movable && (mUUID == cat_id))
+ {
+ is_movable = false;
+ tooltip_msg = LLTrans::getString("TooltipDragOntoSelf");
+ }
+ if (is_movable && (model->isObjectDescendentOf(mUUID, cat_id)))
+ {
+ is_movable = false;
+ tooltip_msg = LLTrans::getString("TooltipDragOntoOwnChild");
+ }
+ if (is_movable && LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType()))
+ {
+ is_movable = false;
+ // tooltip?
+ }
+
+ U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");
+ if (is_movable && move_is_into_outfit)
+ {
+ if (mUUID == my_outifts_id)
+ {
+ if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory");
+ is_movable = false;
+ }
+ else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear))
+ {
+ is_movable = true;
+ }
+ else
+ {
+ tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");
+ is_movable = false;
+ }
+ }
+ else if(getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE)
+ {
+ is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT));
+ }
+ else
+ {
+ is_movable = false;
+ }
+ }
+ if(is_movable && move_is_into_current_outfit && is_link)
+ {
+ is_movable = false;
+ }
+ if (is_movable && move_is_into_lost_and_found)
+ {
+ is_movable = false;
+ }
+ if (is_movable && (mUUID == model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE)))
+ {
+ is_movable = false;
+ // tooltip?
+ }
+ if (is_movable && (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK))
+ {
+ // One cannot move a folder into a stock folder
+ is_movable = false;
+ // tooltip?
+ }
+
+ LLInventoryModel::cat_array_t descendent_categories;
+ LLInventoryModel::item_array_t descendent_items;
+ if (is_movable)
+ {
+ model->collectDescendents(cat_id, descendent_categories, descendent_items, false);
+ for (S32 i=0; i < descendent_categories.size(); ++i)
+ {
+ 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
+ && move_is_into_current_outfit
+ && descendent_items.size() > max_items_to_wear)
+ {
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
+ gInventory.collectDescendentsIf(cat_id,
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ not_worn);
+
+ if (items.size() > max_items_to_wear)
+ {
+ // Can't move 'large' folders into current outfit: MAINT-4086
+ is_movable = false;
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", max_items_to_wear);
+ tooltip_msg = LLTrans::getString("TooltipTooManyWearables",args);
+ }
+ }
+ if (is_movable && move_is_into_trash)
+ {
+ for (S32 i=0; i < descendent_items.size(); ++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.
+ }
+ }
+ }
+ if (is_movable && move_is_into_landmarks)
+ {
+ for (S32 i=0; i < descendent_items.size(); ++i)
+ {
+ LLViewerInventoryItem* item = descendent_items[i];
+
+ // Don't move anything except landmarks and categories into Landmarks folder.
+ // We use getType() instead of getActua;Type() to allow links to landmarks and folders.
+ if (LLAssetType::AT_LANDMARK != item->getType() && LLAssetType::AT_CATEGORY != item->getType())
+ {
+ is_movable = false;
+ break; // It's generally movable, but not into Landmarks.
+ }
+ }
+ }
+
+ if (is_movable && move_is_into_marketplacelistings)
+ {
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
+ LLViewerInventoryCategory * dest_folder = getCategory();
+ S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount());
+ is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size);
+ }
+
+ if (is_movable && !move_is_into_landmarks)
+ {
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(false);
+ is_movable = active_panel != NULL;
+
+ // For a folder to pass the filter all its descendants are required to pass.
+ // We make this exception to allow reordering folders within an inventory panel,
+ // which has a filter applied, like Recent tab for example.
+ // There may be folders which are displayed because some of their descendants pass
+ // the filter, but other don't, and thus remain hidden. Without this check,
+ // such folders would not be allowed to be moved within a panel.
+ if (destination_panel == active_panel)
+ {
+ is_movable = true;
+ }
+ else
+ {
+ LLFolderView* active_folder_view = NULL;
+
+ if (is_movable)
+ {
+ active_folder_view = active_panel->getRootFolder();
+ is_movable = active_folder_view != NULL;
+ }
+
+ if (is_movable && use_filter)
+ {
+ // Check whether the folder being dragged from active inventory panel
+ // passes the filter of the destination panel.
+ is_movable = check_category(model, cat_id, active_panel, filter);
+ }
+ }
+ }
+ //
+ //--------------------------------------------------------------------------------
+
+ accept = is_movable;
+
+ if (accept && drop)
+ {
+ // Dropping in or out of marketplace needs (sometimes) confirmation
+ if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings))
+ {
+ if (move_is_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(cat_id) ||
+ LLMarketplaceData::instance().isListedAndActive(cat_id)))
+ {
+ if (LLMarketplaceData::instance().isListed(cat_id) || LLMarketplaceData::instance().isVersionFolder(cat_id))
+ {
+ // Move the active version folder or listing folder itself outside marketplace listings will unlist the listing so ask that question specifically
+ LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat));
+ }
+ else
+ {
+ // Any other case will simply modify but not unlist an active listed listing
+ LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat));
+ }
+ return true;
+ }
+ if (move_is_from_marketplacelistings && LLMarketplaceData::instance().isVersionFolder(cat_id))
+ {
+ // Moving the version folder from its location will deactivate it. Ask confirmation.
+ LLNotificationsUtil::add("ConfirmMerchantClearVersion", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat));
+ return true;
+ }
+ if (move_is_into_marketplacelistings && LLMarketplaceData::instance().isInActiveFolder(mUUID))
+ {
+ // Moving something in an active listed listing will modify it. Ask confirmation.
+ LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat));
+ return true;
+ }
+ if (move_is_from_marketplacelistings && LLMarketplaceData::instance().isListed(cat_id))
+ {
+ // Moving a whole listing folder will result in archival of SLM data. Ask confirmation.
+ LLNotificationsUtil::add("ConfirmListingCutOrDelete", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat));
+ return true;
+ }
+ if (move_is_into_marketplacelistings && !move_is_from_marketplacelistings)
+ {
+ LLNotificationsUtil::add("ConfirmMerchantMoveInventory", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat));
+ return true;
+ }
+ }
+ // Look for any gestures and deactivate them
+ if (move_is_into_trash)
+ {
+ for (S32 i=0; i < descendent_items.size(); i++)
+ {
+ LLInventoryItem* item = descendent_items[i];
+ if (item->getType() == LLAssetType::AT_GESTURE
+ && LLGestureMgr::instance().isGestureActive(item->getUUID()))
+ {
+ LLGestureMgr::instance().deactivateGesture(item->getUUID());
+ }
+ }
+ }
+
+ if (mUUID == my_outifts_id)
+ {
+ // Category can contains objects,
+ // create a new folder and populate it with links to original objects
+ dropToMyOutfits(inv_cat, cb);
+ }
+ // if target is current outfit folder we use link
+ else if (move_is_into_current_outfit &&
+ (inv_cat->getPreferredType() == LLFolderType::FT_NONE ||
+ inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+ {
+ // traverse category and add all contents to currently worn.
+ bool append = true;
+ LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
+ if (cb) cb->fire(inv_cat->getUUID());
+ }
+ else if (move_is_into_marketplacelistings)
+ {
+ move_folder_to_marketplacelistings(inv_cat, mUUID);
+ if (cb) cb->fire(inv_cat->getUUID());
+ }
+ else
+ {
+ if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX)))
+ {
+ set_dad_inbox_object(cat_id);
+ }
+
+ // Reparent the folder and restamp children if it's moving
+ // into trash.
+ LLInvFVBridge::changeCategoryParent(
+ model,
+ (LLViewerInventoryCategory*)inv_cat,
+ mUUID,
+ move_is_into_trash);
+ if (cb) cb->fire(inv_cat->getUUID());
+ }
+ if (move_is_from_marketplacelistings)
+ {
+ // If we are moving a folder at the listing folder level (i.e. its parent is the marketplace listings folder)
+ if (from_folder_uuid == marketplacelistings_id)
+ {
+ // Clear the folder from the marketplace in case it is a listing folder
+ if (LLMarketplaceData::instance().isListed(cat_id))
+ {
+ LLMarketplaceData::instance().clearListing(cat_id);
+ }
+ }
+ else
+ {
+ // If we move from within an active (listed) listing, checks that it's still valid, if not, unlist
+ LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
+ if (version_folder_id.notNull())
+ {
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [version_folder_id](bool result)
+ {
+ if (!result)
+ {
+ LLMarketplaceData::instance().activateListing(version_folder_id, false);
+ }
+ }
+ );
+ }
+ // In all cases, update the listing we moved from so suffix are updated
+ update_marketplace_category(from_folder_uuid);
+ if (cb) cb->fire(inv_cat->getUUID());
+ }
+ }
+ }
+ }
+ else if (LLToolDragAndDrop::SOURCE_WORLD == source)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = false;
+ }
+ else
+ {
+ // Todo: fix me. moving from task inventory doesn't have a completion callback,
+ // yet making a copy creates new item id so this doesn't work right
+ std::function<void(S32, void*, const LLMoveInv*)> callback = [cb](S32, void*, const LLMoveInv* move_inv) mutable
+ {
+ two_uuids_list_t::const_iterator move_it;
+ for (move_it = move_inv->mMoveList.begin();
+ move_it != move_inv->mMoveList.end();
+ ++move_it)
+ {
+ if (cb)
+ {
+ cb->fire(move_it->second);
+ }
+ }
+ };
+ accept = move_inv_category_world_to_agent(cat_id, mUUID, drop, callback, NULL, filter);
+ }
+ }
+ else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = false;
+ }
+ else
+ {
+ // Accept folders that contain complete outfits.
+ accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id);
+ }
+
+ if (accept && drop)
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, true, false);
+ }
+ }
+
+ return accept;
+}
+
+void warn_move_inventory(LLViewerObject* object, std::shared_ptr<LLMoveInv> move_inv)
+{
+ const char* dialog = NULL;
+ if (object->flagScripted())
+ {
+ dialog = "MoveInventoryFromScriptedObject";
+ }
+ else
+ {
+ dialog = "MoveInventoryFromObject";
+ }
+
+ static LLNotificationPtr notification_ptr;
+ static std::shared_ptr<LLMoveInv> inv_ptr;
+
+ // Notification blocks user from interacting with inventories so everything that comes after first message
+ // is part of this message - don'r show it again
+ // Note: workaround for MAINT-5495 untill proper refactoring and warning system for Drag&Drop can be made.
+ if (notification_ptr == NULL
+ || !notification_ptr->isActive()
+ || LLNotificationsUtil::find(notification_ptr->getID()) == NULL
+ || inv_ptr->mCategoryID != move_inv->mCategoryID
+ || inv_ptr->mObjectID != move_inv->mObjectID)
+ {
+ notification_ptr = LLNotificationsUtil::add(dialog, LLSD(), LLSD(), boost::bind(move_task_inventory_callback, _1, _2, move_inv));
+ inv_ptr = move_inv;
+ }
+ else
+ {
+ // Notification is alive and not responded, operating inv_ptr should be safe so attach new data
+ two_uuids_list_t::iterator move_it;
+ for (move_it = move_inv->mMoveList.begin();
+ move_it != move_inv->mMoveList.end();
+ ++move_it)
+ {
+ inv_ptr->mMoveList.push_back(*move_it);
+ }
+ move_inv.reset();
+ }
+}
+
+// Move/copy all inventory items from the Contents folder of an in-world
+// object to the agent's inventory, inside a given category.
+bool move_inv_category_world_to_agent(const LLUUID& object_id,
+ const LLUUID& category_id,
+ bool drop,
+ std::function<void(S32, void*, const LLMoveInv*)> callback,
+ void* user_data,
+ LLInventoryFilter* filter)
+{
+ // Make sure the object exists. If we allowed dragging from
+ // anonymous objects, it would be possible to bypass
+ // permissions.
+ // content category has same ID as object itself
+ LLViewerObject* object = gObjectList.findObject(object_id);
+ if(!object)
+ {
+ LL_INFOS() << "Object not found for drop." << LL_ENDL;
+ return false;
+ }
+
+ // this folder is coming from an object, as there is only one folder in an object, the root,
+ // we need to collect the entire contents and handle them as a group
+ LLInventoryObject::object_list_t inventory_objects;
+ object->getInventoryContents(inventory_objects);
+
+ if (inventory_objects.empty())
+ {
+ LL_INFOS() << "Object contents not found for drop." << LL_ENDL;
+ return false;
+ }
+
+ bool accept = false;
+ bool is_move = false;
+ bool use_filter = false;
+ if (filter)
+ {
+ U64 filter_types = filter->getFilterTypes();
+ use_filter = filter_types && (filter_types&LLInventoryFilter::FILTERTYPE_DATE || (filter_types&LLInventoryFilter::FILTERTYPE_OBJECT)==0);
+ }
+
+ // coming from a task. Need to figure out if the person can
+ // move/copy this item.
+ LLInventoryObject::object_list_t::iterator it = inventory_objects.begin();
+ LLInventoryObject::object_list_t::iterator end = inventory_objects.end();
+ for ( ; it != end; ++it)
+ {
+ LLInventoryItem* item = dynamic_cast<LLInventoryItem*>(it->get());
+ if (!item)
+ {
+ LL_WARNS() << "Invalid inventory item for drop" << LL_ENDL;
+ continue;
+ }
+
+ // coming from a task. Need to figure out if the person can
+ // move/copy this item.
+ LLPermissions perm(item->getPermissions());
+ if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
+ && perm.allowTransferTo(gAgent.getID())))
+// || gAgent.isGodlike())
+ {
+ accept = true;
+ }
+ else if(object->permYouOwner())
+ {
+ // If the object cannot be copied, but the object the
+ // inventory is owned by the agent, then the item can be
+ // moved from the task to agent inventory.
+ is_move = true;
+ accept = true;
+ }
+
+ if (accept && use_filter)
+ {
+ accept = filter->check(item);
+ }
+
+ if (!accept)
+ {
+ break;
+ }
+ }
+
+ if(drop && accept)
+ {
+ it = inventory_objects.begin();
+ std::shared_ptr<LLMoveInv> move_inv(new LLMoveInv);
+ move_inv->mObjectID = object_id;
+ move_inv->mCategoryID = category_id;
+ move_inv->mCallback = callback;
+ move_inv->mUserData = user_data;
+
+ for ( ; it != end; ++it)
+ {
+ two_uuids_t two(category_id, (*it)->getUUID());
+ move_inv->mMoveList.push_back(two);
+ }
+
+ if(is_move)
+ {
+ // Callback called from within here.
+ warn_move_inventory(object, move_inv);
+ }
+ else
+ {
+ LLNotification::Params params("MoveInventoryFromObject");
+ params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv));
+ LLNotifications::instance().forceResponse(params, 0);
+ }
+ }
+ return accept;
+}
+
+void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer)
+{
+ // Bail out immediately if no descendents
+ if( mComplete.empty() )
+ {
+ LL_WARNS() << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << LL_ENDL;
+ if (clear_observer)
+ {
+ gInventory.removeObserver(this);
+ delete this;
+ }
+ return;
+ }
+
+ // Copy the list of complete fetched folders while "this" is still valid
+ uuid_vec_t completed_folder = mComplete;
+
+ // Clean up, and remove this as an observer now since recursive calls
+ // could notify observers and throw us into an infinite loop.
+ if (clear_observer)
+ {
+ gInventory.removeObserver(this);
+ delete this;
+ }
+
+ for (uuid_vec_t::iterator current_folder = completed_folder.begin(); current_folder != completed_folder.end(); ++current_folder)
+ {
+ // Get the information on the fetched folder items and subfolders and fetch those
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(*current_folder, cat_array, item_array);
+
+ S32 item_count(0);
+ if( item_array )
+ {
+ item_count = item_array->size();
+ }
+
+ S32 cat_count(0);
+ if( cat_array )
+ {
+ cat_count = cat_array->size();
+ }
+
+ // Move to next if current folder empty
+ if ((item_count == 0) && (cat_count == 0))
+ {
+ continue;
+ }
+
+ uuid_vec_t ids;
+ LLRightClickInventoryFetchObserver* outfit = NULL;
+ LLRightClickInventoryFetchDescendentsObserver* categories = NULL;
+
+ // Fetch the items
+ if (item_count)
+ {
+ for (S32 i = 0; i < item_count; ++i)
+ {
+ ids.push_back(item_array->at(i)->getUUID());
+ }
+ outfit = new LLRightClickInventoryFetchObserver(ids);
+ }
+ // Fetch the subfolders
+ if (cat_count)
+ {
+ for (S32 i = 0; i < cat_count; ++i)
+ {
+ ids.push_back(cat_array->at(i)->getUUID());
+ }
+ categories = new LLRightClickInventoryFetchDescendentsObserver(ids);
+ }
+
+ // Perform the item fetch
+ if (outfit)
+ {
+ outfit->startFetch();
+ outfit->execute(); // Not interested in waiting and this will be right 99% of the time.
+ delete outfit;
+//Uncomment the following code for laggy Inventory UI.
+ /*
+ if (outfit->isFinished())
+ {
+ // everything is already here - call done.
+ outfit->execute();
+ delete outfit;
+ }
+ else
+ {
+ // it's all on its way - add an observer, and the inventory
+ // will call done for us when everything is here.
+ gInventory.addObserver(outfit);
+ }
+ */
+ }
+ // Perform the subfolders fetch : this is where we truly recurse down the folder hierarchy
+ if (categories)
+ {
+ categories->startFetch();
+ if (categories->isFinished())
+ {
+ // everything is already here - call done.
+ categories->execute();
+ delete categories;
+ }
+ else
+ {
+ // it's all on its way - add an observer, and the inventory
+ // will call done for us when everything is here.
+ gInventory.addObserver(categories);
+ }
+ }
+ }
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryWearObserver
+//
+// Observer for "copy and wear" operation to support knowing
+// when the all of the contents have been added to inventory.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLInventoryCopyAndWearObserver : public LLInventoryObserver
+{
+public:
+ LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count, bool folder_added=false, bool replace=false) :
+ mCatID(cat_id), mContentsCount(count), mFolderAdded(folder_added), mReplace(replace){}
+ virtual ~LLInventoryCopyAndWearObserver() {}
+ virtual void changed(U32 mask);
+
+protected:
+ LLUUID mCatID;
+ int mContentsCount;
+ bool mFolderAdded;
+ bool mReplace;
+};
+
+
+
+void LLInventoryCopyAndWearObserver::changed(U32 mask)
+{
+ if((mask & (LLInventoryObserver::ADD)) != 0)
+ {
+ if (!mFolderAdded)
+ {
+ const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
+
+ std::set<LLUUID>::const_iterator id_it = changed_items.begin();
+ std::set<LLUUID>::const_iterator id_end = changed_items.end();
+ for (;id_it != id_end; ++id_it)
+ {
+ if ((*id_it) == mCatID)
+ {
+ mFolderAdded = true;
+ break;
+ }
+ }
+ }
+
+ if (mFolderAdded)
+ {
+ LLViewerInventoryCategory* category = gInventory.getCategory(mCatID);
+ if (NULL == category)
+ {
+ LL_WARNS() << "gInventory.getCategory(" << mCatID
+ << ") was NULL" << LL_ENDL;
+ }
+ else
+ {
+ if (category->getDescendentCount() ==
+ mContentsCount)
+ {
+ gInventory.removeObserver(this);
+ LLAppearanceMgr::instance().wearInventoryCategory(category, false, !mReplace);
+ delete this;
+ }
+ }
+ }
+
+ }
+}
+
+
+
+void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("open" == action)
+ {
+ LLFolderViewFolder *f = dynamic_cast<LLFolderViewFolder *>(mInventoryPanel.get()->getItemByID(mUUID));
+ if (f)
+ {
+ f->toggleOpen();
+ }
+
+ return;
+ }
+ else if ("thumbnail" == action)
+ {
+ LLSD data(mUUID);
+ LLFloaterReg::showInstance("change_item_thumbnail", data);
+ return;
+ }
+ else if ("paste" == action)
+ {
+ pasteFromClipboard();
+ return;
+ }
+ else if ("paste_link" == action)
+ {
+ pasteLinkFromClipboard();
+ return;
+ }
+ else if ("properties" == action)
+ {
+ showProperties();
+ return;
+ }
+ else if ("replaceoutfit" == action)
+ {
+ modifyOutfit(false);
+ return;
+ }
+ else if ("addtooutfit" == action)
+ {
+ modifyOutfit(true);
+ return;
+ }
+ else if ("show_in_main_panel" == action)
+ {
+ LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true);
+ return;
+ }
+ else if ("cut" == action)
+ {
+ cutToClipboard();
+ return;
+ }
+ else if ("copy" == action)
+ {
+ copyToClipboard();
+ return;
+ }
+ else if ("removefromoutfit" == action)
+ {
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return;
+ LLViewerInventoryCategory* cat = getCategory();
+ if(!cat) return;
+
+ LLAppearanceMgr::instance().takeOffOutfit( cat->getLinkedUUID() );
+ return;
+ }
+ else if ("copyoutfittoclipboard" == action)
+ {
+ copyOutfitToClipboard();
+ }
+ else if ("purge" == action)
+ {
+ purgeItem(model, mUUID);
+ return;
+ }
+ else if ("restore" == action)
+ {
+ restoreItem();
+ return;
+ }
+ else if ("marketplace_list" == action)
+ {
+ if (depth_nesting_in_marketplace(mUUID) == 1)
+ {
+ LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID);
+ mMessage = "";
+
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [this](bool result)
+ {
+ // todo: might need to ensure bridge/mUUID exists or this will cause crashes
+ if (!result)
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = mMessage;
+ LLNotificationsUtil::add("MerchantListingFailed", subs);
+ }
+ else
+ {
+ LLMarketplaceData::instance().activateListing(mUUID, true);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)
+ );
+ }
+ return;
+ }
+ else if ("marketplace_activate" == action)
+ {
+ if (depth_nesting_in_marketplace(mUUID) == 2)
+ {
+ mMessage = "";
+
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ mUUID,
+ [this](bool result)
+ {
+ if (!result)
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = mMessage;
+ LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
+ }
+ else
+ {
+ LLInventoryCategory* category = gInventory.getCategory(mUUID);
+ LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+ false,
+ 2);
+ }
+ return;
+ }
+ else if ("marketplace_unlist" == action)
+ {
+ if (depth_nesting_in_marketplace(mUUID) == 1)
+ {
+ LLMarketplaceData::instance().activateListing(mUUID,false,1);
+ }
+ return;
+ }
+ else if ("marketplace_deactivate" == action)
+ {
+ if (depth_nesting_in_marketplace(mUUID) == 2)
+ {
+ LLInventoryCategory* category = gInventory.getCategory(mUUID);
+ LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), LLUUID::null, 1);
+ }
+ return;
+ }
+ else if ("marketplace_create_listing" == action)
+ {
+ mMessage = "";
+
+ // first run vithout fix_hierarchy, second run with fix_hierarchy
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ mUUID,
+ [this](bool result)
+ {
+ if (!result)
+ {
+ mMessage = "";
+
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ mUUID,
+ [this](bool result)
+ {
+ if (result)
+ {
+ LLNotificationsUtil::add("MerchantForceValidateListing");
+ LLMarketplaceData::instance().createListing(mUUID);
+ }
+ else
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = mMessage;
+ LLNotificationsUtil::add("MerchantListingFailed", subs);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+ true);
+ }
+ else
+ {
+ LLMarketplaceData::instance().createListing(mUUID);
+ }
+ },
+ boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
+ false);
+
+ return;
+ }
+ else if ("marketplace_disassociate_listing" == action)
+ {
+ LLMarketplaceData::instance().clearListing(mUUID);
+ return;
+ }
+ else if ("marketplace_get_listing" == action)
+ {
+ // This is used only to exercise the SLM API but won't be shown to end users
+ LLMarketplaceData::instance().getListing(mUUID);
+ return;
+ }
+ else if ("marketplace_associate_listing" == action)
+ {
+ LLFloaterAssociateListing::show(mUUID);
+ return;
+ }
+ else if ("marketplace_check_listing" == action)
+ {
+ LLSD data(mUUID);
+ LLFloaterReg::showInstance("marketplace_validation", data);
+ return;
+ }
+ else if ("marketplace_edit_listing" == action)
+ {
+ std::string url = LLMarketplaceData::instance().getListingURL(mUUID);
+ if (!url.empty())
+ {
+ LLUrlAction::openURL(url);
+ }
+ return;
+ }
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ else if ("delete_system_folder" == action)
+ {
+ removeSystemFolder();
+ }
+#endif
+ else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
+ {
+ LLInventoryCategory * cat = gInventory.getCategory(mUUID);
+ if (!cat) return;
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action)));
+ }
+}
+
+void LLFolderBridge::gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level)
+{
+ if (log_level >= LLError::LEVEL_ERROR)
+ {
+ if (!mMessage.empty())
+ {
+ // Currently, we do not gather all messages as it creates very long alerts
+ // Users can get to the whole list of errors on a listing using the "Check for Errors" audit button or "Check listing" right click menu
+ //mMessage += "\n";
+ return;
+ }
+ // Take the leading spaces out...
+ std::string::size_type start = message.find_first_not_of(" ");
+ // Append the message
+ mMessage += message.substr(start, message.length() - start);
+ }
+}
+
+void LLFolderBridge::copyOutfitToClipboard()
+{
+ std::string text;
+
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(mUUID, cat_array, item_array);
+
+ S32 item_count(0);
+ if( item_array )
+ {
+ item_count = item_array->size();
+ }
+
+ if (item_count)
+ {
+ for (S32 i = 0; i < item_count;)
+ {
+ LLSD uuid =item_array->at(i)->getUUID();
+ LLViewerInventoryItem* item = gInventory.getItem(uuid);
+
+ i++;
+ if (item != NULL)
+ {
+ // Append a newline to all but the last line
+ text += i != item_count ? item->getName() + "\n" : item->getName();
+ }
+ }
+ }
+
+ LLClipboard::instance().copyToClipboard(utf8str_to_wstring(text),0,text.size());
+}
+
+void LLFolderBridge::openItem()
+{
+ LL_DEBUGS() << "LLFolderBridge::openItem()" << LL_ENDL;
+
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ if (!panel)
+ {
+ return;
+ }
+ LLInventoryModel* model = getInventoryModel();
+ if (!model)
+ {
+ return;
+ }
+ if (mUUID.isNull())
+ {
+ return;
+ }
+ panel->onFolderOpening(mUUID);
+ bool fetching_inventory = model->fetchDescendentsOf(mUUID);
+ // Only change folder type if we have the folder contents.
+ if (!fetching_inventory)
+ {
+ // Disabling this for now, it's causing crash when new items are added to folders
+ // since folder type may change before new item item has finished processing.
+ // determineFolderType();
+ }
+}
+
+void LLFolderBridge::closeItem()
+{
+ determineFolderType();
+}
+
+void LLFolderBridge::determineFolderType()
+{
+ if (isUpToDate())
+ {
+ LLInventoryModel* model = getInventoryModel();
+ LLViewerInventoryCategory* category = model->getCategory(mUUID);
+ if (category)
+ {
+ category->determineFolderType();
+ }
+ }
+}
+
+bool LLFolderBridge::isItemRenameable() const
+{
+ return get_is_category_renameable(getInventoryModel(), mUUID);
+}
+
+void LLFolderBridge::restoreItem()
+{
+ LLViewerInventoryCategory* cat;
+ cat = (LLViewerInventoryCategory*)getCategory();
+ if(cat)
+ {
+ LLInventoryModel* model = getInventoryModel();
+ const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType()));
+ // do not restamp children on restore
+ LLInvFVBridge::changeCategoryParent(model, cat, new_parent, false);
+ }
+}
+
+LLFolderType::EType LLFolderBridge::getPreferredType() const
+{
+ LLFolderType::EType preferred_type = LLFolderType::FT_NONE;
+ LLViewerInventoryCategory* cat = getCategory();
+ if(cat)
+ {
+ preferred_type = cat->getPreferredType();
+ }
+
+ return preferred_type;
+}
+
+// Icons for folders are based on the preferred type
+LLUIImagePtr LLFolderBridge::getIcon() const
+{
+ return getFolderIcon(false);
+}
+
+LLUIImagePtr LLFolderBridge::getIconOpen() const
+{
+ return getFolderIcon(true);
+}
+
+LLUIImagePtr LLFolderBridge::getFolderIcon(bool is_open) const
+{
+ LLFolderType::EType preferred_type = getPreferredType();
+ return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, is_open));
+}
+
+// static : use by LLLinkFolderBridge to get the closed type icons
+LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type)
+{
+ return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, false));
+}
+
+LLUIImagePtr LLFolderBridge::getIconOverlay() const
+{
+ if (getInventoryObject() && getInventoryObject()->getIsLinkType())
+ {
+ return LLUI::getUIImage("Inv_Link");
+ }
+ return NULL;
+}
+
+bool LLFolderBridge::renameItem(const std::string& new_name)
+{
+
+ LLScrollOnRenameObserver *observer = new LLScrollOnRenameObserver(mUUID, mRoot);
+ gInventory.addObserver(observer);
+
+ rename_category(getInventoryModel(), mUUID, new_name);
+
+ // return false because we either notified observers (& therefore
+ // rebuilt) or we didn't update.
+ return false;
+}
+
+bool LLFolderBridge::removeItem()
+{
+ if(!isItemRemovable())
+ {
+ return false;
+ }
+ const LLViewerInventoryCategory *cat = getCategory();
+
+ LLSD payload;
+ LLSD args;
+ args["FOLDERNAME"] = cat->getName();
+
+ LLNotification::Params params("ConfirmDeleteProtectedCategory");
+ params.payload(payload).substitutions(args).functor.function(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2));
+ LLNotifications::instance().forceResponse(params, 0);
+ return true;
+}
+
+
+bool LLFolderBridge::removeSystemFolder()
+{
+ const LLViewerInventoryCategory *cat = getCategory();
+ if (!LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+ {
+ return false;
+ }
+
+ LLSD payload;
+ LLSD args;
+ args["FOLDERNAME"] = cat->getName();
+
+ LLNotification::Params params("ConfirmDeleteProtectedCategory");
+ params.payload(payload).substitutions(args).functor.function(boost::bind(&LLFolderBridge::removeItemResponse, this, _1, _2));
+ {
+ LLNotifications::instance().add(params);
+ }
+ return true;
+}
+
+bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotification::getSelectedOption(notification, response);
+
+ // if they choose delete, do it. Otherwise, don't do anything
+ if(option == 0)
+ {
+ // move it to the trash
+ LLPreview::hide(mUUID);
+ getInventoryModel()->removeCategory(mUUID);
+ return true;
+ }
+ return false;
+}
+
+//Recursively update the folder's creation date
+void LLFolderBridge::updateHierarchyCreationDate(time_t date)
+{
+ if(getCreationDate() < date)
+ {
+ setCreationDate(date);
+ if(mParent)
+ {
+ static_cast<LLFolderBridge *>(mParent)->updateHierarchyCreationDate(date);
+ }
+ }
+}
+
+void LLFolderBridge::pasteFromClipboard()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (model && isClipboardPasteable())
+ {
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const bool paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
+
+ bool cut_from_marketplacelistings = false;
+ if (LLClipboard::instance().isCutMode())
+ {
+ //Items are not removed from folder on "cut", so we need update listing folder on "paste" operation
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
+ {
+ const LLUUID& item_id = (*iter);
+ if(gInventory.isObjectDescendentOf(item_id, marketplacelistings_id) && (LLMarketplaceData::instance().isInActiveFolder(item_id) ||
+ LLMarketplaceData::instance().isListedAndActive(item_id)))
+ {
+ cut_from_marketplacelistings = true;
+ break;
+ }
+ }
+ }
+ if (cut_from_marketplacelistings || (paste_into_marketplacelistings && !LLMarketplaceData::instance().isListed(mUUID) && LLMarketplaceData::instance().isInActiveFolder(mUUID)))
+ {
+ // Prompt the user if pasting in a marketplace active version listing (note that pasting right under the listing folder root doesn't need a prompt)
+ LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_pasteFromClipboard, this, _1, _2));
+ }
+ else
+ {
+ // Otherwise just do the paste
+ perform_pasteFromClipboard();
+ }
+ }
+}
+
+// Callback for pasteFromClipboard if DAMA required...
+void LLFolderBridge::callback_pasteFromClipboard(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0) // YES
+ {
+ std::vector<LLUUID> objects;
+ std::set<LLUUID> parent_folders;
+ LLClipboard::instance().pasteFromClipboard(objects);
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
+ {
+ const LLInventoryObject* obj = gInventory.getObject(*iter);
+ parent_folders.insert(obj->getParentUUID());
+ }
+ perform_pasteFromClipboard();
+ for (std::set<LLUUID>::const_iterator iter = parent_folders.begin(); iter != parent_folders.end(); ++iter)
+ {
+ gInventory.addChangedMask(LLInventoryObserver::STRUCTURE, *iter);
+ }
+
+ }
+}
+
+void LLFolderBridge::perform_pasteFromClipboard()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (model && isClipboardPasteable())
+ {
+ const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
+
+ const bool move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
+ const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
+ const bool move_is_into_favorites = (mUUID == favorites_id);
+ const bool move_is_into_lost_and_found = model->isObjectDescendentOf(mUUID, lost_and_found_id);
+
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+
+ LLPointer<LLInventoryCallback> cb = NULL;
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ if (panel->getRootFolder()->isSingleFolderMode() && panel->getRootFolderID() == mUUID)
+ {
+ cb = new LLPasteIntoFolderCallback(mInventoryPanel);
+ }
+
+ LLViewerInventoryCategory * dest_folder = getCategory();
+ if (move_is_into_marketplacelistings)
+ {
+ std::string error_msg;
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
+ int index = 0;
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
+ {
+ const LLUUID& item_id = (*iter);
+ LLInventoryItem *item = model->getItem(item_id);
+ LLInventoryCategory *cat = model->getCategory(item_id);
+
+ if (item && !can_move_item_to_marketplace(master_folder, dest_folder, item, error_msg, objects.size() - index, true))
+ {
+ break;
+ }
+ if (cat && !can_move_folder_to_marketplace(master_folder, dest_folder, cat, error_msg, objects.size() - index, true, true))
+ {
+ break;
+ }
+ ++index;
+ }
+ if (!error_msg.empty())
+ {
+ LLSD subs;
+ subs["[ERROR_CODE]"] = error_msg;
+ LLNotificationsUtil::add("MerchantPasteFailed", subs);
+ return;
+ }
+ }
+ else
+ {
+ // Check that all items can be moved into that folder : for the moment, only stock folder mismatch is checked
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
+ {
+ const LLUUID& item_id = (*iter);
+ LLInventoryItem *item = model->getItem(item_id);
+ LLInventoryCategory *cat = model->getCategory(item_id);
+
+ if ((item && !dest_folder->acceptItem(item)) || (cat && (dest_folder->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)))
+ {
+ std::string error_msg = LLTrans::getString("TooltipOutboxMixedStock");
+ LLSD subs;
+ subs["[ERROR_CODE]"] = error_msg;
+ LLNotificationsUtil::add("StockPasteFailed", subs);
+ return;
+ }
+ }
+ }
+
+ const LLUUID parent_id(mUUID);
+
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin();
+ iter != objects.end();
+ ++iter)
+ {
+ const LLUUID& item_id = (*iter);
+
+ LLInventoryItem *item = model->getItem(item_id);
+ LLInventoryObject *obj = model->getObject(item_id);
+ if (obj)
+ {
+
+ if (move_is_into_lost_and_found)
+ {
+ if (LLAssetType::AT_CATEGORY == obj->getType())
+ {
+ return;
+ }
+ }
+ if (move_is_into_outfit)
+ {
+ if (!move_is_into_my_outfits && item && can_move_to_outfit(item, move_is_into_current_outfit))
+ {
+ dropToOutfit(item, move_is_into_current_outfit, cb);
+ }
+ else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType())
+ {
+ LLInventoryCategory* cat = model->getCategory(item_id);
+ U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");
+ if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear))
+ {
+ dropToMyOutfits(cat, cb);
+ }
+ else
+ {
+ LLNotificationsUtil::add("MyOutfitsPasteFailed");
+ }
+ }
+ else
+ {
+ LLNotificationsUtil::add("MyOutfitsPasteFailed");
+ }
+ }
+ else if (move_is_into_current_outfit)
+ {
+ if (item && can_move_to_outfit(item, move_is_into_current_outfit))
+ {
+ dropToOutfit(item, move_is_into_current_outfit, cb);
+ }
+ else
+ {
+ LLNotificationsUtil::add("MyOutfitsPasteFailed");
+ }
+ }
+ else if (move_is_into_favorites)
+ {
+ if (item && can_move_to_landmarks(item))
+ {
+ if (LLClipboard::instance().isCutMode())
+ {
+ LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item);
+ llassert(viitem);
+ if (viitem)
+ {
+ //changeItemParent() implicity calls dirtyFilter
+ changeItemParent(model, viitem, parent_id, false);
+ if (cb) cb->fire(item_id);
+ }
+ }
+ else
+ {
+ dropToFavorites(item, cb);
+ }
+ }
+ }
+ else if (LLClipboard::instance().isCutMode())
+ {
+ // Do a move to "paste" a "cut"
+ // move_inventory_item() is not enough, as we have to update inventory locally too
+ if (LLAssetType::AT_CATEGORY == obj->getType())
+ {
+ LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id);
+ llassert(vicat);
+ if (vicat)
+ {
+ // Clear the cut folder from the marketplace if it is a listing folder
+ if (LLMarketplaceData::instance().isListed(item_id))
+ {
+ LLMarketplaceData::instance().clearListing(item_id);
+ }
+ if (move_is_into_marketplacelistings)
+ {
+ move_folder_to_marketplacelistings(vicat, parent_id);
+ }
+ else
+ {
+ //changeCategoryParent() implicity calls dirtyFilter
+ changeCategoryParent(model, vicat, parent_id, false);
+ }
+ if (cb) cb->fire(item_id);
+ }
+ }
+ else
+ {
+ LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item);
+ llassert(viitem);
+ if (viitem)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ if (!move_item_to_marketplacelistings(viitem, parent_id))
+ {
+ // Stop pasting into the marketplace as soon as we get an error
+ break;
+ }
+ }
+ else
+ {
+ //changeItemParent() implicity calls dirtyFilter
+ changeItemParent(model, viitem, parent_id, false);
+ }
+ if (cb) cb->fire(item_id);
+ }
+ }
+ }
+ else
+ {
+ // Do a "copy" to "paste" a regular copy clipboard
+ if (LLAssetType::AT_CATEGORY == obj->getType())
+ {
+ LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id);
+ llassert(vicat);
+ if (vicat)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ move_folder_to_marketplacelistings(vicat, parent_id, true);
+ }
+ else
+ {
+ copy_inventory_category(model, vicat, parent_id);
+ }
+ if (cb) cb->fire(item_id);
+ }
+ }
+ else
+ {
+ LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item);
+ llassert(viitem);
+ if (viitem)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ if (!move_item_to_marketplacelistings(viitem, parent_id, true))
+ {
+ // Stop pasting into the marketplace as soon as we get an error
+ break;
+ }
+ if (cb) cb->fire(item_id);
+ }
+ else if (item->getIsLinkType())
+ {
+ link_inventory_object(parent_id,
+ item_id,
+ cb);
+ }
+ else
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ parent_id,
+ std::string(),
+ cb);
+ }
+ }
+ }
+ }
+ }
+ }
+ // Change mode to paste for next paste
+ LLClipboard::instance().setCutMode(false);
+ }
+}
+
+void LLFolderBridge::pasteLinkFromClipboard()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ const bool move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
+ const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
+
+ if (move_is_into_marketplacelistings)
+ {
+ // Notify user of failure somehow -- play error sound? modal dialog?
+ return;
+ }
+
+ const LLUUID parent_id(mUUID);
+
+ std::vector<LLUUID> objects;
+ LLClipboard::instance().pasteFromClipboard(objects);
+
+ LLPointer<LLInventoryCallback> cb = NULL;
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ if (panel->getRootFolder()->isSingleFolderMode())
+ {
+ cb = new LLPasteIntoFolderCallback(mInventoryPanel);
+ }
+
+ for (std::vector<LLUUID>::const_iterator iter = objects.begin();
+ iter != objects.end();
+ ++iter)
+ {
+ const LLUUID &object_id = (*iter);
+ if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ LLInventoryItem *item = model->getItem(object_id);
+ if (item && can_move_to_outfit(item, move_is_into_current_outfit))
+ {
+ dropToOutfit(item, move_is_into_current_outfit, cb);
+ }
+ }
+ else if (LLConstPointer<LLInventoryObject> obj = model->getObject(object_id))
+ {
+ link_inventory_object(parent_id, obj, cb);
+ }
+ }
+ // Change mode to paste for next paste
+ LLClipboard::instance().setCutMode(false);
+ }
+}
+
+void LLFolderBridge::staticFolderOptionsMenu()
+{
+ LLFolderBridge* selfp = sSelf.get();
+
+ if (selfp && selfp->mRoot)
+ {
+ selfp->mRoot->updateMenu();
+ }
+}
+
+bool LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type)
+{
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ model->collectDescendentsIf(mUUID,
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_type);
+ return !item_array.empty();
+}
+
+void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items)
+{
+ LLInventoryModel* model = getInventoryModel();
+ llassert(model != NULL);
+
+ const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
+ const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ if (outfits_id == mUUID)
+ {
+ items.push_back(std::string("New Outfit"));
+ }
+
+ if (lost_and_found_id == mUUID)
+ {
+ // This is the lost+found folder.
+ items.push_back(std::string("Empty Lost And Found"));
+
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(mUUID, cat_array, item_array);
+ // Enable Empty menu item only when there is something to act upon.
+ if (0 == cat_array->size() && 0 == item_array->size())
+ {
+ disabled_items.push_back(std::string("Empty Lost And Found"));
+ }
+
+ disabled_items.push_back(std::string("New Folder"));
+ disabled_items.push_back(std::string("upload_def"));
+ disabled_items.push_back(std::string("create_new"));
+ }
+ if (favorites == mUUID)
+ {
+ disabled_items.push_back(std::string("New Folder"));
+ }
+ if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ if (LLMarketplaceData::instance().isUpdating(mUUID))
+ {
+ disabled_items.push_back(std::string("New Folder"));
+ disabled_items.push_back(std::string("Rename"));
+ disabled_items.push_back(std::string("Cut"));
+ disabled_items.push_back(std::string("Copy"));
+ disabled_items.push_back(std::string("Paste"));
+ disabled_items.push_back(std::string("Delete"));
+ }
+ }
+ if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)
+ {
+ disabled_items.push_back(std::string("New Folder"));
+ disabled_items.push_back(std::string("upload_def"));
+ disabled_items.push_back(std::string("create_new"));
+ }
+ if (marketplace_listings_id == mUUID)
+ {
+ disabled_items.push_back(std::string("New Folder"));
+ disabled_items.push_back(std::string("Rename"));
+ disabled_items.push_back(std::string("Cut"));
+ disabled_items.push_back(std::string("Delete"));
+ }
+
+ if (isPanelActive("Favorite Items"))
+ {
+ disabled_items.push_back(std::string("Delete"));
+ }
+ if(trash_id == mUUID)
+ {
+ bool is_recent_panel = isPanelActive("Recent Items");
+
+ // This is the trash.
+ items.push_back(std::string("Empty Trash"));
+
+ LLInventoryModel::cat_array_t* cat_array;
+ LLInventoryModel::item_array_t* item_array;
+ gInventory.getDirectDescendentsOf(mUUID, cat_array, item_array);
+ LLViewerInventoryCategory *trash = getCategory();
+ // Enable Empty menu item only when there is something to act upon.
+ // Also don't enable menu if folder isn't fully fetched
+ if ((0 == cat_array->size() && 0 == item_array->size())
+ || is_recent_panel
+ || !trash
+ || trash->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN
+ || trash->getDescendentCount() == LLViewerInventoryCategory::VERSION_UNKNOWN
+ || gAgentAvatarp->hasAttachmentsInTrash())
+ {
+ disabled_items.push_back(std::string("Empty Trash"));
+ }
+
+ items.push_back(std::string("thumbnail"));
+ }
+ else if(isItemInTrash())
+ {
+ // This is a folder in the trash.
+ items.clear(); // clear any items that used to exist
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else if(isAgentInventory()) // do not allow creating in library
+ {
+ LLViewerInventoryCategory *cat = getCategory();
+ // BAP removed protected check to re-enable standard ops in untyped folders.
+ // Not sure what the right thing is to do here.
+ if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT))
+ {
+ if (!isInboxFolder() // don't allow creation in inbox
+ && outfits_id != mUUID)
+ {
+ bool menu_items_added = false;
+ // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694.
+ if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat))
+ {
+ items.push_back(std::string("New Folder"));
+ menu_items_added = true;
+ }
+ if (!isMarketplaceListingsFolder())
+ {
+ items.push_back(std::string("upload_def"));
+ items.push_back(std::string("create_new"));
+ items.push_back(std::string("New Script"));
+ items.push_back(std::string("New Note"));
+ items.push_back(std::string("New Gesture"));
+ items.push_back(std::string("New Material"));
+ items.push_back(std::string("New Clothes"));
+ items.push_back(std::string("New Body Parts"));
+ items.push_back(std::string("New Settings"));
+ if (!LLEnvironment::instance().isInventoryEnabled())
+ {
+ disabled_items.push_back("New Settings");
+ }
+ }
+ else
+ {
+ items.push_back(std::string("New Listing Folder"));
+ }
+ if (menu_items_added)
+ {
+ items.push_back(std::string("Create Separator"));
+ }
+ }
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ // Want some but not all of the items from getClipboardEntries for outfits.
+ if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT))
+ {
+ items.push_back(std::string("Rename"));
+ items.push_back(std::string("thumbnail"));
+
+ addDeleteContextMenuOptions(items, disabled_items);
+ // EXT-4030: disallow deletion of currently worn outfit
+ const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
+ if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory()))
+ {
+ disabled_items.push_back(std::string("Delete"));
+ }
+ }
+ }
+
+ if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID)
+ {
+ items.push_back(std::string("Copy outfit list to clipboard"));
+ addOpenFolderMenuOptions(flags, items);
+ }
+
+ //Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06
+ mCallingCards = mWearables = false;
+
+ LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
+ if (checkFolderForContentsOfType(model, is_callingcard))
+ {
+ mCallingCards=true;
+ }
+
+ LLFindWearables is_wearable;
+ LLIsType is_object( LLAssetType::AT_OBJECT );
+ LLIsType is_gesture( LLAssetType::AT_GESTURE );
+
+ if (checkFolderForContentsOfType(model, is_wearable) ||
+ checkFolderForContentsOfType(model, is_object) ||
+ checkFolderForContentsOfType(model, is_gesture) )
+ {
+ mWearables=true;
+ }
+ }
+ else
+ {
+ // Mark wearables and allow copy from library
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return;
+ const LLInventoryCategory* category = model->getCategory(mUUID);
+ if (!category) return;
+ LLFolderType::EType type = category->getPreferredType();
+ const bool is_system_folder = LLFolderType::lookupIsProtectedType(type);
+
+ LLFindWearables is_wearable;
+ LLIsType is_object(LLAssetType::AT_OBJECT);
+ LLIsType is_gesture(LLAssetType::AT_GESTURE);
+
+ if (checkFolderForContentsOfType(model, is_wearable) ||
+ checkFolderForContentsOfType(model, is_object) ||
+ checkFolderForContentsOfType(model, is_gesture))
+ {
+ mWearables = true;
+ }
+
+ if (!is_system_folder)
+ {
+ items.push_back(std::string("Copy"));
+ if (!isItemCopyable())
+ {
+ // For some reason there are items in library that can't be copied directly
+ disabled_items.push_back(std::string("Copy"));
+ }
+ }
+ }
+
+ // Preemptively disable system folder removal if more than one item selected.
+ if ((flags & FIRST_SELECTED_ITEM) == 0)
+ {
+ disabled_items.push_back(std::string("Delete System Folder"));
+ }
+
+ if (isAgentInventory() && !isMarketplaceListingsFolder())
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+ }
+
+
+
+ // Add menu items that are dependent on the contents of the folder.
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory *) model->getCategory(mUUID);
+ if (category && (marketplace_listings_id != mUUID))
+ {
+ uuid_vec_t folders;
+ folders.push_back(category->getUUID());
+
+ sSelf = getHandle();
+ LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders);
+ fetch->startFetch();
+ if (fetch->isFinished())
+ {
+ // Do not call execute() or done() here as if the folder is here, there's likely no point drilling down
+ // This saves lots of time as buildContextMenu() is called a lot
+ delete fetch;
+ buildContextMenuFolderOptions(flags, items, disabled_items);
+ }
+ 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);
+ }
+ }
+}
+
+void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items)
+{
+ // Build folder specific options back up
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return;
+
+ const LLInventoryCategory* category = model->getCategory(mUUID);
+ if(!category) return;
+
+ const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if ((trash_id == mUUID) || isItemInTrash())
+ {
+ addOpenFolderMenuOptions(flags, items);
+ return;
+ }
+
+ if (!canMenuDelete())
+ {
+ disabled_items.push_back(std::string("Delete"));
+ }
+ if (isMarketplaceListingsFolder()) 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_agent_inventory = isAgentInventory();
+
+ // Only enable calling-card related options for non-system folders.
+ if (!is_system_folder && is_agent_inventory && (mRoot != NULL))
+ {
+ LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
+ if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard))
+ {
+ items.push_back(std::string("Calling Card Separator"));
+ items.push_back(std::string("Conference Chat Folder"));
+ items.push_back(std::string("IM All Contacts In Folder"));
+ }
+
+ if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren() && (type != LLFolderType::FT_OUTFIT))
+ {
+ items.push_back(std::string("Ungroup folder items"));
+ }
+ }
+ else
+ {
+ disabled_items.push_back(std::string("New folder from selected"));
+ }
+
+ //skip the rest options in single-folder mode
+ if (mRoot == NULL)
+ {
+ return;
+ }
+
+ addOpenFolderMenuOptions(flags, items);
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory)
+ {
+ items.push_back(std::string("Delete System Folder"));
+ }
+#endif
+
+ // wearables related functionality for folders.
+ //is_wearable
+ LLFindWearables is_wearable;
+ LLIsType is_object( LLAssetType::AT_OBJECT );
+ LLIsType is_gesture( LLAssetType::AT_GESTURE );
+
+ if (mWearables ||
+ checkFolderForContentsOfType(model, is_wearable) ||
+ checkFolderForContentsOfType(model, is_object) ||
+ checkFolderForContentsOfType(model, is_gesture) )
+ {
+ // Only enable add/replace outfit for non-system folders.
+ if (!is_system_folder)
+ {
+ // Adding an outfit onto another (versus replacing) doesn't make sense.
+ if (type != LLFolderType::FT_OUTFIT)
+ {
+ items.push_back(std::string("Add To Outfit"));
+ if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID))
+ {
+ disabled_items.push_back(std::string("Add To Outfit"));
+ }
+ }
+
+ items.push_back(std::string("Replace Outfit"));
+ if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID))
+ {
+ disabled_items.push_back(std::string("Replace Outfit"));
+ }
+ }
+ if (is_agent_inventory)
+ {
+ items.push_back(std::string("Folder Wearables Separator"));
+ // Note: If user tries to unwear "My Inventory", it's going to deactivate everything including gestures
+ // Might be safer to disable this for "My Inventory"
+ items.push_back(std::string("Remove From Outfit"));
+ if (type != LLFolderType::FT_ROOT_INVENTORY // Unless COF is empty, whih shouldn't be, warrantied to have worn items
+ && !LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) // expensive from root!
+ {
+ disabled_items.push_back(std::string("Remove From Outfit"));
+ }
+ }
+ items.push_back(std::string("Outfit Separator"));
+
+ }
+}
+
+// Flags unused
+void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ sSelf.markDead();
+
+ // fetch contents of this folder, as context menu can depend on contents
+ // still, user would have to open context menu again to see the changes
+ gInventory.fetchDescendentsOf(getUUID());
+
+
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ LL_DEBUGS() << "LLFolderBridge::buildContextMenu()" << LL_ENDL;
+
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return;
+
+ buildContextMenuOptions(flags, items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+
+ // Reposition the menu, in case we're adding items to an existing menu.
+ menu.needsArrange();
+ menu.arrangeAndClear();
+}
+
+void LLFolderBridge::addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items)
+{
+ if ((flags & ITEM_IN_MULTI_SELECTION) == 0)
+ {
+ items.push_back(std::string("open_in_new_window"));
+ items.push_back(std::string("Open Folder Separator"));
+ items.push_back(std::string("Copy Separator"));
+ if(isPanelActive("comb_single_folder_inv"))
+ {
+ items.push_back(std::string("open_in_current_window"));
+ }
+ }
+}
+
+bool LLFolderBridge::hasChildren() const
+{
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return false;
+ LLInventoryModel::EHasChildren has_children;
+ has_children = gInventory.categoryHasChildren(mUUID);
+ return has_children != LLInventoryModel::CHILDREN_NO;
+}
+
+bool LLFolderBridge::dragOrDrop(MASK mask, bool drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ std::string& tooltip_msg)
+{
+ LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
+
+ static LLPointer<LLInventoryCallback> drop_cb = NULL;
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ LLToolDragAndDrop* drop_tool = LLToolDragAndDrop::getInstance();
+ if (drop
+ && panel->getRootFolder()->isSingleFolderMode()
+ && panel->getRootFolderID() == mUUID
+ && drop_tool->getCargoIndex() == 0)
+ {
+ drop_cb = new LLPasteIntoFolderCallback(mInventoryPanel);
+ }
+
+
+ //LL_INFOS() << "LLFolderBridge::dragOrDrop()" << LL_ENDL;
+ bool accept = false;
+ switch(cargo_type)
+ {
+ case DAD_TEXTURE:
+ case DAD_SOUND:
+ case DAD_CALLINGCARD:
+ case DAD_LANDMARK:
+ case DAD_SCRIPT:
+ case DAD_CLOTHING:
+ case DAD_OBJECT:
+ case DAD_NOTECARD:
+ case DAD_BODYPART:
+ case DAD_ANIMATION:
+ case DAD_GESTURE:
+ case DAD_MESH:
+ case DAD_SETTINGS:
+ case DAD_MATERIAL:
+ accept = dragItemIntoFolder(inv_item, drop, tooltip_msg, true, drop_cb);
+ break;
+ case DAD_LINK:
+ // DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER.
+ // If we have an item of AT_LINK_FOLDER type we should process the linked
+ // category being dragged or dropped into folder.
+ if (inv_item && LLAssetType::AT_LINK_FOLDER == inv_item->getActualType())
+ {
+ LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID());
+ if (linked_category)
+ {
+ accept = dragCategoryIntoFolder((LLInventoryCategory*)linked_category, drop, tooltip_msg, true, true, drop_cb);
+ }
+ }
+ else
+ {
+ accept = dragItemIntoFolder(inv_item, drop, tooltip_msg, true, drop_cb);
+ }
+ break;
+ case DAD_CATEGORY:
+ if (LLFriendCardsManager::instance().isAnyFriendCategory(mUUID))
+ {
+ accept = false;
+ }
+ else
+ {
+ accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop, tooltip_msg, false, true, drop_cb);
+ }
+ break;
+ case DAD_ROOT_CATEGORY:
+ case DAD_NONE:
+ break;
+ default:
+ LL_WARNS() << "Unhandled cargo type for drag&drop " << cargo_type << LL_ENDL;
+ break;
+ }
+
+ if (!drop || drop_tool->getCargoIndex() + 1 == drop_tool->getCargoCount())
+ {
+ drop_cb = NULL;
+ }
+ return accept;
+}
+
+LLViewerInventoryCategory* LLFolderBridge::getCategory() const
+{
+ LLViewerInventoryCategory* cat = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ cat = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ }
+ return cat;
+}
+
+
+// static
+void LLFolderBridge::pasteClipboard(void* user_data)
+{
+ LLFolderBridge* self = (LLFolderBridge*)user_data;
+ if(self) self->pasteFromClipboard();
+}
+
+void LLFolderBridge::createNewShirt(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHIRT);
+}
+
+void LLFolderBridge::createNewPants(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_PANTS);
+}
+
+void LLFolderBridge::createNewShoes(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHOES);
+}
+
+void LLFolderBridge::createNewSocks(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SOCKS);
+}
+
+void LLFolderBridge::createNewJacket(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_JACKET);
+}
+
+void LLFolderBridge::createNewSkirt(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIRT);
+}
+
+void LLFolderBridge::createNewGloves(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_GLOVES);
+}
+
+void LLFolderBridge::createNewUndershirt(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERSHIRT);
+}
+
+void LLFolderBridge::createNewUnderpants(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_UNDERPANTS);
+}
+
+void LLFolderBridge::createNewShape(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SHAPE);
+}
+
+void LLFolderBridge::createNewSkin(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_SKIN);
+}
+
+void LLFolderBridge::createNewHair(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_HAIR);
+}
+
+void LLFolderBridge::createNewEyes(void* user_data)
+{
+ LLFolderBridge::createWearable((LLFolderBridge*)user_data, LLWearableType::WT_EYES);
+}
+
+EInventorySortGroup LLFolderBridge::getSortGroup() const
+{
+ LLFolderType::EType preferred_type = getPreferredType();
+
+ if (preferred_type == LLFolderType::FT_TRASH)
+ {
+ return SG_TRASH_FOLDER;
+ }
+
+ if(LLFolderType::lookupIsProtectedType(preferred_type))
+ {
+ return SG_SYSTEM_FOLDER;
+ }
+
+ return SG_NORMAL_FOLDER;
+}
+
+
+// static
+void LLFolderBridge::createWearable(LLFolderBridge* bridge, LLWearableType::EType type)
+{
+ if(!bridge) return;
+ LLUUID parent_id = bridge->getUUID();
+ LLAgentWearables::createWearable(type, false, parent_id);
+}
+
+void LLFolderBridge::modifyOutfit(bool append)
+{
+ LLInventoryModel* model = getInventoryModel();
+ if(!model) return;
+ LLViewerInventoryCategory* cat = getCategory();
+ if(!cat) return;
+
+ // checking amount of items to wear
+ U32 max_items = gSavedSettings.getU32("WearFolderLimit");
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
+ gInventory.collectDescendentsIf(cat->getUUID(),
+ cats,
+ items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ not_worn);
+
+ if (items.size() > max_items)
+ {
+ LLSD args;
+ args["AMOUNT"] = llformat("%d", max_items);
+ LLNotificationsUtil::add("TooManyWearables", args);
+ return;
+ }
+
+ if (isAgentInventory())
+ {
+ LLAppearanceMgr::instance().wearInventoryCategory(cat, false, append);
+ }
+ else
+ {
+ // Library, we need to copy content first
+ LLAppearanceMgr::instance().wearInventoryCategory(cat, true, append);
+ }
+}
+
+//static
+void LLFolderBridge::onCanDeleteIdle(void* user_data)
+{
+ LLFolderBridge* self = (LLFolderBridge*)user_data;
+
+ // we really need proper onidle mechanics that returns available time
+ const F32 EXPIRY_SECONDS = 0.008f;
+ LLTimer timer;
+ timer.setTimerExpirySec(EXPIRY_SECONDS);
+
+ LLInventoryModel* model = self->getInventoryModel();
+ if (model)
+ {
+ switch (self->mCanDeleteFolderState)
+ {
+ case CDS_INIT_FOLDER_CHECK:
+ // Can still be expensive, split it further?
+ model->collectDescendents(
+ self->mUUID,
+ self->mFoldersToCheck,
+ self->mItemsToCheck,
+ LLInventoryModel::EXCLUDE_TRASH);
+ self->mCanDeleteFolderState = CDS_PROCESSING_ITEMS;
+ break;
+
+ case CDS_PROCESSING_ITEMS:
+ while (!timer.hasExpired() && !self->mItemsToCheck.empty())
+ {
+ LLViewerInventoryItem* item = self->mItemsToCheck.back().get();
+ if (item)
+ {
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
+ {
+ if (get_is_item_worn(item))
+ {
+ // At the moment we disable 'cut' if category has worn items (do we need to?)
+ // but allow 'delete' to happen since it will prompt user to detach
+ self->mCanCut = false;
+ }
+ }
+
+ if (!item->getIsLinkType() && get_is_item_worn(item))
+ {
+ self->mCanCut = false;
+ }
+ }
+ self->mItemsToCheck.pop_back();
+ }
+ self->mCanDeleteFolderState = CDS_PROCESSING_FOLDERS;
+ break;
+ case CDS_PROCESSING_FOLDERS:
+ {
+ const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
+ LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr;
+
+ while (!timer.hasExpired() && !self->mFoldersToCheck.empty())
+ {
+ LLViewerInventoryCategory* cat = self->mFoldersToCheck.back().get();
+ if (cat)
+ {
+ const LLFolderType::EType folder_type = cat->getPreferredType();
+ if (LLFolderType::lookupIsProtectedType(folder_type))
+ {
+ self->mCanCut = false;
+ self->mCanDelete = false;
+ self->completeDeleteProcessing();
+ break;
+ }
+
+ // Can't delete the outfit that is currently being worn.
+ if (folder_type == LLFolderType::FT_OUTFIT)
+ {
+ if (cat == outfit_linked_category)
+ {
+ self->mCanCut = false;
+ self->mCanDelete = false;
+ self->completeDeleteProcessing();
+ break;
+ }
+ }
+ }
+ self->mFoldersToCheck.pop_back();
+ }
+ }
+ self->mCanDeleteFolderState = CDS_DONE;
+ break;
+ case CDS_DONE:
+ self->completeDeleteProcessing();
+ break;
+ }
+ }
+}
+
+bool LLFolderBridge::canMenuDelete()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (!model) return false;
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ if (!category)
+ {
+ return false;
+ }
+
+ S32 version = category->getVersion();
+ if (mLastCheckedVersion == version)
+ {
+ return mCanDelete;
+ }
+
+ initCanDeleteProcessing(model, version);
+ return false;
+}
+
+bool LLFolderBridge::canMenuCut()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (!model) return false;
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ if (!category)
+ {
+ return false;
+ }
+
+ S32 version = category->getVersion();
+ if (mLastCheckedVersion == version)
+ {
+ return mCanCut;
+ }
+
+ initCanDeleteProcessing(model, version);
+ return false;
+}
+
+void LLFolderBridge::initCanDeleteProcessing(LLInventoryModel* model, S32 version)
+{
+ if (mCanDeleteFolderState == CDS_DONE
+ || mInProgressVersion != version)
+ {
+ if (get_is_category_removable(model, mUUID))
+ {
+ // init recursive check of content
+ mInProgressVersion = version;
+ mCanCut = true;
+ mCanDelete = true;
+ mCanDeleteFolderState = CDS_INIT_FOLDER_CHECK;
+ mFoldersToCheck.clear();
+ mItemsToCheck.clear();
+ gIdleCallbacks.addFunction(onCanDeleteIdle, this);
+ }
+ else
+ {
+ // no check needed
+ mCanDelete = false;
+ mCanCut = false;
+ mLastCheckedVersion = version;
+ mCanDeleteFolderState = CDS_DONE;
+ mFoldersToCheck.clear();
+ mItemsToCheck.clear();
+ }
+ }
+}
+
+void LLFolderBridge::completeDeleteProcessing()
+{
+ LLInventoryModel* model = getInventoryModel();
+ LLViewerInventoryCategory* category = model ? (LLViewerInventoryCategory*)model->getCategory(mUUID) : nullptr;
+ if (model && category && category->getVersion() == mInProgressVersion)
+ {
+ mLastCheckedVersion = mInProgressVersion;
+ mCanDeleteFolderState = CDS_DONE;
+ gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
+ }
+ else
+ {
+ mCanDelete = false;
+ mCanCut = false;
+ mLastCheckedVersion = LLViewerInventoryCategory::VERSION_UNKNOWN;
+ mCanDeleteFolderState = CDS_DONE;
+ }
+
+ if (mRoot)
+ {
+ mRoot->updateMenu();
+ }
+}
+
+
+// +=================================================+
+// | LLMarketplaceFolderBridge |
+// +=================================================+
+
+// LLMarketplaceFolderBridge is a specialized LLFolderBridge for use in Marketplace Inventory panels
+LLMarketplaceFolderBridge::LLMarketplaceFolderBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid) :
+LLFolderBridge(inventory, root, uuid)
+{
+ m_depth = depth_nesting_in_marketplace(mUUID);
+ m_stockCountCache = COMPUTE_STOCK_NOT_EVALUATED;
+}
+
+LLUIImagePtr LLMarketplaceFolderBridge::getIcon() const
+{
+ return getMarketplaceFolderIcon(false);
+}
+
+LLUIImagePtr LLMarketplaceFolderBridge::getIconOpen() const
+{
+ return getMarketplaceFolderIcon(true);
+}
+
+LLUIImagePtr LLMarketplaceFolderBridge::getMarketplaceFolderIcon(bool is_open) const
+{
+ LLFolderType::EType preferred_type = getPreferredType();
+ if (!LLMarketplaceData::instance().isUpdating(getUUID()))
+ {
+ // Skip computation (expensive) if we're waiting for updates. Use the old value in that case.
+ m_depth = depth_nesting_in_marketplace(mUUID);
+ }
+ if ((preferred_type == LLFolderType::FT_NONE) && (m_depth == 2))
+ {
+ // We override the type when in the marketplace listings folder and only for version folder
+ preferred_type = LLFolderType::FT_MARKETPLACE_VERSION;
+ }
+ return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, is_open));
+}
+
+std::string LLMarketplaceFolderBridge::getLabelSuffix() const
+{
+ if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= FOLDER_LOADING_MESSAGE_DELAY)
+ {
+ return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str());
+ }
+
+ std::string suffix = "";
+ // Listing folder case
+ if (LLMarketplaceData::instance().isListed(getUUID()))
+ {
+ suffix = llformat("%d",LLMarketplaceData::instance().getListingID(getUUID()));
+ if (suffix.empty())
+ {
+ suffix = LLTrans::getString("MarketplaceNoID");
+ }
+ suffix = " (" + suffix + ")";
+ if (LLMarketplaceData::instance().getActivationState(getUUID()))
+ {
+ suffix += " (" + LLTrans::getString("MarketplaceLive") + ")";
+ }
+ }
+ // Version folder case
+ else if (LLMarketplaceData::instance().isVersionFolder(getUUID()))
+ {
+ suffix += " (" + LLTrans::getString("MarketplaceActive") + ")";
+ }
+ // Add stock amount
+ bool updating = LLMarketplaceData::instance().isUpdating(getUUID());
+ if (!updating)
+ {
+ // Skip computation (expensive) if we're waiting for update anyway. Use the old value in that case.
+ m_stockCountCache = compute_stock_count(getUUID());
+ }
+ if (m_stockCountCache == 0)
+ {
+ suffix += " (" + LLTrans::getString("MarketplaceNoStock") + ")";
+ }
+ else if (m_stockCountCache != COMPUTE_STOCK_INFINITE)
+ {
+ if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)
+ {
+ suffix += " (" + LLTrans::getString("MarketplaceStock");
+ }
+ else
+ {
+ suffix += " (" + LLTrans::getString("MarketplaceMax");
+ }
+ if (m_stockCountCache == COMPUTE_STOCK_NOT_EVALUATED)
+ {
+ suffix += "=" + LLTrans::getString("MarketplaceUpdating") + ")";
+ }
+ else
+ {
+ suffix += "=" + llformat("%d", m_stockCountCache) + ")";
+ }
+ }
+ // Add updating suffix
+ if (updating)
+ {
+ suffix += " (" + LLTrans::getString("MarketplaceUpdating") + ")";
+ }
+ return LLInvFVBridge::getLabelSuffix() + suffix;
+}
+
+LLFontGL::StyleFlags LLMarketplaceFolderBridge::getLabelStyle() const
+{
+ return (LLMarketplaceData::instance().getActivationState(getUUID()) ? LLFontGL::BOLD : LLFontGL::NORMAL);
+}
+
+
+
+
+// helper stuff
+bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, std::shared_ptr<LLMoveInv> move_inv)
+{
+ LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData;
+ LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID);
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if(option == 0 && object)
+ {
+ if (cat_and_wear && cat_and_wear->mWear) // && !cat_and_wear->mFolderResponded)
+ {
+ LLInventoryObject::object_list_t inventory_objects;
+ object->getInventoryContents(inventory_objects);
+ int contents_count = inventory_objects.size();
+ LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count, cat_and_wear->mFolderResponded,
+ cat_and_wear->mReplace);
+
+ gInventory.addObserver(inventoryObserver);
+ }
+
+ two_uuids_list_t::iterator move_it;
+ for (move_it = move_inv->mMoveList.begin();
+ move_it != move_inv->mMoveList.end();
+ ++move_it)
+ {
+ object->moveInventory(move_it->first, move_it->second);
+ }
+
+ // update the UI.
+ dialog_refresh_all();
+ }
+
+ if (move_inv->mCallback)
+ {
+ move_inv->mCallback(option, move_inv->mUserData, move_inv.get());
+ }
+
+ move_inv.reset(); //since notification will persist
+ return false;
+}
+
+void drop_to_favorites_cb(const LLUUID& id, LLPointer<LLInventoryCallback> cb1, LLPointer<LLInventoryCallback> cb2)
+{
+ cb1->fire(id);
+ cb2->fire(id);
+}
+
+LLFolderBridge::LLFolderBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid)
+ : LLInvFVBridge(inventory, root, uuid)
+ , mCallingCards(false)
+ , mWearables(false)
+ , mIsLoading(false)
+ , mShowDescendantsCount(false)
+ , mCanDeleteFolderState(CDS_DONE)
+ , mLastCheckedVersion(S32_MIN)
+ , mInProgressVersion(S32_MIN)
+ , mCanDelete(false)
+ , mCanCut(false)
+{
+}
+
+LLFolderBridge::~LLFolderBridge()
+{
+ gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
+}
+
+void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb)
+{
+ // 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_fav = new AddFavoriteLandmarkCallback();
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL;
+ LLFolderViewModelItemInventory* view_model = drag_over_item ? static_cast<LLFolderViewModelItemInventory*>(drag_over_item->getViewModelItem()) : NULL;
+ if (view_model)
+ {
+ cb_fav.get()->setTargetLandmarkId(view_model->getUUID());
+ }
+
+ LLPointer <LLInventoryCallback> callback = cb_fav;
+ if (cb)
+ {
+ callback = new LLBoostFuncInventoryCallback(boost::bind(drop_to_favorites_cb, _1, cb, cb_fav));
+ }
+
+ copy_inventory_item(
+ gAgent.getID(),
+ inv_item->getPermissions().getOwner(),
+ inv_item->getUUID(),
+ mUUID,
+ std::string(),
+ callback);
+}
+
+void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit, LLPointer<LLInventoryCallback> cb)
+{
+ if((inv_item->getInventoryType() == LLInventoryType::IT_TEXTURE) || (inv_item->getInventoryType() == LLInventoryType::IT_SNAPSHOT))
+ {
+ const LLUUID &my_outifts_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ if(mUUID != my_outifts_id)
+ {
+ // Legacy: prior to thumbnails images in outfits were used for outfit gallery.
+ LLNotificationsUtil::add("ThumbnailOutfitPhoto");
+ }
+ return;
+ }
+
+ // 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_object(mUUID, LLConstPointer<LLInventoryObject>(inv_item), cb);
+ }
+}
+
+void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLInventoryCallback> cb)
+{
+ // make a folder in the My Outfits directory.
+ const LLUUID dest_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+
+ // Note: creation will take time, so passing folder id to callback is slightly unreliable,
+ // but so is collecting and passing descendants' ids
+ inventory_func_type func = boost::bind(&LLFolderBridge::outfitFolderCreatedCallback, this, inv_cat->getUUID(), _1, cb);
+ gInventory.createNewCategory(dest_id,
+ LLFolderType::FT_OUTFIT,
+ inv_cat->getName(),
+ func,
+ inv_cat->getThumbnailUUID());
+}
+
+void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer<LLInventoryCallback> cb)
+{
+ LLInventoryModel::cat_array_t* categories;
+ LLInventoryModel::item_array_t* items;
+ getInventoryModel()->getDirectDescendentsOf(cat_source_id, categories, items);
+
+ LLInventoryObject::const_object_list_t link_array;
+
+
+ LLInventoryModel::item_array_t::iterator iter = items->begin();
+ LLInventoryModel::item_array_t::iterator end = items->end();
+ while (iter!=end)
+ {
+ const LLViewerInventoryItem* item = (*iter);
+ // By this point everything is supposed to be filtered,
+ // but there was a delay to create folder so something could have changed
+ LLInventoryType::EType inv_type = item->getInventoryType();
+ if ((inv_type == LLInventoryType::IT_WEARABLE) ||
+ (inv_type == LLInventoryType::IT_GESTURE) ||
+ (inv_type == LLInventoryType::IT_ATTACHMENT) ||
+ (inv_type == LLInventoryType::IT_OBJECT) ||
+ (inv_type == LLInventoryType::IT_SNAPSHOT) ||
+ (inv_type == LLInventoryType::IT_TEXTURE))
+ {
+ link_array.push_back(LLConstPointer<LLInventoryObject>(item));
+ }
+ iter++;
+ }
+
+ if (!link_array.empty())
+ {
+ link_inventory_array(cat_dest_id, link_array, cb);
+ }
+}
+
+// Callback for drop item if DAMA required...
+void LLFolderBridge::callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0) // YES
+ {
+ std::string tooltip_msg;
+ dragItemIntoFolder(inv_item, true, tooltip_msg, false);
+ }
+}
+
+// Callback for drop category if DAMA required...
+void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0) // YES
+ {
+ std::string tooltip_msg;
+ dragCategoryIntoFolder(inv_category, true, tooltip_msg, false, false);
+ }
+}
+
+// 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,
+ std::string& tooltip_msg,
+ bool user_confirm,
+ LLPointer<LLInventoryCallback> cb)
+{
+ LLInventoryModel* model = getInventoryModel();
+
+ if (!model || !inv_item) return false;
+ if (!isAgentInventory()) return false; // cannot drag into library
+ if (!isAgentAvatarValid()) return false;
+
+ LLInventoryPanel* destination_panel = mInventoryPanel.get();
+ if (!destination_panel) return false;
+
+ LLInventoryFilter* filter = getInventoryFilter();
+ if (!filter) return false;
+
+ const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+ const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+ const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+ const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
+ const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ const LLUUID from_folder_uuid = inv_item->getParentUUID();
+
+ const bool move_is_into_current_outfit = (mUUID == current_outfit_id);
+ const bool move_is_into_favorites = (mUUID == favorites_id);
+ const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
+ const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+ const bool move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
+ const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
+ const bool move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id);
+
+ LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
+ bool accept = false;
+ U64 filter_types = filter->getFilterTypes();
+ // We shouldn't allow to drop non recent items into recent tab (or some similar transactions)
+ // while we are allowing to interact with regular filtered inventory
+ bool use_filter = filter_types && (filter_types&LLInventoryFilter::FILTERTYPE_DATE || (filter_types&LLInventoryFilter::FILTERTYPE_OBJECT)==0);
+ LLViewerObject* object = NULL;
+ if(LLToolDragAndDrop::SOURCE_AGENT == source)
+ {
+ const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+
+ 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());
+
+ //--------------------------------------------------------------------------------
+ // Determine if item can be moved.
+ //
+
+ bool is_movable = true;
+
+ switch (inv_item->getActualType())
+ {
+ case LLAssetType::AT_CATEGORY:
+ is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType());
+ break;
+ default:
+ break;
+ }
+ // Can't explicitly drag things out of the COF.
+ if (move_is_outof_current_outfit)
+ {
+ is_movable = false;
+ }
+ if (move_is_into_trash)
+ {
+ is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID());
+ }
+ 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());
+ }
+
+ //
+ //--------------------------------------------------------------------------------
+
+ //--------------------------------------------------------------------------------
+ // Determine if item can be moved & dropped
+ // Note: if user_confirm is false, we already went through those accept logic test and can skip them
+
+ accept = true;
+
+ if (user_confirm && !is_movable)
+ {
+ accept = false;
+ }
+ else if (user_confirm && (mUUID == inv_item->getParentUUID()) && !move_is_into_favorites)
+ {
+ accept = false;
+ }
+ else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit))
+ {
+ accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
+ }
+ else if (user_confirm && (move_is_into_favorites || move_is_into_landmarks))
+ {
+ accept = can_move_to_landmarks(inv_item);
+ }
+ else if (user_confirm && move_is_into_marketplacelistings)
+ {
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
+ LLViewerInventoryCategory * dest_folder = getCategory();
+ accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex());
+ }
+
+ // Check that the folder can accept this item based on folder/item type compatibility (e.g. stock folder compatibility)
+ if (user_confirm && accept)
+ {
+ LLViewerInventoryCategory * dest_folder = getCategory();
+ accept = dest_folder->acceptItem(inv_item);
+ }
+
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(false);
+
+ // Check whether the item being dragged from active inventory panel
+ // passes the filter of the destination panel.
+ if (user_confirm && accept && active_panel && use_filter)
+ {
+ LLFolderViewItem* fv_item = active_panel->getItemByID(inv_item->getUUID());
+ if (!fv_item) return false;
+
+ accept = filter->check(fv_item->getViewModelItem());
+ }
+
+ if (accept && drop)
+ {
+ if (inv_item->getType() == LLAssetType::AT_GESTURE
+ && LLGestureMgr::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash)
+ {
+ 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).
+ // RN: a better solution would be to deselect automatically when an item is moved
+ // and then select any item that is dropped only in the panel that it is dropped in
+ if (active_panel && (destination_panel != active_panel))
+ {
+ active_panel->unSelectAll();
+ }
+ // Dropping in or out of marketplace needs (sometimes) confirmation
+ if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings))
+ {
+ if ((move_is_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(inv_item->getUUID())
+ || LLMarketplaceData::instance().isListedAndActive(inv_item->getUUID()))) ||
+ (move_is_into_marketplacelistings && LLMarketplaceData::instance().isInActiveFolder(mUUID)))
+ {
+ LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropItemIntoFolder, this, _1, _2, inv_item));
+ return true;
+ }
+ if (move_is_into_marketplacelistings && !move_is_from_marketplacelistings)
+ {
+ LLNotificationsUtil::add("ConfirmMerchantMoveInventory", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropItemIntoFolder, this, _1, _2, inv_item));
+ return true;
+ }
+ }
+
+ //--------------------------------------------------------------------------------
+ // Destination folder logic
+ //
+
+ // REORDER
+ // (only reorder the item in Favorites folder)
+ if ((mUUID == inv_item->getParentUUID()) && move_is_into_favorites)
+ {
+ LLFolderViewItem* itemp = destination_panel->getRootFolder()->getDraggingOverItem();
+ if (itemp)
+ {
+ LLUUID srcItemId = inv_item->getUUID();
+ LLUUID destItemId = static_cast<LLFolderViewModelItemInventory*>(itemp->getViewModelItem())->getUUID();
+ LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(srcItemId, destItemId);
+ }
+ }
+
+ // FAVORITES folder
+ // (copy the item)
+ else if (move_is_into_favorites)
+ {
+ dropToFavorites(inv_item, cb);
+ }
+ // 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, cb);
+ }
+ // MARKETPLACE LISTINGS folder
+ // Move the item
+ else if (move_is_into_marketplacelistings)
+ {
+ move_item_to_marketplacelistings(inv_item, mUUID);
+ if (cb) cb->fire(inv_item->getUUID());
+ }
+ // NORMAL or TRASH folder
+ // (move the item, restamp if into trash)
+ else
+ {
+ // set up observer to select item once drag and drop from inbox is complete
+ if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)))
+ {
+ set_dad_inbox_object(inv_item->getUUID());
+ }
+
+ LLInvFVBridge::changeItemParent(
+ model,
+ (LLViewerInventoryItem*)inv_item,
+ mUUID,
+ move_is_into_trash);
+ if (cb) cb->fire(inv_item->getUUID());
+ }
+
+ if (move_is_from_marketplacelistings)
+ {
+ // If we move from an active (listed) listing, checks that it's still valid, if not, unlist
+ LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
+ if (version_folder_id.notNull())
+ {
+ LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
+ version_folder_id,
+ [version_folder_id](bool result)
+ {
+ if (!result)
+ {
+ LLMarketplaceData::instance().activateListing(version_folder_id, false);
+ }
+ });
+ }
+ }
+
+ //
+ //--------------------------------------------------------------------------------
+ }
+ }
+ else if (LLToolDragAndDrop::SOURCE_WORLD == source)
+ {
+ // Make sure the object exists. If we allowed dragging from
+ // anonymous objects, it would be possible to bypass
+ // permissions.
+ object = gObjectList.findObject(inv_item->getParentUUID());
+ if (!object)
+ {
+ LL_INFOS() << "Object not found for drop." << LL_ENDL;
+ return false;
+ }
+
+ // coming from a task. Need to figure out if the person can
+ // move/copy this item.
+ LLPermissions perm(inv_item->getPermissions());
+ bool is_move = false;
+ if ((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
+ && perm.allowTransferTo(gAgent.getID())))
+ // || gAgent.isGodlike())
+ {
+ accept = true;
+ }
+ else if(object->permYouOwner())
+ {
+ // If the object cannot be copied, but the object the
+ // inventory is owned by the agent, then the item can be
+ // moved from the task to agent inventory.
+ 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;
+ }
+ // Don't allow to move a single item to Favorites or Landmarks
+ // if it is not a landmark or a link to a landmark.
+ else if ((move_is_into_favorites || move_is_into_landmarks)
+ && !can_move_to_landmarks(inv_item))
+ {
+ accept = false;
+ }
+ else if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = false;
+ }
+
+ // Check whether the item being dragged from in world
+ // passes the filter of the destination panel.
+ if (accept && use_filter)
+ {
+ accept = filter->check(inv_item);
+ }
+
+ if (accept && drop)
+ {
+ LLUUID item_id = inv_item->getUUID();
+ std::shared_ptr<LLMoveInv> move_inv (new LLMoveInv());
+ move_inv->mObjectID = inv_item->getParentUUID();
+ two_uuids_t item_pair(mUUID, item_id);
+ move_inv->mMoveList.push_back(item_pair);
+ if (cb)
+ {
+ move_inv->mCallback = [item_id, cb](S32, void*, const LLMoveInv* move_inv) mutable
+ { cb->fire(item_id); };
+ }
+ move_inv->mUserData = NULL;
+ if(is_move)
+ {
+ warn_move_inventory(object, move_inv);
+ }
+ else
+ {
+ // store dad inventory item to select added one later. See EXT-4347
+ set_dad_inventory_item(inv_item, mUUID);
+
+ LLNotification::Params params("MoveInventoryFromObject");
+ params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv));
+ LLNotifications::instance().forceResponse(params, 0);
+ }
+ }
+ }
+ else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
+ {
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = false;
+ }
+ else if ((inv_item->getActualType() == LLAssetType::AT_SETTINGS) && !LLEnvironment::instance().isInventoryEnabled())
+ {
+ tooltip_msg = LLTrans::getString("NoEnvironmentSettings");
+ accept = false;
+ }
+ else
+ {
+ // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder
+ // because they must contain only links to wearable items.
+ accept = !(move_is_into_current_outfit || move_is_into_outfit);
+ }
+
+ // Check whether the item being dragged from notecard
+ // passes the filter of the destination panel.
+ if (accept && use_filter)
+ {
+ accept = filter->check(inv_item);
+ }
+
+ if (accept && drop)
+ {
+ copy_inventory_from_notecard(mUUID, // Drop to the chosen destination folder
+ LLToolDragAndDrop::getInstance()->getObjectID(),
+ LLToolDragAndDrop::getInstance()->getSourceID(),
+ inv_item);
+ }
+ }
+ else if(LLToolDragAndDrop::SOURCE_LIBRARY == source)
+ {
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item;
+ if(item && item->isFinished())
+ {
+ accept = true;
+
+ if (move_is_into_marketplacelistings)
+ {
+ tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
+ accept = false;
+ }
+ else if (move_is_into_current_outfit || move_is_into_outfit)
+ {
+ accept = can_move_to_outfit(inv_item, move_is_into_current_outfit);
+ }
+ // Don't allow to move a single item to Favorites or Landmarks
+ // if it is not a landmark or a link to a landmark.
+ else if (move_is_into_favorites || move_is_into_landmarks)
+ {
+ accept = can_move_to_landmarks(inv_item);
+ }
+
+ LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(false);
+
+ // Check whether the item being dragged from the library
+ // passes the filter of the destination panel.
+ if (accept && active_panel && use_filter)
+ {
+ LLFolderViewItem* fv_item = active_panel->getItemByID(inv_item->getUUID());
+ if (!fv_item) return false;
+
+ accept = filter->check(fv_item->getViewModelItem());
+ }
+
+ if (accept && drop)
+ {
+ // FAVORITES folder
+ // (copy the item)
+ if (move_is_into_favorites)
+ {
+ dropToFavorites(inv_item, cb);
+ }
+ // 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, cb);
+ }
+ else
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ inv_item->getPermissions().getOwner(),
+ inv_item->getUUID(),
+ mUUID,
+ std::string(),
+ cb);
+ }
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS() << "unhandled drag source" << LL_ENDL;
+ }
+ return accept;
+}
+
+// static
+bool check_category(LLInventoryModel* model,
+ const LLUUID& cat_id,
+ LLInventoryPanel* active_panel,
+ LLInventoryFilter* filter)
+{
+ if (!model || !active_panel || !filter)
+ return false;
+
+ if (!filter->checkFolder(cat_id))
+ {
+ return false;
+ }
+
+ LLInventoryModel::cat_array_t descendent_categories;
+ LLInventoryModel::item_array_t descendent_items;
+ model->collectDescendents(cat_id, descendent_categories, descendent_items, true);
+
+ S32 num_descendent_categories = descendent_categories.size();
+ S32 num_descendent_items = descendent_items.size();
+
+ if (num_descendent_categories + num_descendent_items == 0)
+ {
+ // Empty folder should be checked as any other folder view item.
+ // If we are filtering by date the folder should not pass because
+ // it doesn't have its own creation date. See LLInvFVBridge::getCreationDate().
+ return check_item(cat_id, active_panel, filter);
+ }
+
+ for (S32 i = 0; i < num_descendent_categories; ++i)
+ {
+ LLInventoryCategory* category = descendent_categories[i];
+ if(!check_category(model, category->getUUID(), active_panel, filter))
+ {
+ return false;
+ }
+ }
+
+ for (S32 i = 0; i < num_descendent_items; ++i)
+ {
+ LLViewerInventoryItem* item = descendent_items[i];
+ if(!check_item(item->getUUID(), active_panel, filter))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// static
+bool check_item(const LLUUID& item_id,
+ LLInventoryPanel* active_panel,
+ LLInventoryFilter* filter)
+{
+ if (!active_panel || !filter) return false;
+
+ LLFolderViewItem* fv_item = active_panel->getItemByID(item_id);
+ if (!fv_item) return false;
+
+ return filter->check(fv_item->getViewModelItem());
+}
+
+// +=================================================+
+// | LLTextureBridge |
+// +=================================================+
+
+LLUIImagePtr LLTextureBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInvType);
+}
+
+void LLTextureBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+}
+
+bool LLTextureBridge::canSaveTexture(void)
+{
+ const LLInventoryModel* model = getInventoryModel();
+ if(!model)
+ {
+ return false;
+ }
+
+ const LLViewerInventoryItem *item = model->getItem(mUUID);
+ if (item)
+ {
+ return item->checkPermissionsSet(PERM_ITEM_UNRESTRICTED);
+ }
+ return false;
+}
+
+void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLTextureBridge::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+
+ addOpenRightClickMenuOption(items);
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+
+ items.push_back(std::string("Texture Separator"));
+
+ if ((flags & ITEM_IN_MULTI_SELECTION) != 0)
+ {
+ items.push_back(std::string("Save Selected As"));
+ }
+ else
+ {
+ items.push_back(std::string("Save As"));
+ if (!canSaveTexture())
+ {
+ disabled_items.push_back(std::string("Save As"));
+ }
+ }
+
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+// virtual
+void LLTextureBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("save_as" == action)
+ {
+ LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUID);
+ if (preview_texture)
+ {
+ preview_texture->openToSave();
+ preview_texture->saveAs();
+ }
+ }
+ else if ("save_selected_as" == action)
+ {
+ openItem();
+ if (canSaveTexture())
+ {
+ LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUID);
+ if (preview_texture)
+ {
+ preview_texture->saveMultipleToFile(mFileName);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "You don't have permission to save " << getName() << " to disk." << LL_ENDL;
+ }
+
+ }
+ else LLItemBridge::performAction(model, action);
+}
+
+// +=================================================+
+// | LLSoundBridge |
+// +=================================================+
+
+void LLSoundBridge::openItem()
+{
+ const LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+}
+
+void LLSoundBridge::openSoundPreview(void* which)
+{
+ LLSoundBridge *me = (LLSoundBridge *)which;
+ LLFloaterReg::showInstance("preview_sound", LLSD(me->mUUID), TAKE_FOCUS_YES);
+}
+
+void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLSoundBridge::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ if (isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+ items.push_back(std::string("Sound Open"));
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+ }
+
+ items.push_back(std::string("Sound Separator"));
+ items.push_back(std::string("Sound Play"));
+ }
+
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+void LLSoundBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("sound_play" == action)
+ {
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ send_sound_trigger(item->getAssetUUID(), SOUND_GAIN);
+ }
+ }
+ else if ("open" == action)
+ {
+ openSoundPreview((void*)this);
+ }
+ else LLItemBridge::performAction(model, action);
+}
+
+// +=================================================+
+// | LLLandmarkBridge |
+// +=================================================+
+
+LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags/* = 0x00*/) :
+ LLItemBridge(inventory, root, uuid)
+{
+ mVisited = false;
+ if (flags & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED)
+ {
+ mVisited = true;
+ }
+}
+
+LLUIImagePtr LLLandmarkBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, false);
+}
+
+void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ LL_DEBUGS() << "LLLandmarkBridge::buildContextMenu()" << LL_ENDL;
+ if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+ items.push_back(std::string("Landmark Open"));
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+ }
+
+ items.push_back(std::string("Landmark Separator"));
+ items.push_back(std::string("url_copy"));
+ items.push_back(std::string("About Landmark"));
+ items.push_back(std::string("show_on_map"));
+ }
+
+ // Disable "About Landmark" menu item for
+ // multiple landmarks selected. Only one landmark
+ // info panel can be shown at a time.
+ if ((flags & FIRST_SELECTED_ITEM) == 0)
+ {
+ disabled_items.push_back(std::string("url_copy"));
+ disabled_items.push_back(std::string("About Landmark"));
+ }
+
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+// Convenience function for the two functions below.
+void teleport_via_landmark(const LLUUID& asset_id)
+{
+ gAgent.teleportViaLandmark( asset_id );
+
+ // we now automatically track the landmark you're teleporting to
+ // because you'll probably arrive at a telehub instead
+ LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance();
+ if( floater_world_map )
+ {
+ floater_world_map->trackLandmark( asset_id );
+ }
+}
+
+// virtual
+void LLLandmarkBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("teleport" == action)
+ {
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ teleport_via_landmark(item->getAssetUUID());
+ }
+ }
+ else if ("about" == action)
+ {
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ LLSD key;
+ key["type"] = "landmark";
+ key["id"] = item->getUUID();
+
+ LLFloaterSidePanelContainer::showPanel("places", key);
+ }
+ }
+ else
+ {
+ LLItemBridge::performAction(model, action);
+ }
+}
+
+static bool open_landmark_callback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ LLUUID asset_id = notification["payload"]["asset_id"].asUUID();
+ if (option == 0)
+ {
+ teleport_via_landmark(asset_id);
+ }
+
+ return false;
+}
+static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportFromLandmark", open_landmark_callback);
+
+
+void LLLandmarkBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+}
+
+
+// +=================================================+
+// | LLCallingCardObserver |
+// +=================================================+
+class LLCallingCardObserver : public LLFriendObserver
+{
+public:
+ LLCallingCardObserver(LLCallingCardBridge* bridge) : mBridgep(bridge) {}
+ virtual ~LLCallingCardObserver() { mBridgep = NULL; }
+ virtual void changed(U32 mask)
+ {
+ if (mask & LLFriendObserver::ONLINE)
+ {
+ mBridgep->refreshFolderViewItem();
+ mBridgep->checkSearchBySuffixChanges();
+ }
+ }
+protected:
+ LLCallingCardBridge* mBridgep;
+};
+
+// +=================================================+
+// | LLCallingCardBridge |
+// +=================================================+
+
+LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid ) :
+ LLItemBridge(inventory, root, uuid)
+{
+ mObserver = new LLCallingCardObserver(this);
+ mCreatorUUID = getItem()->getCreatorUUID();
+ LLAvatarTracker::instance().addParticularFriendObserver(mCreatorUUID, mObserver);
+}
+
+LLCallingCardBridge::~LLCallingCardBridge()
+{
+ LLAvatarTracker::instance().removeParticularFriendObserver(mCreatorUUID, mObserver);
+
+ delete mObserver;
+}
+
+void LLCallingCardBridge::refreshFolderViewItem()
+{
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ LLFolderViewItem* itemp = panel ? panel->getItemByID(mUUID) : NULL;
+ if (itemp)
+ {
+ itemp->refresh();
+ }
+}
+
+void LLCallingCardBridge::checkSearchBySuffixChanges()
+{
+ if (!mDisplayName.empty())
+ {
+ // changes in mDisplayName are processed by rename function and here it will be always same
+ // suffixes are also of fixed length, and we are processing change of one at a time,
+ // so it should be safe to use length (note: mSearchableName is capitalized)
+ S32 old_length = mSearchableName.length();
+ S32 new_length = mDisplayName.length() + getLabelSuffix().length();
+ if (old_length == new_length)
+ {
+ return;
+ }
+ mSearchableName.assign(mDisplayName);
+ mSearchableName.append(getLabelSuffix());
+ LLStringUtil::toUpper(mSearchableName);
+ if (new_length<old_length)
+ {
+ LLInventoryFilter* filter = getInventoryFilter();
+ if (filter && mPassedFilter && mSearchableName.find(filter->getFilterSubString()) == std::string::npos)
+ {
+ // string no longer contains substring
+ // we either have to update all parents manually or restart filter.
+ // dirtyFilter will not work here due to obsolete descendants' generations
+ getInventoryFilter()->setModified(LLFolderViewFilter::FILTER_MORE_RESTRICTIVE);
+ }
+ }
+ else
+ {
+ if (getInventoryFilter())
+ {
+ // mSearchableName became longer, we gained additional suffix and need to repeat filter check.
+ dirtyFilter();
+ }
+ }
+ }
+}
+
+// virtual
+void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("begin_im" == action)
+ {
+ LLViewerInventoryItem *item = getItem();
+ if (item && (item->getCreatorUUID() != gAgent.getID()) &&
+ (!item->getCreatorUUID().isNull()))
+ {
+ std::string callingcard_name = LLCacheName::getDefaultName();
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name))
+ {
+ callingcard_name = av_name.getCompleteName();
+ }
+ LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID());
+ if (session_id != LLUUID::null)
+ {
+ LLFloaterIMContainer::getInstance()->showConversation(session_id);
+ }
+ }
+ }
+ else if ("lure" == action)
+ {
+ LLViewerInventoryItem *item = getItem();
+ if (item && (item->getCreatorUUID() != gAgent.getID()) &&
+ (!item->getCreatorUUID().isNull()))
+ {
+ LLAvatarActions::offerTeleport(item->getCreatorUUID());
+ }
+ }
+ else if ("request_lure" == action)
+ {
+ LLViewerInventoryItem *item = getItem();
+ if (item && (item->getCreatorUUID() != gAgent.getID()) &&
+ (!item->getCreatorUUID().isNull()))
+ {
+ LLAvatarActions::teleportRequest(item->getCreatorUUID());
+ }
+ }
+
+ else LLItemBridge::performAction(model, action);
+}
+
+LLUIImagePtr LLCallingCardBridge::getIcon() const
+{
+ bool online = false;
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID());
+ }
+ return LLInventoryIcon::getIcon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, false);
+}
+
+std::string LLCallingCardBridge::getLabelSuffix() const
+{
+ LLViewerInventoryItem* item = getItem();
+ if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) )
+ {
+ return LLItemBridge::getLabelSuffix() + " online";
+ }
+ else
+ {
+ return LLItemBridge::getLabelSuffix();
+ }
+}
+
+void LLCallingCardBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+/*
+ LLViewerInventoryItem* item = getItem();
+ if(item && !item->getCreatorUUID().isNull())
+ {
+ LLAvatarActions::showProfile(item->getCreatorUUID());
+ }
+*/
+}
+
+void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLCallingCardBridge::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+ if ((flags & FIRST_SELECTED_ITEM) == 0)
+ {
+ disabled_items.push_back(std::string("Open"));
+ }
+ addOpenRightClickMenuOption(items);
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+
+ LLInventoryItem* item = getItem();
+ bool good_card = (item
+ && (LLUUID::null != item->getCreatorUUID())
+ && (item->getCreatorUUID() != gAgent.getID()));
+ bool user_online = false;
+ if (item)
+ {
+ user_online = (LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()));
+ }
+ items.push_back(std::string("Send Instant Message Separator"));
+ items.push_back(std::string("Send Instant Message"));
+ items.push_back(std::string("Offer Teleport..."));
+ items.push_back(std::string("Request Teleport..."));
+ items.push_back(std::string("Conference Chat"));
+
+ if (!good_card)
+ {
+ disabled_items.push_back(std::string("Send Instant Message"));
+ }
+ if (!good_card || !user_online)
+ {
+ disabled_items.push_back(std::string("Offer Teleport..."));
+ disabled_items.push_back(std::string("Request Teleport..."));
+ disabled_items.push_back(std::string("Conference Chat"));
+ }
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+bool LLCallingCardBridge::dragOrDrop(MASK mask, bool drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ std::string& tooltip_msg)
+{
+ LLViewerInventoryItem* item = getItem();
+ bool rv = false;
+ if(item)
+ {
+ // check the type
+ switch(cargo_type)
+ {
+ case DAD_TEXTURE:
+ case DAD_SOUND:
+ case DAD_LANDMARK:
+ case DAD_SCRIPT:
+ case DAD_CLOTHING:
+ case DAD_OBJECT:
+ case DAD_NOTECARD:
+ case DAD_BODYPART:
+ case DAD_ANIMATION:
+ case DAD_GESTURE:
+ case DAD_MESH:
+ case DAD_SETTINGS:
+ case DAD_MATERIAL:
+ {
+ LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
+ const LLPermissions& perm = inv_item->getPermissions();
+ if(gInventory.getItem(inv_item->getUUID())
+ && perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
+ {
+ rv = true;
+ if(drop)
+ {
+ LLGiveInventory::doGiveInventoryItem(item->getCreatorUUID(),
+ (LLInventoryItem*)cargo_data);
+ }
+ }
+ else
+ {
+ // It's not in the user's inventory (it's probably in
+ // an object's contents), so disallow dragging it here.
+ // You can't give something you don't yet have.
+ rv = false;
+ }
+ break;
+ }
+ case DAD_CATEGORY:
+ {
+ LLInventoryCategory* inv_cat = (LLInventoryCategory*)cargo_data;
+ if( gInventory.getCategory( inv_cat->getUUID() ) )
+ {
+ rv = true;
+ if(drop)
+ {
+ LLGiveInventory::doGiveInventoryCategory(
+ item->getCreatorUUID(),
+ inv_cat);
+ }
+ }
+ else
+ {
+ // It's not in the user's inventory (it's probably in
+ // an object's contents), so disallow dragging it here.
+ // You can't give something you don't yet have.
+ rv = false;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return rv;
+}
+
+// +=================================================+
+// | LLNotecardBridge |
+// +=================================================+
+
+void LLNotecardBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+}
+
+void LLNotecardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLNotecardBridge::buildContextMenu()" << LL_ENDL;
+
+ if (isMarketplaceListingsFolder())
+ {
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ hide_context_entries(menu, items, disabled_items);
+ }
+ else
+ {
+ LLItemBridge::buildContextMenu(menu, flags);
+ }
+}
+
+// +=================================================+
+// | LLGestureBridge |
+// +=================================================+
+
+LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const
+{
+ if( LLGestureMgr::instance().isGestureActive(mUUID) )
+ {
+ return LLFontGL::BOLD;
+ }
+ else
+ {
+ return LLFontGL::NORMAL;
+ }
+}
+
+std::string LLGestureBridge::getLabelSuffix() const
+{
+ if( LLGestureMgr::instance().isGestureActive(mUUID) )
+ {
+ LLStringUtil::format_map_t args;
+ args["[GESLABEL]"] = LLItemBridge::getLabelSuffix();
+ return LLTrans::getString("ActiveGesture", args);
+ }
+ else
+ {
+ return LLItemBridge::getLabelSuffix();
+ }
+}
+
+// virtual
+void LLGestureBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if (isAddAction(action))
+ {
+ LLGestureMgr::instance().activateGesture(mUUID);
+
+ LLViewerInventoryItem* item = gInventory.getItem(mUUID);
+ if (!item) return;
+
+ // Since we just changed the suffix to indicate (active)
+ // the server doesn't need to know, just the viewer.
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+ }
+ else if ("deactivate" == action || isRemoveAction(action))
+ {
+ LLGestureMgr::instance().deactivateGesture(mUUID);
+
+ LLViewerInventoryItem* item = gInventory.getItem(mUUID);
+ if (!item) return;
+
+ // Since we just changed the suffix to indicate (active)
+ // the server doesn't need to know, just the viewer.
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+ }
+ else if("play" == action)
+ {
+ if(!LLGestureMgr::instance().isGestureActive(mUUID))
+ {
+ // we need to inform server about gesture activating to be consistent with LLPreviewGesture and LLGestureComboList.
+ bool inform_server = true;
+ bool deactivate_similar = false;
+ LLGestureMgr::instance().setGestureLoadedCallback(mUUID, boost::bind(&LLGestureBridge::playGesture, mUUID));
+ LLViewerInventoryItem* item = gInventory.getItem(mUUID);
+ llassert(item);
+ if (item)
+ {
+ LLGestureMgr::instance().activateGestureWithAsset(mUUID, item->getAssetUUID(), inform_server, deactivate_similar);
+ }
+ }
+ else
+ {
+ playGesture(mUUID);
+ }
+ }
+ else LLItemBridge::performAction(model, action);
+}
+
+void LLGestureBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+/*
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null);
+ preview->setFocus(true);
+ }
+*/
+}
+
+bool LLGestureBridge::removeItem()
+{
+ // Grab class information locally since *this may be deleted
+ // within this function. Not a great pattern...
+ const LLInventoryModel* model = getInventoryModel();
+ if(!model)
+ {
+ return false;
+ }
+ const LLUUID item_id = mUUID;
+
+ // This will also force close the preview window, if it exists.
+ // This may actually delete *this, if mUUID is in the COF.
+ LLGestureMgr::instance().deactivateGesture(item_id);
+
+ // If deactivateGesture deleted *this, then return out immediately.
+ if (!model->getObject(item_id))
+ {
+ return true;
+ }
+
+ return LLItemBridge::removeItem();
+}
+
+void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLGestureBridge::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+
+ addOpenRightClickMenuOption(items);
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+
+ items.push_back(std::string("Gesture Separator"));
+ if (LLGestureMgr::instance().isGestureActive(getUUID()))
+ {
+ items.push_back(std::string("Deactivate"));
+ }
+ else
+ {
+ items.push_back(std::string("Activate"));
+ }
+ items.push_back(std::string("PlayGesture"));
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+// static
+void LLGestureBridge::playGesture(const LLUUID& item_id)
+{
+ if (LLGestureMgr::instance().isGesturePlaying(item_id))
+ {
+ LLGestureMgr::instance().stopGesture(item_id);
+ }
+ else
+ {
+ LLGestureMgr::instance().playGesture(item_id);
+ }
+}
+
+
+// +=================================================+
+// | LLAnimationBridge |
+// +=================================================+
+
+void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ LL_DEBUGS() << "LLAnimationBridge::buildContextMenu()" << LL_ENDL;
+ if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+ items.push_back(std::string("Animation Open"));
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+ }
+
+ items.push_back(std::string("Animation Separator"));
+ items.push_back(std::string("Animation Play"));
+ items.push_back(std::string("Animation Audition"));
+ }
+
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+// virtual
+void LLAnimationBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ((action == "playworld") || (action == "playlocal"))
+ {
+ if (getItem())
+ {
+ LLSD::String activate = "NONE";
+ if ("playworld" == action) activate = "Inworld";
+ if ("playlocal" == action) activate = "Locally";
+
+ LLPreviewAnim* preview = LLFloaterReg::showTypedInstance<LLPreviewAnim>("preview_anim", LLSD(mUUID));
+ if (preview)
+ {
+ preview->play(activate);
+ }
+ }
+ }
+ else
+ {
+ LLItemBridge::performAction(model, action);
+ }
+}
+
+void LLAnimationBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+/*
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES);
+ }
+*/
+}
+
+// +=================================================+
+// | LLObjectBridge |
+// +=================================================+
+
+// static
+LLUUID LLObjectBridge::sContextMenuItemID;
+
+LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ LLInventoryType::EType type,
+ U32 flags) :
+ LLItemBridge(inventory, root, uuid)
+{
+ mAttachPt = (flags & 0xff); // low bye of inventory flags
+ mIsMultiObject = is_flag_set(flags, LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS);
+ mInvType = type;
+}
+
+LLUIImagePtr LLObjectBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject);
+}
+
+LLInventoryObject* LLObjectBridge::getObject() const
+{
+ LLInventoryObject* object = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ object = (LLInventoryObject*)model->getObject(mUUID);
+ }
+ return object;
+}
+
+LLViewerInventoryItem* LLObjectBridge::getItem() const
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (model)
+ {
+ return model->getItem(mUUID);
+ }
+ return NULL;
+}
+
+LLViewerInventoryCategory* LLObjectBridge::getCategory() const
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (model)
+ {
+ return model->getCategory(mUUID);
+ }
+ return NULL;
+}
+
+// virtual
+void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if (isAddAction(action))
+ {
+ LLUUID object_id = mUUID;
+ LLViewerInventoryItem* item;
+ item = (LLViewerInventoryItem*)gInventory.getItem(object_id);
+ if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID()))
+ {
+ rez_attachment(item, NULL, true); // Replace if "Wear"ing.
+ }
+ else if(item && item->isFinished())
+ {
+ // must be in library. copy it to our inventory and put it on.
+ LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0));
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ LLUUID::null,
+ std::string(),
+ cb);
+ }
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+ else if ("wear_add" == action)
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding.
+ }
+ else if ("touch" == action)
+ {
+ handle_attachment_touch(mUUID);
+ }
+ else if ("edit" == action)
+ {
+ handle_attachment_edit(mUUID);
+ }
+ else if (isRemoveAction(action))
+ {
+ LLAppearanceMgr::instance().removeItemFromAvatar(mUUID);
+ }
+ else LLItemBridge::performAction(model, action);
+}
+
+void LLObjectBridge::openItem()
+{
+ // 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;
+ if (gAgentAvatarp->getAttachedPointName(mUUID, attachment_point_name))
+ {
+ LLStringUtil::format_map_t args;
+ args["[ATTACHMENT_POINT]"] = LLTrans::getString(attachment_point_name);
+
+ return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args);
+ }
+ else
+ {
+ LLStringUtil::format_map_t args;
+ args["[ATTACHMENT_ERROR]"] = LLTrans::getString(attachment_point_name);
+ return LLItemBridge::getLabelSuffix() + LLTrans::getString("AttachmentErrorMessage", args);
+ }
+ }
+ return LLItemBridge::getLabelSuffix();
+}
+
+void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace)
+{
+ const LLUUID& item_id = item->getLinkedUUID();
+
+ // Check for duplicate request.
+ if (isAgentAvatarValid() &&
+ gAgentAvatarp->isWearingAttachment(item_id))
+ {
+ LL_WARNS() << "ATT duplicate attachment request, ignoring" << LL_ENDL;
+ return;
+ }
+
+ S32 attach_pt = 0;
+ if (isAgentAvatarValid() && attachment)
+ {
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter)
+ {
+ if (iter->second == attachment)
+ {
+ attach_pt = iter->first;
+ break;
+ }
+ }
+ }
+
+ 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 (replace &&
+ (attachment && attachment->getNumObjects() > 0))
+ {
+ LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez);
+ }
+ else
+ {
+ LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);
+ }
+}
+
+bool confirm_attachment_rez(const LLSD& notification, const LLSD& response)
+{
+ if (!gAgentAvatarp->canAttachMoreObjects())
+ {
+ LLSD args;
+ args["MAX_ATTACHMENTS"] = llformat("%d", gAgentAvatarp->getMaxAttachments());
+ LLNotificationsUtil::add("MaxAttachmentsOnOutfit", args);
+ return false;
+ }
+
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0/*YES*/)
+ {
+ LLUUID item_id = notification["payload"]["item_id"].asUUID();
+ LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+
+ if (itemp)
+ {
+ // 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();
+ bool is_add = notification["payload"]["is_add"].asBoolean();
+
+ LL_DEBUGS("Avatar") << "ATT calling addAttachmentRequest " << (itemp ? itemp->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL;
+ LLAttachmentsMgr::instance().addAttachmentRequest(item_id, attachment_pt, is_add);
+ }
+ }
+ return false;
+}
+static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_attachment_rez);
+
+void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+
+ LLObjectBridge::sContextMenuItemID = mUUID;
+
+ LLInventoryItem *item = getItem();
+ if(item)
+ {
+ if (!isAgentAvatarValid()) return;
+
+ if( get_is_item_worn( mUUID ) )
+ {
+ items.push_back(std::string("Wearable And Object Separator"));
+
+ items.push_back(std::string("Attachment Touch"));
+ if ( ((flags & FIRST_SELECTED_ITEM) == 0) || !enable_attachment_touch(mUUID) )
+ {
+ disabled_items.push_back(std::string("Attachment Touch"));
+ }
+
+ items.push_back(std::string("Wearable Edit"));
+ if ( ((flags & FIRST_SELECTED_ITEM) == 0) || !get_is_item_editable(mUUID) )
+ {
+ disabled_items.push_back(std::string("Wearable Edit"));
+ }
+
+ items.push_back(std::string("Detach From Yourself"));
+ }
+ else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder())
+ {
+ 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
+ //items.push_back(std::string("Restore to Last Position"));
+
+ if (!gAgentAvatarp->canAttachMoreObjects())
+ {
+ 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"));
+ }
+ LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", true);
+ LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", true);
+ if (attach_menu
+ && (attach_menu->getChildCount() == 0)
+ && attach_hud_menu
+ && (attach_hud_menu->getChildCount() == 0)
+ && isAgentAvatarValid())
+ {
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ LLMenuItemCallGL::Params p;
+ std::string submenu_name = attachment->getName();
+ if (LLTrans::getString(submenu_name) != "")
+ {
+ p.name = (" ")+LLTrans::getString(submenu_name)+" ";
+ }
+ else
+ {
+ p.name = submenu_name;
+ }
+ LLSD cbparams;
+ cbparams["index"] = curiter->first;
+ 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";
+ p.on_enable.parameter = cbparams;
+ LLView* parent = attachment->getIsHUDAttachment() ? attach_hud_menu : attach_menu;
+ LLUICtrlFactory::create<LLMenuItemCallGL>(p, parent);
+ items.push_back(p.name);
+ }
+ }
+ }
+ }
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+bool LLObjectBridge::renameItem(const std::string& new_name)
+{
+ if(!isItemRenameable())
+ return false;
+ LLPreview::dirty(mUUID);
+ LLInventoryModel* model = getInventoryModel();
+ if(!model)
+ return false;
+ LLViewerInventoryItem* item = getItem();
+ if(item && (item->getName() != new_name))
+ {
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
+ new_item->rename(new_name);
+ new_item->updateServer(false);
+ model->updateItem(new_item);
+ model->notifyObservers();
+ buildDisplayName();
+
+ if (isAgentAvatarValid())
+ {
+ LLViewerObject* obj = gAgentAvatarp->getWornAttachment( item->getUUID() );
+ if(obj)
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ LLSelectMgr::getInstance()->addAsIndividual( obj, SELECT_ALL_TES, false );
+ LLSelectMgr::getInstance()->selectionSetObjectName( new_name );
+ LLSelectMgr::getInstance()->deselectAll();
+ }
+ }
+ }
+ // return false because we either notified observers (& therefore
+ // rebuilt) or we didn't update.
+ return false;
+}
+
+// +=================================================+
+// | LLLSLTextBridge |
+// +=================================================+
+
+void LLLSLTextBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+}
+
+// +=================================================+
+// | LLWearableBridge |
+// +=================================================+
+
+LLWearableBridge::LLWearableBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType inv_type,
+ LLWearableType::EType wearable_type) :
+ LLItemBridge(inventory, root, uuid),
+ mAssetType( asset_type ),
+ mWearableType(wearable_type)
+{
+ mInvType = inv_type;
+}
+
+bool LLWearableBridge::renameItem(const std::string& new_name)
+{
+ if (get_is_item_worn(mUUID))
+ {
+ gAgentWearables.setWearableName( mUUID, new_name );
+ }
+ return LLItemBridge::renameItem(new_name);
+}
+
+std::string LLWearableBridge::getLabelSuffix() const
+{
+ if (get_is_item_worn(mUUID))
+ {
+ // e.g. "(worn)"
+ return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn");
+ }
+ else
+ {
+ return LLItemBridge::getLabelSuffix();
+ }
+}
+
+LLUIImagePtr LLWearableBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(mAssetType, mInvType, mWearableType, false);
+}
+
+// virtual
+void LLWearableBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if (isAddAction(action))
+ {
+ wearOnAvatar();
+ }
+ else if ("wear_add" == action)
+ {
+ wearAddOnAvatar();
+ }
+ else if ("edit" == action)
+ {
+ editOnAvatar();
+ return;
+ }
+ else if (isRemoveAction(action))
+ {
+ removeFromAvatar();
+ return;
+ }
+ else LLItemBridge::performAction(model, action);
+}
+
+void LLWearableBridge::openItem()
+{
+ performAction(getInventoryModel(),
+ get_is_item_worn(mUUID) ? "take_off" : "wear");
+}
+
+void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLWearableBridge::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else if (isMarketplaceListingsFolder())
+ {
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ }
+ else
+ { // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere
+ bool can_open = ((flags & SUPPRESS_OPEN_ITEM) != SUPPRESS_OPEN_ITEM);
+
+ // If we have clothing, don't add "Open" as it's the same action as "Wear" SL-18976
+ LLViewerInventoryItem* item = getItem();
+ if (can_open && item)
+ {
+ can_open = (item->getType() != LLAssetType::AT_CLOTHING) &&
+ (item->getType() != LLAssetType::AT_BODYPART);
+ }
+ if (isLinkedObjectMissing())
+ {
+ can_open = false;
+ }
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+
+ if (can_open)
+ {
+ addOpenRightClickMenuOption(items);
+ }
+ else
+ {
+ 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);
+
+ items.push_back(std::string("Wearable And Object Separator"));
+ items.push_back(std::string("Wearable Edit"));
+
+ if (((flags & FIRST_SELECTED_ITEM) == 0) || (item && !gAgentWearables.isWearableModifiable(item->getUUID())))
+ {
+ disabled_items.push_back(std::string("Wearable Edit"));
+ }
+ // 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 And Object Wear"));
+ disabled_items.push_back(std::string("Wearable Add"));
+ disabled_items.push_back(std::string("Wearable Edit"));
+ }
+
+ // Disable wear and take off based on whether the item is worn.
+ if(item)
+ {
+ switch (item->getType())
+ {
+ case LLAssetType::AT_CLOTHING:
+ items.push_back(std::string("Take Off"));
+ // Fallthrough since clothing and bodypart share wear options
+ case LLAssetType::AT_BODYPART:
+ if (get_is_item_worn(item->getUUID()))
+ {
+ 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 And Object Wear"));
+ disabled_items.push_back(std::string("Take Off"));
+ disabled_items.push_back(std::string("Wearable Edit"));
+ }
+
+ if (LLWearableType::getInstance()->getAllowMultiwear(mWearableType))
+ {
+ items.push_back(std::string("Wearable Add"));
+ if (!gAgentWearables.canAddWearable(mWearableType))
+ {
+ disabled_items.push_back(std::string("Wearable Add"));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+// Called from menus
+// static
+bool LLWearableBridge::canWearOnAvatar(void* user_data)
+{
+ LLWearableBridge* self = (LLWearableBridge*)user_data;
+ if(!self) return false;
+ if(!self->isAgentInventory())
+ {
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem();
+ if(!item || !item->isFinished()) return false;
+ }
+ return (!get_is_item_worn(self->mUUID));
+}
+
+// Called from menus
+// static
+void LLWearableBridge::onWearOnAvatar(void* user_data)
+{
+ LLWearableBridge* self = (LLWearableBridge*)user_data;
+ if(!self) return;
+ self->wearOnAvatar();
+}
+
+void LLWearableBridge::wearOnAvatar()
+{
+ // TODO: investigate wearables may not be loaded at this point EXT-8231
+
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
+ }
+}
+
+void LLWearableBridge::wearAddOnAvatar()
+{
+ // TODO: investigate wearables may not be loaded at this point EXT-8231
+
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, false);
+ }
+}
+
+// static
+void LLWearableBridge::onWearOnAvatarArrived( LLViewerWearable* wearable, void* userdata )
+{
+ LLUUID* item_id = (LLUUID*) userdata;
+ if(wearable)
+ {
+ LLViewerInventoryItem* item = NULL;
+ item = (LLViewerInventoryItem*)gInventory.getItem(*item_id);
+ if(item)
+ {
+ if(item->getAssetUUID() == wearable->getAssetID())
+ {
+ gAgentWearables.setWearableItem(item, wearable);
+ gInventory.notifyObservers();
+ //self->getFolderItem()->refreshFromRoot();
+ }
+ else
+ {
+ LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL;
+ }
+ }
+ }
+ delete item_id;
+}
+
+// static
+// BAP remove the "add" code path once everything is fully COF-ified.
+void LLWearableBridge::onWearAddOnAvatarArrived( LLViewerWearable* wearable, void* userdata )
+{
+ LLUUID* item_id = (LLUUID*) userdata;
+ if(wearable)
+ {
+ LLViewerInventoryItem* item = NULL;
+ item = (LLViewerInventoryItem*)gInventory.getItem(*item_id);
+ if(item)
+ {
+ if(item->getAssetUUID() == wearable->getAssetID())
+ {
+ bool do_append = true;
+ gAgentWearables.setWearableItem(item, wearable, do_append);
+ gInventory.notifyObservers();
+ //self->getFolderItem()->refreshFromRoot();
+ }
+ else
+ {
+ LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL;
+ }
+ }
+ }
+ delete item_id;
+}
+
+// static
+bool LLWearableBridge::canEditOnAvatar(void* user_data)
+{
+ LLWearableBridge* self = (LLWearableBridge*)user_data;
+ if(!self) return false;
+
+ return (get_is_item_worn(self->mUUID));
+}
+
+// static
+void LLWearableBridge::onEditOnAvatar(void* user_data)
+{
+ LLWearableBridge* self = (LLWearableBridge*)user_data;
+ if(self)
+ {
+ self->editOnAvatar();
+ }
+}
+
+void LLWearableBridge::editOnAvatar()
+{
+ LLAgentWearables::editWearable(mUUID);
+}
+
+// static
+bool LLWearableBridge::canRemoveFromAvatar(void* user_data)
+{
+ LLWearableBridge* self = (LLWearableBridge*)user_data;
+ if( self && (LLAssetType::AT_BODYPART != self->mAssetType) )
+ {
+ return get_is_item_worn( self->mUUID );
+ }
+ return false;
+}
+
+void LLWearableBridge::removeFromAvatar()
+{
+ LL_WARNS() << "safe to remove?" << LL_ENDL;
+ if (get_is_item_worn(mUUID))
+ {
+ LLAppearanceMgr::instance().removeItemFromAvatar(mUUID);
+ }
+}
+
+
+// +=================================================+
+// | LLLinkItemBridge |
+// +=================================================+
+// For broken item links
+
+std::string LLLinkItemBridge::sPrefix("Link: ");
+
+void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ // *TODO: Translate
+ LL_DEBUGS() << "LLLink::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ items.push_back(std::string("Find Original"));
+ disabled_items.push_back(std::string("Find Original"));
+
+ if(isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else
+ {
+ items.push_back(std::string("Properties"));
+ addDeleteContextMenuOptions(items, disabled_items);
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+// +=================================================+
+// | LLSettingsBridge |
+// +=================================================+
+
+LLSettingsBridge::LLSettingsBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ LLSettingsType::type_e settings_type):
+ LLItemBridge(inventory, root, uuid),
+ mSettingsType(settings_type)
+{
+}
+
+LLUIImagePtr LLSettingsBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(LLAssetType::AT_SETTINGS, LLInventoryType::IT_SETTINGS, mSettingsType, false);
+}
+
+void LLSettingsBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("apply_settings_local" == action)
+ {
+ // Single item only
+ LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
+ if (!item)
+ return;
+ LLUUID asset_id = item->getAssetUUID();
+ LLEnvironment::instance().setEnvironment(LLEnvironment::ENV_LOCAL, asset_id, LLEnvironment::TRANSITION_INSTANT);
+ LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);
+ }
+ else if ("apply_settings_parcel" == action)
+ {
+ // Single item only
+ LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem());
+ if (!item)
+ return;
+ LLUUID asset_id = item->getAssetUUID();
+ std::string name = item->getName();
+
+ U32 flags(0);
+
+ if (!item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
+ flags |= LLSettingsBase::FLAG_NOMOD;
+ if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
+ flags |= LLSettingsBase::FLAG_NOTRANS;
+
+ LLParcel *parcel = LLViewerParcelMgr::instance().getAgentOrSelectedParcel();
+ if (!parcel)
+ {
+ LL_WARNS("INVENTORY") << "could not identify parcel." << LL_ENDL;
+ return;
+ }
+ S32 parcel_id = parcel->getLocalID();
+
+ LL_DEBUGS("ENVIRONMENT") << "Applying asset ID " << asset_id << " to parcel " << parcel_id << LL_ENDL;
+ LLEnvironment::instance().updateParcel(parcel_id, asset_id, name, LLEnvironment::NO_TRACK, -1, -1, flags);
+ LLEnvironment::instance().setSharedEnvironment();
+ }
+ else
+ LLItemBridge::performAction(model, action);
+}
+
+void LLSettingsBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ if (item->getPermissions().getOwner() != gAgent.getID())
+ LLNotificationsUtil::add("NoEditFromLibrary");
+ else
+ LLInvFVBridgeAction::doAction(item->getType(), mUUID, getInventoryModel());
+ }
+}
+
+void LLSettingsBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLSettingsBridge::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ if (isMarketplaceListingsFolder())
+ {
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ hide_context_entries(menu, items, disabled_items);
+ }
+ else if (isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else
+ {
+ items.push_back(std::string("Share"));
+ if (!canShare())
+ {
+ disabled_items.push_back(std::string("Share"));
+ }
+
+ addOpenRightClickMenuOption(items);
+ items.push_back(std::string("Properties"));
+
+ getClipboardEntries(true, items, disabled_items, flags);
+
+ items.push_back("Settings Separator");
+ items.push_back("Settings Apply Local");
+
+ items.push_back("Settings Apply Parcel");
+ if (!canUpdateParcel())
+ disabled_items.push_back("Settings Apply Parcel");
+
+ items.push_back("Settings Apply Region");
+ if (!canUpdateRegion())
+ disabled_items.push_back("Settings Apply Region");
+ }
+ addLinkReplaceMenuOption(items, disabled_items);
+ hide_context_entries(menu, items, disabled_items);
+}
+
+bool LLSettingsBridge::renameItem(const std::string& new_name)
+{
+ /*TODO: change internal settings name? */
+ return LLItemBridge::renameItem(new_name);
+}
+
+bool LLSettingsBridge::isItemRenameable() const
+{
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ return (item->getPermissions().allowModifyBy(gAgent.getID()));
+ }
+ return false;
+}
+
+bool LLSettingsBridge::canUpdateParcel() const
+{
+ return LLEnvironment::instance().canAgentUpdateParcelEnvironment();
+}
+
+bool LLSettingsBridge::canUpdateRegion() const
+{
+ return LLEnvironment::instance().canAgentUpdateRegionEnvironment();
+}
+
+
+// +=================================================+
+// | LLMaterialBridge |
+// +=================================================+
+
+void LLMaterialBridge::openItem()
+{
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel());
+ }
+}
+
+void LLMaterialBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ LL_DEBUGS() << "LLMaterialBridge::buildContextMenu()" << LL_ENDL;
+
+ if (isMarketplaceListingsFolder())
+ {
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ addMarketplaceContextMenuOptions(flags, items, disabled_items);
+ items.push_back(std::string("Properties"));
+ getClipboardEntries(false, items, disabled_items, flags);
+ hide_context_entries(menu, items, disabled_items);
+ }
+ else
+ {
+ LLItemBridge::buildContextMenu(menu, flags);
+ }
+}
+
+
+// +=================================================+
+// | LLLinkBridge |
+// +=================================================+
+// For broken folder links.
+std::string LLLinkFolderBridge::sPrefix("Link: ");
+LLUIImagePtr LLLinkFolderBridge::getIcon() const
+{
+ LLFolderType::EType folder_type = LLFolderType::FT_NONE;
+ const LLInventoryObject *obj = getInventoryObject();
+ if (obj)
+ {
+ LLViewerInventoryCategory* cat = NULL;
+ LLInventoryModel* model = getInventoryModel();
+ if(model)
+ {
+ cat = (LLViewerInventoryCategory*)model->getCategory(obj->getLinkedUUID());
+ if (cat)
+ {
+ folder_type = cat->getPreferredType();
+ }
+ }
+ }
+ return LLFolderBridge::getIcon(folder_type);
+}
+
+void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ // *TODO: Translate
+ LL_DEBUGS() << "LLLink::buildContextMenu()" << LL_ENDL;
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+
+ if (isItemInTrash())
+ {
+ addTrashContextMenuOptions(items, disabled_items);
+ }
+ else
+ {
+ items.push_back(std::string("Find Original"));
+ addDeleteContextMenuOptions(items, disabled_items);
+ }
+ hide_context_entries(menu, items, disabled_items);
+}
+void LLLinkFolderBridge::performAction(LLInventoryModel* model, std::string action)
+{
+ if ("goto" == action)
+ {
+ gotoItem();
+ return;
+ }
+ LLItemBridge::performAction(model,action);
+}
+void LLLinkFolderBridge::gotoItem()
+{
+ LLItemBridge::gotoItem();
+
+ const LLUUID &cat_uuid = getFolderID();
+ if (!cat_uuid.isNull())
+ {
+ LLFolderViewItem *base_folder = LLInventoryPanel::getActiveInventoryPanel()->getItemByID(cat_uuid);
+ if (base_folder)
+ {
+ base_folder->setOpen(true);
+ }
+ }
+}
+const LLUUID &LLLinkFolderBridge::getFolderID() const
+{
+ if (LLViewerInventoryItem *link_item = getItem())
+ {
+ if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory())
+ {
+ const LLUUID& cat_uuid = cat->getUUID();
+ return cat_uuid;
+ }
+ }
+ return LLUUID::null;
+}
+
+void LLUnknownItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ menuentry_vec_t items;
+ menuentry_vec_t disabled_items;
+ items.push_back(std::string("Properties"));
+ items.push_back(std::string("Rename"));
+ hide_context_entries(menu, items, disabled_items);
+}
+
+LLUIImagePtr LLUnknownItemBridge::getIcon() const
+{
+ return LLInventoryIcon::getIcon(LLAssetType::AT_UNKNOWN, mInvType);
+}
+
+
+/********************************************************************************
+ **
+ ** BRIDGE ACTIONS
+ **/
+
+// static
+void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type,
+ const LLUUID& uuid,
+ LLInventoryModel* 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();
+ delete action;
+ }
+}
+
+// static
+void LLInvFVBridgeAction::doAction(const LLUUID& uuid, LLInventoryModel* model)
+{
+ llassert(model);
+ LLViewerInventoryItem* item = model->getItem(uuid);
+ llassert(item);
+ if (item)
+ {
+ LLAssetType::EType asset_type = item->getType();
+ LLInvFVBridgeAction* action = createAction(asset_type,uuid,model);
+ if(action)
+ {
+ action->doIt();
+ delete action;
+ }
+ }
+}
+
+LLViewerInventoryItem* LLInvFVBridgeAction::getItem() const
+{
+ if (mModel)
+ return (LLViewerInventoryItem*)mModel->getItem(mUUID);
+ return NULL;
+}
+
+class LLTextureBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ if (getItem())
+ {
+ LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLTextureBridgeAction(){}
+protected:
+ LLTextureBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+class LLSoundBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ send_sound_trigger(item->getAssetUUID(), SOUND_GAIN);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLSoundBridgeAction(){}
+protected:
+ LLSoundBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+class LLLandmarkBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ // Opening (double-clicking) a landmark immediately teleports,
+ // but warns you the first time.
+ LLSD payload;
+ payload["asset_id"] = item->getAssetUUID();
+
+ LLSD args;
+ args["LOCATION"] = item->getName();
+
+ LLNotificationsUtil::add("TeleportFromLandmark", args, payload);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLLandmarkBridgeAction(){}
+protected:
+ LLLandmarkBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+class LLCallingCardBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item && item->getCreatorUUID().notNull())
+ {
+ LLAvatarActions::showProfile(item->getCreatorUUID());
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLCallingCardBridgeAction(){}
+protected:
+ LLCallingCardBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+
+};
+
+class LLNotecardBridgeAction
+: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLNotecardBridgeAction(){}
+protected:
+ LLNotecardBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+class LLGestureBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null);
+ preview->setFocus(true);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLGestureBridgeAction(){}
+protected:
+ LLGestureBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+class LLAnimationBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLAnimationBridgeAction(){}
+protected:
+ LLAnimationBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+class LLObjectBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ attachOrDetach();
+ }
+ virtual ~LLObjectBridgeAction(){}
+protected:
+ LLObjectBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+ void attachOrDetach();
+};
+
+void LLObjectBridgeAction::attachOrDetach()
+{
+ if (get_is_item_worn(mUUID))
+ {
+ LLAppearanceMgr::instance().removeItemFromAvatar(mUUID);
+ }
+ else
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(mUUID, true, false); // Don't replace if adding.
+ }
+}
+
+class LLLSLTextBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLLSLTextBridgeAction(){}
+protected:
+ LLLSLTextBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+class LLWearableBridgeAction: public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ wearOnAvatar();
+ }
+
+ virtual ~LLWearableBridgeAction(){}
+protected:
+ LLWearableBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+ bool isItemInTrash() const;
+ // return true if the item is in agent inventory. if false, it
+ // must be lost or in the inventory library.
+ bool isAgentInventory() const;
+ void wearOnAvatar();
+};
+
+bool LLWearableBridgeAction::isItemInTrash() const
+{
+ if(!mModel) return false;
+ const LLUUID trash_id = mModel->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ return mModel->isObjectDescendentOf(mUUID, trash_id);
+}
+
+bool LLWearableBridgeAction::isAgentInventory() const
+{
+ if(!mModel) return false;
+ if(gInventory.getRootFolderID() == mUUID) return true;
+ return mModel->isObjectDescendentOf(mUUID, gInventory.getRootFolderID());
+}
+
+void LLWearableBridgeAction::wearOnAvatar()
+{
+ // TODO: investigate wearables may not be loaded at this point EXT-8231
+
+ LLViewerInventoryItem* item = getItem();
+ if(item)
+ {
+ if (get_is_item_worn(mUUID))
+ {
+ if(item->getType() != LLAssetType::AT_BODYPART)
+ {
+ LLAppearanceMgr::instance().removeItemFromAvatar(item->getUUID());
+ }
+ }
+ else
+ {
+ LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true);
+ }
+ }
+}
+
+class LLSettingsBridgeAction
+ : public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ virtual void doIt()
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLSettingsType::type_e type = item->getSettingsType();
+ switch (type)
+ {
+ case LLSettingsType::ST_SKY:
+ LLFloaterReg::showInstance("env_fixed_environmentent_sky", LLSDMap("inventory_id", item->getUUID()), TAKE_FOCUS_YES);
+ break;
+ case LLSettingsType::ST_WATER:
+ LLFloaterReg::showInstance("env_fixed_environmentent_water", LLSDMap("inventory_id", item->getUUID()), TAKE_FOCUS_YES);
+ break;
+ case LLSettingsType::ST_DAYCYCLE:
+ LLFloaterReg::showInstance("env_edit_extdaycycle", LLSDMap("inventory_id", item->getUUID())("edit_context", "inventory"), TAKE_FOCUS_YES);
+ break;
+ default:
+ break;
+ }
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ virtual ~LLSettingsBridgeAction(){}
+protected:
+ LLSettingsBridgeAction(const LLUUID& id, LLInventoryModel* model) : LLInvFVBridgeAction(id, model) {}
+};
+
+class LLMaterialBridgeAction : public LLInvFVBridgeAction
+{
+ friend class LLInvFVBridgeAction;
+public:
+ void doIt() override
+ {
+ LLViewerInventoryItem* item = getItem();
+ if (item)
+ {
+ LLFloaterReg::showInstance("material_editor", LLSD(item->getUUID()), TAKE_FOCUS_YES);
+ }
+ LLInvFVBridgeAction::doIt();
+ }
+ ~LLMaterialBridgeAction() = default;
+private:
+ LLMaterialBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
+};
+
+
+LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type,
+ const LLUUID& uuid,
+ LLInventoryModel* model)
+{
+ LLInvFVBridgeAction* action = NULL;
+ switch(asset_type)
+ {
+ case LLAssetType::AT_TEXTURE:
+ action = new LLTextureBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_SOUND:
+ action = new LLSoundBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_LANDMARK:
+ action = new LLLandmarkBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_CALLINGCARD:
+ action = new LLCallingCardBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_OBJECT:
+ action = new LLObjectBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_NOTECARD:
+ action = new LLNotecardBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_ANIMATION:
+ action = new LLAnimationBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_GESTURE:
+ action = new LLGestureBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_LSL_TEXT:
+ action = new LLLSLTextBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_CLOTHING:
+ case LLAssetType::AT_BODYPART:
+ action = new LLWearableBridgeAction(uuid,model);
+ break;
+ case LLAssetType::AT_SETTINGS:
+ action = new LLSettingsBridgeAction(uuid, model);
+ break;
+ case LLAssetType::AT_MATERIAL:
+ action = new LLMaterialBridgeAction(uuid, model);
+ break;
+ default:
+ break;
+ }
+ return action;
+}
+
+/** Bridge Actions
+ **
+ ********************************************************************************/
+
+/************************************************************************/
+/* Recent Inventory Panel related classes */
+/************************************************************************/
+void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+ menuentry_vec_t disabled_items, items;
+ buildContextMenuOptions(flags, items, disabled_items);
+
+ 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,
+ LLFolderViewModelInventory* view_model,
+ LLFolderView* root,
+ const LLUUID& uuid,
+ U32 flags /*= 0x00*/ ) const
+{
+ LLInvFVBridge* new_listener = NULL;
+ if (asset_type == LLAssetType::AT_CATEGORY
+ && actual_asset_type != LLAssetType::AT_LINK_FOLDER)
+ {
+ new_listener = new LLRecentItemsFolderBridge(inv_type, inventory, root, uuid);
+ }
+ else
+ {
+ new_listener = LLInventoryFolderViewModelBuilder::createBridge(asset_type,
+ actual_asset_type,
+ inv_type,
+ inventory,
+ view_model,
+ root,
+ uuid,
+ flags);
+ }
+ return new_listener;
+}
+
+LLFolderViewGroupedItemBridge::LLFolderViewGroupedItemBridge()
+{
+}
+
+void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu)
+{
+ uuid_vec_t ids;
+ menuentry_vec_t disabled_items;
+ if (get_selection_item_uuids(selected_items, ids))
+ {
+ if (!LLAppearanceMgr::instance().canAddWearables(ids) && canWearSelected(ids))
+ {
+ 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"));
+ }
+ }
+ disable_context_entries_if_present(menu, disabled_items);
+}
+
+bool LLFolderViewGroupedItemBridge::canWearSelected(const uuid_vec_t& item_ids) const
+{
+ for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it)
+ {
+ const LLViewerInventoryItem* item = gInventory.getItem(*it);
+ if (!item || (item->getType() >= LLAssetType::AT_COUNT) || (item->getType() <= LLAssetType::AT_NONE))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+// EOF
|