From ee84500735a3af8ebbdf60efced59568566a86fd Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 16 Apr 2012 23:33:34 -0500 Subject: [PATCH] Added some cursory direct-delivery support. --- indra/newview/CMakeLists.txt | 2 + indra/newview/llappviewer.cpp | 6 + indra/newview/llinventorybridge.cpp | 609 ++++++++++++++++-- indra/newview/llinventorybridge.h | 10 + indra/newview/llinventoryfunctions.cpp | 172 +++++ indra/newview/llinventoryfunctions.h | 9 + indra/newview/llinventorymodel.cpp | 2 + indra/newview/llmarketplacenotifications.cpp | 90 +++ indra/newview/llmarketplacenotifications.h | 57 ++ indra/newview/llviewermessage.cpp | 6 + indra/newview/llviewermessage.h | 1 + .../default/xui/en-us/menu_inventory.xml | 7 + .../skins/default/xui/en-us/notifications.xml | 79 +++ .../skins/default/xui/en-us/strings.xml | 8 + 14 files changed, 1008 insertions(+), 50 deletions(-) create mode 100644 indra/newview/llmarketplacenotifications.cpp create mode 100644 indra/newview/llmarketplacenotifications.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 14e6235b4..25991f04e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -319,6 +319,7 @@ set(viewer_SOURCE_FILES llmaniprotate.cpp llmanipscale.cpp llmaniptranslate.cpp + llmarketplacenotifications.cpp llmediaremotectrl.cpp llmemoryview.cpp llmenucommands.cpp @@ -809,6 +810,7 @@ set(viewer_HEADER_FILES llmaniprotate.h llmanipscale.h llmaniptranslate.h + llmarketplacenotifications.h llmediaremotectrl.h llmemoryview.h llmenucommands.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0ab9fdefa..10871544b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -51,6 +51,8 @@ #include "llagentwearables.h" #include "llwindow.h" #include "llviewerstats.h" +//#include "llmarketplacefunctions.h" +#include "llmarketplacenotifications.h" #include "llmd5.h" #include "llmeshrepository.h" #include "llpumpio.h" @@ -4089,6 +4091,10 @@ void LLAppViewer::idle() // update media focus LLViewerMediaFocus::getInstance()->update(); + + // Update marketplace + //LLMarketplaceInventoryImporter::update(); + LLMarketplaceInventoryNotifications::update(); // objects and camera should be in sync, do LOD calculations now { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 507fddca9..c2a870ce1 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -76,6 +76,7 @@ #include "llinventoryclipboard.h" #include "lllineeditor.h" #include "llmenugl.h" +//#include "llmarketplacefunctions.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include "llpreviewanim.h" @@ -131,6 +132,11 @@ #include "rlvlocks.h" // [/RLVa:KB] +// Marketplace outbox current disabled +#define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU 1 +#define ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU 0 +#define BLOCK_WORN_ITEMS_IN_OUTBOX 1 + bool InventoryLinksEnabled() { return gHippoGridManager->getConnectedGrid()->supportsInvLinks(); @@ -184,6 +190,16 @@ bool isRemoveAction(const std::string& action) return ("take_off" == action || "detach" == action || "deactivate" == action); } +bool isMarketplaceCopyAction(const std::string& action) +{ + return (("copy_to_outbox" == action) || ("move_to_outbox" == action)); +} + +bool isMarketplaceSendAction(const std::string& action) +{ + return ("send_to_marketplace" == action); +} + // void gotImageForSaveItemAs(BOOL success, LLViewerTexture *src_vi, @@ -678,12 +694,16 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, { items.push_back(std::string("Find Links")); } - items.push_back(std::string("Rename")); - if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Rename")); - } + if (!isInboxFolder()) + { + items.push_back(std::string("Rename")); + if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Rename")); + } + } + if (show_asset_id) { items.push_back(std::string("Copy Asset UUID")); @@ -709,13 +729,24 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, { disabled_items.push_back(std::string("Copy")); } + + if (canListOnMarketplace()) + { + items.push_back(std::string("Marketplace Separator")); + + items.push_back(std::string("Merchant Copy")); + if (!canListOnMarketplaceNow()) + { + disabled_items.push_back(std::string("Merchant Copy")); + } + } } } // Don't allow items to be pasted directly into the COF. - if (!isCOFFolder()) + if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder()) { - items.push_back(std::string("Paste")); + items.push_back(std::string("Paste")); } if (!isClipboardPasteable() || ((flags & FIRST_SELECTED_ITEM) == 0)) { @@ -751,6 +782,10 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); + } + else if(isOutboxFolder()) + { + addOutboxContextMenuOptions(flags, items, disabled_items); } else { @@ -835,6 +870,32 @@ void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items) items.push_back(std::string("Open")); } +void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags, + menuentry_vec_t &items, + menuentry_vec_t &disabled_items) +{ + items.push_back(std::string("Rename")); + items.push_back(std::string("Delete")); + + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Rename")); + } + +#if ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU + if (isOutboxFolderDirectParent()) + { + items.push_back(std::string("Marketplace Separator")); + items.push_back(std::string("Marketplace Send")); + + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Marketplace Send")); + } + } +#endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU +} + // *TODO: remove this BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { @@ -931,6 +992,53 @@ BOOL LLInvFVBridge::isCOFFolder() const return LLAppearanceMgr::instance().getIsInCOF(mUUID); } +BOOL LLInvFVBridge::isInboxFolder() const +{ + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false); + + if (inbox_id.isNull()) + { + return FALSE; + } + + return gInventory.isObjectDescendentOf(mUUID, inbox_id); +} + +BOOL LLInvFVBridge::isOutboxFolder() const +{ + const LLUUID outbox_id = getOutboxFolder(); + + if (outbox_id.isNull()) + { + return FALSE; + } + + return gInventory.isObjectDescendentOf(mUUID, outbox_id); +} + +BOOL LLInvFVBridge::isOutboxFolderDirectParent() const +{ + BOOL outbox_is_parent = FALSE; + + const LLInventoryCategory *cat = gInventory.getCategory(mUUID); + + if (cat) + { + const LLUUID outbox_id = getOutboxFolder(); + + outbox_is_parent = (outbox_id.notNull() && (outbox_id == cat->getParentUUID())); + } + + return outbox_is_parent; +} + +const LLUUID LLInvFVBridge::getOutboxFolder() const +{ + const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); + + return outbox_id; +} + BOOL LLInvFVBridge::isItemPermissive() const { return FALSE; @@ -1112,6 +1220,110 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) } } + +bool LLInvFVBridge::canListOnMarketplace() const +{ +#if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU + + LLInventoryModel * model = getInventoryModel(); + + const LLViewerInventoryCategory * cat = model->getCategory(mUUID); + if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + return false; + } + + if (!isAgentInventory()) + { + return false; + } + + if (getOutboxFolder().isNull()) + { + return false; + } + + if (isInboxFolder() || isOutboxFolder()) + { + 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; + +#else + return false; +#endif +} + +bool LLInvFVBridge::canListOnMarketplaceNow() const +{ +#if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU + + bool can_list = true; + + // Do not allow listing while import is in progress + /*if (LLMarketplaceInventoryImporter::instanceExists()) + { + can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress(); + }*/ + + 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 = mRoot->getFolderByID(object_id); + if (object_folderp) + { + can_list = !object_folderp->isLoading(); + } + } + + if (can_list) + { + // Get outbox id + const LLUUID & outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + LLFolderViewItem * outbox_itemp = mRoot->getItemByID(outbox_id); + + if (outbox_itemp) + { + MASK mask = 0x0; + BOOL drop = FALSE; + EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType()); + void * cargo_data = (void *) obj; + + can_list = outbox_itemp->getListener()->dragOrDrop(mask, drop, cargo_type, cargo_data); + } + } + } + + return can_list; + +#else + return false; +#endif +} + + // +=================================================+ // | InventoryFVBridgeBuilder | // +=================================================+ @@ -1209,6 +1421,8 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) folder_view_itemp->getListener()->pasteLinkFromClipboard(); return; } + + // else if("reupload" == action) { LLInventoryItem* item = model->getItem(mUUID); @@ -1220,6 +1434,16 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) } } // + else if (isMarketplaceCopyAction(action)) + { + llinfos << "Copy item to marketplace action!" << llendl; + + LLInventoryItem* itemp = model->getItem(mUUID); + if (!itemp) return; + + const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); + copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId()); + } } // static @@ -1456,6 +1680,10 @@ BOOL LLItemBridge::isItemRenameable() const return FALSE; } // [/RLVa:KB] + if (isInboxFolder()) + { + return FALSE; + } return (item->getPermissions().allowModifyBy(gAgent.getID())); } @@ -1493,6 +1721,8 @@ BOOL LLItemBridge::removeItem() { return FALSE; } + + // move it to the trash LLPreview::hide(mUUID, TRUE); LLInventoryModel* model = getInventoryModel(); @@ -1815,6 +2045,38 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const } +static BOOL can_move_to_outbox(LLInventoryItem* inv_item) +{ + // Collapse links directly to items/folders + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + if (linked_item != NULL) + { + inv_item = linked_item; + } + + bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); + if (!allow_transfer) + { + return false; + } + +#if BLOCK_WORN_ITEMS_IN_OUTBOX + bool worn = get_is_item_worn(inv_item->getUUID()); + if (worn) + { + return false; + } +#endif + + bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); + if (calling_card) + { + return false; + } + + return true; +} int get_folder_levels(LLInventoryCategory* inv_cat) @@ -1872,8 +2134,11 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, const LLUUID &cat_id = inv_cat->getUUID(); const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); + const BOOL move_is_from_outbox = model->isObjectDescendentOf(cat_id, outbox_id); // check to make sure source is agent inventory, and is represented there. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); @@ -1977,6 +2242,94 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, is_movable = RlvFolderLocks::instance().canMoveFolder(cat_id, mUUID); } // [/RLVa:KB] + if (is_movable && move_is_into_outbox) + { + const int nested_folder_levels = get_folder_path_length(outbox_id, mUUID) + get_folder_levels(inv_cat); + + if (nested_folder_levels > (S32)gSavedSettings.getU32("InventoryOutboxMaxFolderDepth")) + { + is_movable = FALSE; + } + else + { + int dragged_folder_count = descendent_categories.count(); + int existing_item_count = 0; + int existing_folder_count = 0; + + const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID); + + if (master_folder != NULL) + { + if (model->isObjectDescendentOf(cat_id, master_folder->getUUID())) + { + // Don't use count because we're already inside the same category anyway + dragged_folder_count = 0; + } + else + { + existing_folder_count = 1; // Include the master folder in the count! + + // If we're in the drop operation as opposed to the drag without drop, we are doing a + // single category at a time so don't block based on the total amount of cargo data items + if (drop) + { + dragged_folder_count += 1; + } + else + { + // NOTE: The cargo id's count is a total of categories AND items but we err on the side of + // prevention rather than letting too many folders into the hierarchy of the outbox, + // when we're dragging the item to a new parent + dragged_folder_count += LLToolDragAndDrop::instance().getCargoIDsCount(); + } + } + + // Tally the total number of categories and items inside the master folder + + LLInventoryModel::cat_array_t existing_categories; + LLInventoryModel::item_array_t existing_items; + + model->collectDescendents(master_folder->getUUID(), existing_categories, existing_items, FALSE); + + existing_folder_count += existing_categories.count(); + existing_item_count += existing_items.count(); + } + else + { + // Assume a single category is being dragged to the outbox since we evaluate one at a time + // when not putting them under a parent item. + dragged_folder_count += 1; + } + + const int nested_folder_count = existing_folder_count + dragged_folder_count; + const int nested_item_count = existing_item_count + descendent_items.count(); + + if (nested_folder_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) + { + is_movable = FALSE; + } + else if (nested_item_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxItemCount")) + { + is_movable = FALSE; + } + + if (is_movable == TRUE) + { + for (S32 i=0; i < descendent_items.count(); ++i) + { + LLInventoryItem* item = descendent_items[i]; + if (!can_move_to_outbox(item)) + { + is_movable = FALSE; + break; + } + } + } + } + } + + // + //-------------------------------------------------------------------------------- accept = is_movable; @@ -2039,8 +2392,17 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, #endif } } + else if (move_is_into_outbox && !move_is_from_outbox) + { + copy_folder_to_outbox(inv_cat, mUUID, cat_id, LLToolDragAndDrop::getOperationId()); + } else { + if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false))) + { + set_dad_inbox_object(cat_id); + } + // Reparent the folder and restamp children if it's moving // into trash. LLInvFVBridge::changeCategoryParent( @@ -2053,12 +2415,26 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else if (LLToolDragAndDrop::SOURCE_WORLD == source) { - accept = move_inv_category_world_to_agent(cat_id, mUUID, drop); + if (move_is_into_outbox) + { + accept = FALSE; + } + else + { + accept = move_inv_category_world_to_agent(cat_id, mUUID, drop); + } } else if (LLToolDragAndDrop::SOURCE_LIBRARY == source) { - // Accept folders that contain complete outfits. - accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id); + if (move_is_into_outbox) + { + accept = FALSE; + } + else + { + // Accept folders that contain complete outfits. + accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id); + } if (accept && drop) { @@ -2428,6 +2804,33 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) restoreItem(); return; } +#ifndef LL_RELEASE_FOR_DOWNLOAD + else if ("delete_system_folder" == action) + { + removeSystemFolder(); + } +#endif + else if (isMarketplaceCopyAction(action)) + { + llinfos << "Copy folder to marketplace action!" << llendl; + + LLInventoryCategory * cat = gInventory.getCategory(mUUID); + if (!cat) return; + + const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); + copy_folder_to_outbox(cat, outbox_id, cat->getUUID(), LLToolDragAndDrop::getOperationId()); + } +#if ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU + else if (isMarketplaceSendAction(action)) + { + llinfos << "Send to marketplace action!" << llendl; + + LLInventoryCategory * cat = gInventory.getCategory(mUUID); + if (!cat) return; + + send_to_marketplace(cat); + } +#endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU } void LLFolderBridge::openItem() @@ -2750,6 +3153,10 @@ void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) mItems.clear(); // clear any items that used to exist addTrashContextMenuOptions(mItems, mDisabledItems); } + else if(isOutboxFolder()) + { + addOutboxContextMenuOptions(flags, mItems, mDisabledItems); + } else if(isAgentInventory()) // do not allow creating in library { LLViewerInventoryCategory *cat = getCategory(); @@ -2759,13 +3166,14 @@ void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) { LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); if(panel && !panel->getFilterWorn()) + if (!isInboxFolder() && !isOutboxFolder()) // don't allow creation in inbox or outbox { - mItems.push_back(std::string("New Folder")); - mItems.push_back(std::string("New Script")); - mItems.push_back(std::string("New Note")); - mItems.push_back(std::string("New Gesture")); - mItems.push_back(std::string("New Clothes")); - mItems.push_back(std::string("New Body Parts")); + mItems.push_back(std::string("New Folder")); + mItems.push_back(std::string("New Script")); + mItems.push_back(std::string("New Note")); + mItems.push_back(std::string("New Gesture")); + mItems.push_back(std::string("New Clothes")); + mItems.push_back(std::string("New Body Parts")); } getClipboardEntries(false, mItems, mDisabledItems, flags); @@ -2829,6 +3237,7 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags) if (trash_id == mUUID) return; if (isItemInTrash()) return; if (!isAgentInventory()) return; + if (isOutboxFolder()) return; LLFolderType::EType type = category->getPreferredType(); const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); @@ -2914,7 +3323,6 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) lldebugs << "LLFolderBridge::buildContextMenu()" << llendl; -// std::vector disabled_items; LLInventoryModel* model = getInventoryModel(); if(!model) return; @@ -3280,11 +3688,14 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); + const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); 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_outfit = (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_outbox = model->isObjectDescendentOf(mUUID, outbox_id); //(mUUID == outbox_id); + const BOOL move_is_from_outbox = model->isObjectDescendentOf(inv_item->getUUID(), outbox_id); LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); BOOL accept = FALSE; @@ -3378,6 +3789,32 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = can_move_to_landmarks(inv_item); } + else if (move_is_into_outbox) + { + accept = can_move_to_outbox(inv_item); + + if (accept) + { + const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID); + + int existing_item_count = LLToolDragAndDrop::instance().getCargoIDsCount(); + + if (master_folder != NULL) + { + LLInventoryModel::cat_array_t existing_categories; + LLInventoryModel::item_array_t existing_items; + + gInventory.collectDescendents(master_folder->getUUID(), existing_categories, existing_items, FALSE); + + existing_item_count += existing_items.count(); + } + + if (existing_item_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxItemCount")) + { + accept = FALSE; + } + } + } if(accept && drop) { @@ -3410,10 +3847,26 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { dropToOutfit(inv_item, move_is_into_current_outfit); } + else if (move_is_into_outbox) + { + if (move_is_from_outbox) + { + move_item_within_outbox(inv_item, mUUID, LLToolDragAndDrop::getOperationId()); + } + else + { + copy_item_to_outbox(inv_item, mUUID, LLUUID::null, LLToolDragAndDrop::getOperationId()); + } + } // 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, false, false))) + { + set_dad_inbox_object(inv_item->getUUID()); + } LLInvFVBridge::changeItemParent( model, @@ -3471,6 +3924,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = FALSE; } + else if (move_is_into_outbox) + { + accept = FALSE; + } + if (accept && drop) { LLMoveInv* move_inv = new LLMoveInv; @@ -3496,6 +3954,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) { + if (move_is_into_outbox) + { + 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. @@ -3516,7 +3979,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, if(item && item->isFinished()) { accept = TRUE; - if (move_is_into_current_outfit || move_is_into_outfit) + + if (move_is_into_outbox) + { + 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); } @@ -3643,6 +4111,10 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } + else if(isOutboxFolder()) + { + addOutboxContextMenuOptions(flags, items, disabled_items); + } else { addOpenRightClickMenuOption(items); @@ -3708,22 +4180,28 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - // *TODO: Translate - if(isItemInTrash()) + if (isOutboxFolder()) { - addTrashContextMenuOptions(items, disabled_items); + addOutboxContextMenuOptions(flags, items, disabled_items); } else { - items.push_back(std::string("Sound Open")); - items.push_back(std::string("Properties")); + if (isItemInTrash()) + { + addTrashContextMenuOptions(items, disabled_items); + } + else + { + items.push_back(std::string("Sound Open")); + items.push_back(std::string("Properties")); - getClipboardEntries(true, items, disabled_items, flags); + getClipboardEntries(true, items, disabled_items, flags); + } + + items.push_back(std::string("Sound Separator")); + items.push_back(std::string("Sound Play")); } - items.push_back(std::string("Sound Separator")); - items.push_back(std::string("Sound Play")); - hide_context_entries(menu, items, disabled_items); } @@ -3754,23 +4232,29 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - // *TODO: Translate lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; - if(isItemInTrash()) + if(isOutboxFolder()) { - addTrashContextMenuOptions(items, disabled_items); + addOutboxContextMenuOptions(flags, items, disabled_items); } else { - items.push_back(std::string("Landmark Open")); - items.push_back(std::string("Properties")); + if(isItemInTrash()) + { + addTrashContextMenuOptions(items, disabled_items); + } + else + { + items.push_back(std::string("Landmark Open")); + items.push_back(std::string("Properties")); - getClipboardEntries(true, items, disabled_items, flags); + getClipboardEntries(true, items, disabled_items, flags); + } + + items.push_back(std::string("Landmark Separator")); + items.push_back(std::string("Teleport To Landmark")); } - items.push_back(std::string("Landmark Separator")); - items.push_back(std::string("Teleport To Landmark")); - // Disable "About Landmark" menu item for // multiple landmarks selected. Only one landmark // info panel can be shown at a time. @@ -3997,6 +4481,10 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); + } + else if(isOutboxFolder()) + { + items.push_back(std::string("Delete")); } else { @@ -4311,6 +4799,10 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } + else if(isOutboxFolder()) + { + items.push_back(std::string("Delete")); + } else { @@ -4322,8 +4814,8 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Gesture Separator")); if (LLGestureMgr::instance().isGestureActive(getUUID())) { - items.push_back(std::string("Deactivate")); - } + items.push_back(std::string("Deactivate")); + } else { items.push_back(std::string("Activate")); @@ -4357,22 +4849,29 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t disabled_items; lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl; - if(isItemInTrash()) + if(isOutboxFolder()) { - addTrashContextMenuOptions(items, disabled_items); + items.push_back(std::string("Delete")); } else { - items.push_back(std::string("Animation Open")); - items.push_back(std::string("Properties")); + if(isItemInTrash()) + { + addTrashContextMenuOptions(items, disabled_items); + } + else + { + items.push_back(std::string("Animation Open")); + items.push_back(std::string("Properties")); - getClipboardEntries(true, items, disabled_items, flags); + 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")); } - items.push_back(std::string("Animation Separator")); - items.push_back(std::string("Animation Play")); - items.push_back(std::string("Animation Audition")); - hide_context_entries(menu, items, disabled_items); } @@ -4724,8 +5223,11 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); - } - + } + else if(isOutboxFolder()) + { + items.push_back(std::string("Delete")); + } else { items.push_back(std::string("Properties")); @@ -5085,6 +5587,10 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } + else if(isOutboxFolder()) + { + items.push_back(std::string("Delete")); + } else { // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere BOOL can_open = ((flags & SUPPRESS_OPEN_ITEM) != SUPPRESS_OPEN_ITEM); @@ -5537,6 +6043,10 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Restore Item")); } + else if(isOutboxFolder()) + { + addOutboxContextMenuOptions(flags, items, disabled_items); + } else { items.push_back(std::string("Properties")); @@ -5544,7 +6054,6 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) getClipboardEntries(true, items, disabled_items, flags); } - hide_context_entries(menu, items, disabled_items); } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 9d259e619..305d0649d 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -69,6 +69,8 @@ public: U32 flags = 0x00); virtual ~LLInvFVBridge() {} + bool canListOnMarketplace() const; + bool canListOnMarketplaceNow() const; //-------------------------------------------------------------------- // LLInvFVBridge functionality @@ -128,6 +130,9 @@ protected: virtual void addDeleteContextMenuOptions(menuentry_vec_t &items, menuentry_vec_t &disabled_items); virtual void addOpenRightClickMenuOption(menuentry_vec_t &items); + virtual void addOutboxContextMenuOptions(U32 flags, + menuentry_vec_t &items, + menuentry_vec_t &disabled_items); protected: LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid); @@ -139,6 +144,11 @@ protected: BOOL isAgentInventory() const; // false if lost or in the inventory library BOOL isCOFFolder() const; // true if COF or descendent of + BOOL isInboxFolder() const; // true if COF or descendent of marketplace inbox + BOOL isOutboxFolder() const; // true if COF or descendent of marketplace outbox + BOOL isOutboxFolderDirectParent() const; + const LLUUID getOutboxFolder() const; + virtual BOOL isItemPermissive() const; static void changeItemParent(LLInventoryModel* model, LLViewerInventoryItem* item, diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index ddcc57776..b4724536d 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -55,6 +55,7 @@ #include "llinventorymodel.h" #include "llinventorypanel.h" #include "lllineeditor.h" +#include "llmarketplacenotifications.h" #include "llmenugl.h" #include "llnotificationsutil.h" #include "llpanelmaininventory.h" @@ -518,6 +519,177 @@ void show_item_profile(const LLUUID& item_uuid) } } +void open_outbox() +{ + //LLFloaterReg::showInstance("outbox"); +} + +LLUUID create_folder_in_outbox_for_item(LLInventoryItem* item, const LLUUID& destFolderId, S32 operation_id) +{ + llassert(item); + llassert(destFolderId.notNull()); + + LLUUID created_folder_id = gInventory.createNewCategory(destFolderId, LLFolderType::FT_NONE, item->getName()); + gInventory.notifyObservers(); + + LLNotificationsUtil::add("OutboxFolderCreated"); + + return created_folder_id; +} + +void move_to_outbox_cb_action(const LLSD& payload) +{ + LLViewerInventoryItem * viitem = gInventory.getItem(payload["item_id"].asUUID()); + LLUUID dest_folder_id = payload["dest_folder_id"].asUUID(); + + if (viitem) + { + // when moving item directly into outbox create folder with that name + if (dest_folder_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + { + S32 operation_id = payload["operation_id"].asInteger(); + dest_folder_id = create_folder_in_outbox_for_item(viitem, dest_folder_id, operation_id); + } + + LLUUID parent = viitem->getParentUUID(); + + change_item_parent( + &gInventory, + viitem, + dest_folder_id, + false); + + LLUUID top_level_folder = payload["top_level_folder"].asUUID(); + + if (top_level_folder != LLUUID::null) + { + LLViewerInventoryCategory* category; + + while (parent.notNull()) + { + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(parent,cat_array,item_array); + + LLUUID next_parent; + + category = gInventory.getCategory(parent); + + if (!category) break; + + next_parent = category->getParentUUID(); + + if (cat_array->empty() && item_array->empty()) + { + remove_category(&gInventory, parent); + } + + if (parent == top_level_folder) + { + break; + } + + parent = next_parent; + } + } + + open_outbox(); + } +} + +void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id) +{ + // Collapse links directly to items/folders + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); + if (linked_category != NULL) + { + copy_folder_to_outbox(linked_category, dest_folder, top_level_folder, operation_id); + } + else + { + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + if (linked_item != NULL) + { + inv_item = (LLInventoryItem *) linked_item; + } + + // Check for copy permissions + if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + // when moving item directly into outbox create folder with that name + if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + { + dest_folder = create_folder_in_outbox_for_item(inv_item, dest_folder, operation_id); + } + + copy_inventory_item(gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + dest_folder, + inv_item->getName(), + LLPointer(NULL)); + + open_outbox(); + } + else + { + LLSD payload; + payload["item_id"] = inv_item->getUUID(); + payload["dest_folder_id"] = dest_folder; + payload["top_level_folder"] = top_level_folder; + payload["operation_id"] = operation_id; + + LLMarketplaceInventoryNotifications::addNoCopyNotification(payload, move_to_outbox_cb_action); + } + } +} + +void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id) +{ + // when moving item directly into outbox create folder with that name + if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + { + dest_folder = create_folder_in_outbox_for_item(inv_item, dest_folder, operation_id); + } + + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + + change_item_parent(&gInventory, + viewer_inv_item, + dest_folder, + false); +} + +void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id) +{ + LLUUID new_folder_id = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_cat->getName()); + gInventory.notifyObservers(); + + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(),cat_array,item_array); + + // copy the vector because otherwise the iterator won't be happy if we delete from it + 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; + copy_item_to_outbox(item, new_folder_id, top_level_folder, operation_id); + } + + 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; + copy_folder_to_outbox(category, new_folder_id, top_level_folder, operation_id); + } + + open_outbox(); +} + ///---------------------------------------------------------------------------- /// LLInventoryCollectFunctor implementations ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 20bc90d0d..689f5f1a2 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -71,6 +71,15 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s // Generates a string containing the path to the item specified by item_id. void append_path(const LLUUID& id, std::string& path); +void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id); +void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id); + +void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id); + +/** Miscellaneous global functions + ** ** + *******************************************************************************/ + /******************************************************************************** ** ** ** INVENTORY COLLECTOR FUNCTIONS diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 3cee5dad6..a2060a2a1 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -182,6 +182,8 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, const BOOL break_on_recursion) const { if (obj_id == cat_id) return TRUE; + //The while loop will ALWAYS return false if parent_id is null, regardless of cat_id being null too. Don't bother trying. + if(cat_id.isNull()) return FALSE; LLInventoryObject* obj = getObject(obj_id); int depthCounter = 0; while(obj) diff --git a/indra/newview/llmarketplacenotifications.cpp b/indra/newview/llmarketplacenotifications.cpp new file mode 100644 index 000000000..0886f9a99 --- /dev/null +++ b/indra/newview/llmarketplacenotifications.cpp @@ -0,0 +1,90 @@ +/** + * @file llmarketplacenotifications.cpp + * @brief Handler for notifications related to marketplace file I/O + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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$ + */ + +// Precompiled header +#include "llviewerprecompiledheaders.h" + +#include "llmarketplacenotifications.h" +#include "llnotificationsutil.h" + +#include "llerror.h" + +#include +#include + + +namespace LLMarketplaceInventoryNotifications +{ + typedef boost::signals2::signal no_copy_payload_cb_signal_t; + + static no_copy_payload_cb_signal_t* no_copy_cb_action = NULL; + static bool no_copy_notify_active = false; + static std::list no_copy_payloads; + + void notifyNoCopyCallback(const LLSD& notification, const LLSD& response) + { + const S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (option == 0) + { + llassert(!no_copy_payloads.empty()); + llassert(no_copy_cb_action != NULL); + + BOOST_FOREACH(const LLSD& payload, no_copy_payloads) + { + (*no_copy_cb_action)(payload); + } + } + + delete no_copy_cb_action; + no_copy_cb_action = NULL; + + no_copy_notify_active = false; + no_copy_payloads.clear(); + } + + void update() + { + if (!no_copy_notify_active && !no_copy_payloads.empty()) + { + no_copy_notify_active = true; + + LLNotificationsUtil::add("ConfirmNoCopyToOutbox", LLSD(), LLSD(), boost::bind(¬ifyNoCopyCallback, _1, _2)); + } + } + + void addNoCopyNotification(const LLSD& payload, const NoCopyCallbackFunction& cb) + { + if (no_copy_cb_action == NULL) + { + no_copy_cb_action = new no_copy_payload_cb_signal_t; + no_copy_cb_action->connect(boost::bind(cb, _1)); + } + + no_copy_payloads.push_back(payload); + } +} diff --git a/indra/newview/llmarketplacenotifications.h b/indra/newview/llmarketplacenotifications.h new file mode 100644 index 000000000..83a4e163c --- /dev/null +++ b/indra/newview/llmarketplacenotifications.h @@ -0,0 +1,57 @@ +/** + * @file llmarketplacenotifications.h + * @brief Handler for notifications related to marketplace file I/O + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMARKETPLACENOTIFICATIONS_H +#define LL_LLMARKETPLACENOTIFICATIONS_H + + +#include +#include + + +// +// This is a set of helper functions to handle a unique notification with multiple +// payloads, helpful when dragging and dropping items to the merchant outbox that +// trigger notifications that can potentially interfere with the current drag and +// drop operation. +// +// Notification payloads are cached locally when initiated, the notification itself +// is triggered on the following frame during the call to "update" and then the +// response is triggered once per payload. +// + +namespace LLMarketplaceInventoryNotifications +{ + void update(); + + typedef boost::function NoCopyCallbackFunction; + + void addNoCopyNotification(const LLSD& payload, const NoCopyCallbackFunction& cb); +}; + + +#endif // LL_LLMARKETPLACENOTIFICATIONS_H diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 64b58e022..63a71f5fb 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1062,6 +1062,12 @@ void LLViewerInventoryMoveObserver::changed(U32 mask) } } +void set_dad_inbox_object(const LLUUID& object_id) +{ + LLViewerInventoryMoveObserver* move_observer = new LLViewerInventoryMoveObserver(object_id); + gInventory.addObserver(move_observer); +} + //unlike the FetchObserver for AgentOffer, we only make one //instance of the AddedObserver for TaskOffers //and it never dies. We do this because we don't know the UUID of diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index bf109e789..fd9745d94 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -214,6 +214,7 @@ void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name) bool highlight_offered_object(const LLUUID& obj_id); void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid); +void set_dad_inbox_object(const LLUUID& object_id); struct LLOfferInfo { diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index babfedf9c..854a1cd35 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -301,6 +301,13 @@ name="Take Off" width="128"> + + + + + diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml index 51dea55cb..caee8473d 100644 --- a/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/indra/newview/skins/default/xui/en-us/notifications.xml @@ -283,8 +283,87 @@ Save changes to current clothing/body part? notext="Don't Save" yestext="Save"/> + +You don't have permission to copy one or more of these items to the Merchant Outbox. You can move them or leave them behind. + + + +A new folder has been created for each item you have transferred into the top level of your Merchant Outbox. + + + + + +Success + +All folders were successfully sent to the Marketplace. + + + + + +Some folders did not transfer + +Errors occurred when some folders were sent to the Marketplace. Those folders are still in your Merchant Outbox. + +See the [[MARKETPLACE_IMPORTS_URL] error log] for more information. + + + + + +Transfer failed + +No folders were sent to the Marketplace because of a system or network error. Try again later. + + + + + +Marketplace initialization failed + +Initialization with the Marketplace failed because of a system or network error. Try again later. + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/strings.xml b/indra/newview/skins/default/xui/en-us/strings.xml index dfeed8b66..d55f9e389 100644 --- a/indra/newview/skins/default/xui/en-us/strings.xml +++ b/indra/newview/skins/default/xui/en-us/strings.xml @@ -96,6 +96,14 @@ Land: Only a single item can be dragged here + You can not rez items in your merchant outbox + One or more of these objects cannot be sold or transferred. + Your merchant outbox can only accept items directly from your inventory + You can not put items you are wearing into your merchant outbox + You can not put calling cards into your merchant outbox + Depth of nested folders exceeds 3 + Subfolder count in top-level folder exceeds 20 + Item count in top-level folder exceeds 200 You can't move a folder into its child You can't move a folder into itself