diff options
Diffstat (limited to 'indra/newview/llinventorybridge.cpp')
-rwxr-xr-x | indra/newview/llinventorybridge.cpp | 1299 |
1 files changed, 929 insertions, 370 deletions
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1910656066..c19ed57f2a 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -40,6 +40,7 @@ #include "llfavoritesbar.h" // management of favorites folder #include "llfloateropenobject.h" #include "llfloaterreg.h" +#include "llfloatermarketplacelistings.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" #include "llfolderview.h" @@ -65,6 +66,7 @@ #include "llsidepanelappearance.h" #include "lltooldraganddrop.h" #include "lltrans.h" +#include "llurlaction.h" #include "llviewerassettype.h" #include "llviewerfoldertype.h" #include "llviewermenu.h" @@ -79,11 +81,6 @@ void copy_slurl_to_clipboard_callback_inv(const std::string& slurl); -// 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 - typedef std::pair<LLUUID, LLUUID> two_uuids_t; typedef std::list<two_uuids_t> two_uuids_list_t; @@ -269,13 +266,49 @@ BOOL LLInvFVBridge::isLibraryItem() const /** * @brief Adds this item into clipboard storage */ -BOOL LLInvFVBridge::cutToClipboard() const +BOOL LLInvFVBridge::cutToClipboard() +{ + const LLInventoryObject* obj = gInventory.getObject(mUUID); + if (obj && isItemMovable() && isItemRemovable()) + { + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const BOOL cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id); + + if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) || + LLMarketplaceData::instance().isListedAndActive(mUUID))) + { + // Prompt the user if cutting from a marketplace active listing + LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLInvFVBridge::callback_cutToClipboard, this, _1, _2)); + } + else + { + // Otherwise just perform the cut + return perform_cutToClipboard(); + } + } + 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); + BOOL added_to_clipboard = LLClipboard::instance().addToClipboard(mUUID); + removeObject(&gInventory, mUUID); // Always perform the remove even if the object couldn't make it to the clipboard + return added_to_clipboard; } return FALSE; } @@ -290,15 +323,22 @@ BOOL LLInvFVBridge::copyToClipboard() const return FALSE; } -// *TODO: make sure this does the right thing void LLInvFVBridge::showProperties() { - show_item_profile(mUUID); - - // Disable old properties floater; this is replaced by the sidepanel. - /* - LLFloaterReg::showInstance("properties", mUUID); - */ + 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::removeBatch(std::vector<LLFolderViewModelItem*>& batch) @@ -655,7 +695,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, if (!isInboxFolder()) { items.push_back(std::string("Rename")); - if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) + if (!isItemRenameable() || ((flags & FIRST_SELECTED_ITEM) == 0)) { disabled_items.push_back(std::string("Rename")); } @@ -693,15 +733,23 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Cut")); } - if (canListOnMarketplace()) + if (canListOnMarketplace() && !isMarketplaceListingsFolder()) { items.push_back(std::string("Marketplace Separator")); - items.push_back(std::string("Merchant Copy")); - if (!canListOnMarketplaceNow()) - { - disabled_items.push_back(std::string("Merchant Copy")); - } + if (gMenuHolder->getChild<LLView>("MerchantOutbox")->getVisible()) + { + items.push_back(std::string("Merchant Copy")); + if (!canListOnMarketplaceNow()) + { + disabled_items.push_back(std::string("Merchant Copy")); + } + } + if (gMenuHolder->getChild<LLView>("MarketplaceListings")->getVisible()) + { + items.push_back(std::string("Marketplace Copy")); + items.push_back(std::string("Marketplace Move")); + } } } } @@ -835,21 +883,114 @@ void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags, { 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 } +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) || ((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) || ((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")); + } + } + } + } + // Options available at all levels on items and categories + 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 (!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")); +} + + // *TODO: remove this BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { @@ -964,6 +1105,18 @@ BOOL LLInvFVBridge::isInboxFolder() const return gInventory.isObjectDescendentOf(mUUID, inbox_id); } +BOOL LLInvFVBridge::isMarketplaceListingsFolder() const +{ + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + + if (folder_id.isNull()) + { + return FALSE; + } + + return gInventory.isObjectDescendentOf(mUUID, folder_id); +} + BOOL LLInvFVBridge::isOutboxFolder() const { const LLUUID outbox_id = getOutboxFolder(); @@ -1125,11 +1278,18 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_CATEGORY: if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) { - // Create a link folder handler instead. + // Create a link folder handler instead new_listener = new LLLinkFolderBridge(inventory, root, uuid); - break; } - new_listener = new LLFolderBridge(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: @@ -1172,6 +1332,22 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) } } +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; @@ -1202,8 +1378,6 @@ bool LLInvFVBridge::canShare() const bool LLInvFVBridge::canListOnMarketplace() const { -#if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU - LLInventoryModel * model = getInventoryModel(); const LLViewerInventoryCategory * cat = model->getCategory(mUUID); @@ -1242,16 +1416,10 @@ bool LLInvFVBridge::canListOnMarketplace() const } 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 @@ -1297,10 +1465,6 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const } return can_list; - -#else - return false; -#endif } LLToolDragAndDrop::ESource LLInvFVBridge::getDragSource() const @@ -1392,7 +1556,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) else if ("cut" == action) { cutToClipboard(); - gInventory.removeObject(mUUID); return; } else if ("copy" == action) @@ -1433,6 +1596,13 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId()); } + else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action)) + { + LLInventoryItem* itemp = model->getItem(mUUID); + if (!itemp) return; + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action)); + } else if ("copy_slurl" == action) { LLViewerInventoryItem* item = static_cast<LLViewerInventoryItem*>(getItem()); @@ -1452,6 +1622,11 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string 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) @@ -1917,6 +2092,22 @@ void LLFolderBridge::buildDisplayName() const } } +std::string LLFolderBridge::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()); + } + + return LLInvFVBridge::getLabelSuffix(); +} + +LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const +{ + return LLFontGL::NORMAL; +} void LLFolderBridge::update() { @@ -1973,6 +2164,11 @@ BOOL LLFolderBridge::isItemRemovable() const return FALSE; } } + + if (isMarketplaceListingsFolder() && LLMarketplaceData::instance().getActivationState(mUUID)) + { + return FALSE; + } return TRUE; } @@ -2108,88 +2304,11 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const } -static BOOL can_move_to_outbox(LLInventoryItem* inv_item, std::string& tooltip_msg) -{ - // 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) - { - tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); - return false; - } - -#if BLOCK_WORN_ITEMS_IN_OUTBOX - bool worn = get_is_item_worn(inv_item->getUUID()); - if (worn) - { - tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); - return false; - } -#endif - - bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); - if (calling_card) - { - tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); - return false; - } - - return true; -} - - -int get_folder_levels(LLInventoryCategory* inv_cat) -{ - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); - - int max_child_levels = 0; - - for (S32 i=0; i < cats->size(); ++i) - { - LLInventoryCategory* category = cats->at(i); - max_child_levels = llmax(max_child_levels, get_folder_levels(category)); - } - - return 1 + max_child_levels; -} - -int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id) -{ - int depth = 0; - - if (ancestor_id == descendant_id) return depth; - - const LLInventoryCategory* category = gInventory.getCategory(descendant_id); - - while(category) - { - LLUUID parent_id = category->getParentUUID(); - - if (parent_id.isNull()) break; - - depth++; - - if (parent_id == ancestor_id) return depth; - - category = gInventory.getCategory(parent_id); - } - - LL_WARNS() << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; - return -1; -} BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL drop, - std::string& tooltip_msg) + std::string& tooltip_msg, + BOOL user_confirm) { LLInventoryModel* model = getInventoryModel(); @@ -2208,10 +2327,14 @@ 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 LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID from_folder_uuid = inv_cat->getParentUUID(); 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); + 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(); @@ -2239,6 +2362,18 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, 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; @@ -2264,6 +2399,12 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, 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; @@ -2331,93 +2472,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } - if (is_movable && move_is_into_outbox) + + if (is_movable && (move_is_into_outbox || move_is_into_marketplacelistings)) { - const int nested_folder_levels = get_folder_path_length(outbox_id, mUUID) + get_folder_levels(inv_cat); - - if (nested_folder_levels > gSavedSettings.getU32("InventoryOutboxMaxFolderDepth")) - { - tooltip_msg = LLTrans::getString("TooltipOutboxFolderLevels"); - is_movable = FALSE; - } - else - { - int dragged_folder_count = descendent_categories.size(); - 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().getCargoCount(); - } - } - - // 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.size(); - existing_item_count += existing_items.size(); - } - 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.size(); - - if (nested_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) - { - tooltip_msg = LLTrans::getString("TooltipOutboxTooManyFolders"); - is_movable = FALSE; - } - else if (nested_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) - { - tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects"); - is_movable = FALSE; - } - - if (is_movable == TRUE) - { - for (S32 i=0; i < descendent_items.size(); ++i) - { - LLInventoryItem* item = descendent_items[i]; - if (!can_move_to_outbox(item, tooltip_msg)) - { - is_movable = FALSE; - break; - } - } - } - } + const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : 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) @@ -2460,6 +2521,48 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, 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) { @@ -2485,6 +2588,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, { copy_folder_to_outbox(inv_cat, mUUID, cat_id, LLToolDragAndDrop::getOperationId()); } + else if (move_is_into_marketplacelistings) + { + move_folder_to_marketplacelistings(inv_cat, mUUID); + } else { if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false))) @@ -2500,11 +2607,38 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, mUUID, move_is_into_trash); } + 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()) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); + if (!validate_marketplacelistings(cat,NULL)) + { + 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); + } + } } } else if (LLToolDragAndDrop::SOURCE_WORLD == source) { - if (move_is_into_outbox) + if (move_is_into_outbox || move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -2516,7 +2650,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else if (LLToolDragAndDrop::SOURCE_LIBRARY == source) { - if (move_is_into_outbox) + if (move_is_into_outbox || move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -2886,7 +3020,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) else if ("cut" == action) { cutToClipboard(); - gInventory.removeObject(mUUID); return; } else if ("copy" == action) @@ -2914,6 +3047,88 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) restoreItem(); return; } + else if ("marketplace_list" == action) + { + if (depth_nesting_in_marketplace(mUUID) == 1) + { + LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID); + LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); + mMessage = ""; + if (!validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3))) + { + LLSD subs; + subs["[ERROR_CODE]"] = mMessage; + LLNotificationsUtil::add("MerchantListingFailed", subs); + } + else + { + LLMarketplaceData::instance().activateListing(mUUID,true); + } + } + return; + } + else if ("marketplace_activate" == action) + { + if (depth_nesting_in_marketplace(mUUID) == 2) + { + LLInventoryCategory* category = gInventory.getCategory(mUUID); + LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID); + } + return; + } + else if ("marketplace_unlist" == action) + { + if (depth_nesting_in_marketplace(mUUID) == 1) + { + LLMarketplaceData::instance().activateListing(mUUID,false); + } + 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); + } + return; + } + else if ("marketplace_create_listing" == action) + { + LLMarketplaceData::instance().createListing(mUUID); + 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) { @@ -2930,17 +3145,31 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); copy_folder_to_outbox(cat, outbox_id, cat->getUUID(), LLToolDragAndDrop::getOperationId()); } -#if ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU - else if (isMarketplaceSendAction(action)) + else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action)) { - LL_INFOS() << "Send to marketplace action!" << LL_ENDL; - LLInventoryCategory * cat = gInventory.getCategory(mUUID); if (!cat) return; - - send_to_marketplace(cat); - } -#endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("copy_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::openItem() @@ -3010,25 +3239,24 @@ LLFolderType::EType LLFolderBridge::getPreferredType() const // Icons for folders are based on the preferred type LLUIImagePtr LLFolderBridge::getIcon() const { - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat) - { - preferred_type = cat->getPreferredType(); - } - return getIcon(preferred_type); + return getFolderIcon(FALSE); } -// static -LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) +LLUIImagePtr LLFolderBridge::getIconOpen() const { - return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE)); + return getFolderIcon(TRUE); } -LLUIImagePtr LLFolderBridge::getIconOpen() const +LLUIImagePtr LLFolderBridge::getFolderIcon(BOOL is_open) const { - return LLUI::getUIImage(LLViewerFolderType::lookupIconName(getPreferredType(), TRUE)); + 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 @@ -3040,14 +3268,6 @@ LLUIImagePtr LLFolderBridge::getIconOverlay() const return NULL; } -std::string LLFolderBridge::getLabelSuffix() const -{ - static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); - return mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay() - ? llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()) - : LLStringUtil::null; -} - BOOL LLFolderBridge::renameItem(const std::string& new_name) { @@ -3131,10 +3351,42 @@ void LLFolderBridge::updateHierarchyCreationDate(time_t date) void LLFolderBridge::pasteFromClipboard() { LLInventoryModel* model = getInventoryModel(); - if(model && isClipboardPasteable()) + if (model && isClipboardPasteable()) { - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const BOOL paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); + + if (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 + { + perform_pasteFromClipboard(); + } +} + +void LLFolderBridge::perform_pasteFromClipboard() +{ + LLInventoryModel* model = getInventoryModel(); + if (model && isClipboardPasteable()) + { + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); @@ -3142,58 +3394,68 @@ void LLFolderBridge::pasteFromClipboard() 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_outbox = model->isObjectDescendentOf(mUUID, outbox_id); + const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); const BOOL move_is_into_favorites = (mUUID == favorites_id); std::vector<LLUUID> objects; LLClipboard::instance().pasteFromClipboard(objects); - - if (move_is_into_outbox) - { - LLFolderViewItem * outbox_itemp = mInventoryPanel.get()->getItemByID(mUUID); - - if (outbox_itemp) - { - LLToolDragAndDrop::instance().setCargoCount(objects.size()); - - BOOL can_list = TRUE; - - for (std::vector<LLUUID>::const_iterator iter = objects.begin(); - (iter != objects.end()) && (can_list == TRUE); - ++iter) - { - const LLUUID& item_id = (*iter); - LLInventoryItem *item = model->getItem(item_id); - - if (item) - { - MASK mask = 0x0; - BOOL drop = FALSE; - EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(item->getActualType()); - void * cargo_data = (void *) item; - std::string tooltip_msg; - - can_list = outbox_itemp->getViewModelItem()->dragOrDrop(mask, drop, cargo_type, cargo_data, tooltip_msg); - } - } - - LLToolDragAndDrop::instance().resetCargoCount(); - - if (can_list == FALSE) - { - // Notify user of failure somehow -- play error sound? modal dialog? - return; - } + + LLViewerInventoryCategory * dest_folder = getCategory(); + if (move_is_into_outbox || move_is_into_marketplacelistings) + { + std::string error_msg; + const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_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); + LLInventoryCategory *cat = model->getCategory(item_id); + + if (item && !can_move_item_to_marketplace(master_folder, dest_folder, item, error_msg, objects.size(), true)) + { + break; + } + if (cat && !can_move_folder_to_marketplace(master_folder, dest_folder, cat, error_msg, objects.size(), true, true)) + { + break; + } } - } - + 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) @@ -3221,21 +3483,44 @@ void LLFolderBridge::pasteFromClipboard() LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); llassert(vicat); if (vicat) - { - //changeCategoryParent() implicity calls dirtyFilter - changeCategoryParent(model, vicat, parent_id, FALSE); + { + // 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); + } } } else - { - LLViewerInventoryItem* viitem = dynamic_cast<LLViewerInventoryItem*>(item); - llassert(viitem); - if (viitem) - { - //changeItemParent() implicity calls dirtyFilter - changeItemParent(model, viitem, parent_id, FALSE); - } - } + { + 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); + } + } + } } else { @@ -3246,22 +3531,45 @@ void LLFolderBridge::pasteFromClipboard() llassert(vicat); if (vicat) { - copy_inventory_category(model, vicat, parent_id); + if (move_is_into_marketplacelistings) + { + move_folder_to_marketplacelistings(vicat, parent_id, true); + } + else + { + copy_inventory_category(model, vicat, parent_id); + } } } - else - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - parent_id, - std::string(), - LLPointer<LLInventoryCallback>(NULL)); - } - } - } - } + 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; + } + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + std::string(), + LLPointer<LLInventoryCallback>(NULL)); + } + } + } + } + } + } // Change mode to paste for next paste LLClipboard::instance().setCutMode(false); } @@ -3274,14 +3582,16 @@ void LLFolderBridge::pasteLinkFromClipboard() { const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); 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_outbox = model->isObjectDescendentOf(mUUID, outbox_id); + const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - if (move_is_into_outbox) + if (move_is_into_outbox || move_is_into_marketplacelistings) { // Notify user of failure somehow -- play error sound? modal dialog? return; @@ -3341,9 +3651,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& 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 &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, false); if (lost_and_found_id == mUUID) { @@ -3361,6 +3672,35 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items { 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("New Script")); + disabled_items.push_back(std::string("New Note")); + disabled_items.push_back(std::string("New Gesture")); + disabled_items.push_back(std::string("New Clothes")); + disabled_items.push_back(std::string("New Body Parts")); + } + 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(trash_id == mUUID) { // This is the trash. @@ -3390,12 +3730,14 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items { items.push_back(std::string("New Folder")); } - - 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 Clothes")); - items.push_back(std::string("New Body Parts")); + if (!isMarketplaceListingsFolder()) + { + 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 Clothes")); + items.push_back(std::string("New Body Parts")); + } } getClipboardEntries(false, items, disabled_items, flags); } @@ -3429,9 +3771,9 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items 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) ) + if (checkFolderForContentsOfType(model, is_wearable) || + checkFolderForContentsOfType(model, is_object) || + checkFolderForContentsOfType(model, is_gesture) ) { mWearables=TRUE; } @@ -3443,7 +3785,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items disabled_items.push_back(std::string("Delete System Folder")); } - if (!isOutboxFolder()) + if (!isOutboxFolder() && !isMarketplaceListingsFolder()) { items.push_back(std::string("Share")); if (!canShare()) @@ -3453,7 +3795,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items } // Add menu items that are dependent on the contents of the folder. LLViewerInventoryCategory* category = (LLViewerInventoryCategory *) model->getCategory(mUUID); - if (category) + if (category && (marketplace_listings_id != mUUID)) { uuid_vec_t folders; folders.push_back(category->getUUID()); @@ -3472,8 +3814,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items { // 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) @@ -3490,6 +3832,12 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& if (isItemInTrash()) return; if (!isAgentInventory()) return; if (isOutboxFolder()) 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); @@ -3509,11 +3857,6 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& } } - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } - #ifndef LL_RELEASE_FOR_DOWNLOAD if (LLFolderType::lookupIsProtectedType(type)) { @@ -3802,6 +4145,96 @@ void LLFolderBridge::modifyOutfit(BOOL append) LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, append ); } +// +=================================================+ +// | LLMarketplaceFolderBridge | +// +=================================================+ + +// LLMarketplaceFolderBridge is a specialized LLFolderBridge for use in Marketplace Inventory panels + +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(); + S32 depth = depth_nesting_in_marketplace(mUUID); + if ((preferred_type == LLFolderType::FT_NONE) && (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 + S32 stock_count = compute_stock_count(getUUID()); + if (stock_count == 0) + { + suffix += " (" + LLTrans::getString("MarketplaceNoStock") + ")"; + } + else if (stock_count != -1) + { + if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + suffix += " (" + LLTrans::getString("MarketplaceStock") + "=" + llformat("%d", stock_count) + ")"; + } + else + { + suffix += " (" + LLTrans::getString("MarketplaceMax") + "=" + llformat("%d", stock_count) + ")"; + } + } + // Add updating suffix + if (LLMarketplaceData::instance().isUpdating(getUUID())) + { + 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, LLMoveInv* move_inv) { @@ -3922,12 +4355,35 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c } } +// 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); + } +} + // 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) + std::string& tooltip_msg, + BOOL user_confirm) { LLInventoryModel* model = getInventoryModel(); @@ -3945,7 +4401,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, 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 LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + 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); @@ -3954,6 +4412,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, 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); const BOOL move_is_from_outbox = model->isObjectDescendentOf(inv_item->getUUID(), outbox_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; @@ -4011,7 +4471,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, accept = TRUE; - if (!is_movable) + if (!is_movable) { accept = FALSE; } @@ -4027,34 +4487,20 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = can_move_to_landmarks(inv_item); } - else if (move_is_into_outbox) + else if (move_is_into_outbox || move_is_into_marketplacelistings) { - accept = can_move_to_outbox(inv_item, tooltip_msg); - - if (accept) - { - const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID); - - int existing_item_count = LLToolDragAndDrop::instance().getCargoCount(); - - 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.size(); - } - - if (existing_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) - { - tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects"); - accept = FALSE; - } - } + const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : 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()); } + // Check that the folder can accept this item based on folder/item type compatibility (e.g. stock folder compatibility) + if (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 @@ -4082,6 +4528,22 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { 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 @@ -4094,7 +4556,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLFolderViewItem* itemp = destination_panel->getRootFolder()->getDraggingOverItem(); if (itemp) { - LLUUID srcItemId = inv_item->getUUID(); + LLUUID srcItemId = inv_item->getUUID(); LLUUID destItemId = static_cast<LLFolderViewModelItemInventory*>(itemp->getViewModelItem())->getUUID(); LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(srcItemId, destItemId); } @@ -4112,6 +4574,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { dropToOutfit(inv_item, move_is_into_current_outfit); } + // MERCHANT OUTBOX folder + // Move the item else if (move_is_into_outbox) { if (move_is_from_outbox) @@ -4123,6 +4587,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, copy_item_to_outbox(inv_item, mUUID, LLUUID::null, LLToolDragAndDrop::getOperationId()); } } + // MARKETPLACE LISTINGS folder + // Move the item + else if (move_is_into_marketplacelistings) + { + move_item_to_marketplacelistings(inv_item, mUUID); + } // NORMAL or TRASH folder // (move the item, restamp if into trash) else @@ -4139,8 +4609,24 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, mUUID, move_is_into_trash); } - - // + + 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()) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); + if (!validate_marketplacelistings(cat,NULL)) + { + LLMarketplaceData::instance().activateListing(version_folder_id,false); + } + } + // Update the listing we moved from anyway + update_marketplace_category(from_folder_uuid); + } + + // //-------------------------------------------------------------------------------- } } @@ -4189,7 +4675,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = FALSE; } - else if (move_is_into_outbox) + else if (move_is_into_outbox || move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -4227,7 +4713,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) { - if (move_is_into_outbox) + if (move_is_into_outbox || move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -4261,7 +4747,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = TRUE; - if (move_is_into_outbox) + if (move_is_into_outbox || move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -4434,6 +4920,12 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addOutboxContextMenuOptions(flags, 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")); @@ -4501,6 +4993,12 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addOutboxContextMenuOptions(flags, items, disabled_items); } + else if (isMarketplaceListingsFolder()) + { + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); + } else { if (isItemInTrash()) @@ -4576,6 +5074,12 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addOutboxContextMenuOptions(flags, items, disabled_items); } + else if (isMarketplaceListingsFolder()) + { + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); + } else { if(isItemInTrash()) @@ -4868,6 +5372,12 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Delete")); } + 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")); @@ -5000,6 +5510,25 @@ void LLNotecardBridge::openItem() } } +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 | // +=================================================+ @@ -5135,6 +5664,12 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Delete")); } + 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")); @@ -5189,6 +5724,12 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Delete")); } + else if (isMarketplaceListingsFolder()) + { + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); + } else { if(isItemInTrash()) @@ -5472,6 +6013,12 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Delete")); } + 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")); @@ -5694,6 +6241,12 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Delete")); } + 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); @@ -5994,6 +6547,12 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addOutboxContextMenuOptions(flags, 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("Properties")); |