diff options
Diffstat (limited to 'indra/newview/llfloatermarketplacelistings.cpp')
-rw-r--r-- | indra/newview/llfloatermarketplacelistings.cpp | 2132 |
1 files changed, 1066 insertions, 1066 deletions
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index 4a83d839fe..b75012c44f 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -1,1066 +1,1066 @@ -/**
- * @file llfloatermarketplacelistings.cpp
- * @brief Implementation of the marketplace listings floater and panels
- * @author merov@lindenlab.com
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloatermarketplacelistings.h"
-
-#include "llfloaterreg.h"
-#include "llfiltereditor.h"
-#include "llfolderview.h"
-#include "llinventorybridge.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llinventoryobserver.h"
-#include "llinventoryfunctions.h"
-#include "llmarketplacefunctions.h"
-#include "llnotificationhandler.h"
-#include "llnotificationmanager.h"
-#include "llnotificationsutil.h"
-#include "llsidepaneliteminfo.h"
-#include "llsidepaneltaskinfo.h"
-#include "lltabcontainer.h"
-#include "lltextbox.h"
-#include "lltrans.h"
-#include "llviewerwindow.h"
-
-///----------------------------------------------------------------------------
-/// LLPanelMarketplaceListings
-///----------------------------------------------------------------------------
-
-static LLPanelInjector<LLPanelMarketplaceListings> t_panel_status("llpanelmarketplacelistings");
-
-LLPanelMarketplaceListings::LLPanelMarketplaceListings()
-: mRootFolder(NULL)
-, mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME)
-, mFilterListingFoldersOnly(false)
-{
- mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2));
- mEnableCallbackRegistrar.add("Marketplace.ViewSort.CheckItem", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemCheck, this, _2));
-}
-
-bool LLPanelMarketplaceListings::postBuild()
-{
- childSetAction("add_btn", boost::bind(&LLPanelMarketplaceListings::onAddButtonClicked, this));
- childSetAction("audit_btn", boost::bind(&LLPanelMarketplaceListings::onAuditButtonClicked, this));
-
- mFilterEditor = getChild<LLFilterEditor>("filter_editor");
- mFilterEditor->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onFilterEdit, this, _2));
-
- mAuditBtn = getChild<LLButton>("audit_btn");
- mAuditBtn->setEnabled(false);
-
- return LLPanel::postBuild();
-}
-
-bool LLPanelMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- bool handled = (handled_view != NULL);
- // Special case the drop zone
- if (handled && (handled_view->getName() == "marketplace_drop_zone"))
- {
- LLFolderView* root_folder = getRootFolder();
- handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- }
- return handled;
-}
-
-void LLPanelMarketplaceListings::buildAllPanels()
-{
- // Build the All panel first
- LLInventoryPanel* panel_all_items;
- panel_all_items = buildInventoryPanel("All Items", "panel_marketplace_listings_inventory.xml");
- panel_all_items->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
- panel_all_items->getFilter().markDefault();
-
- // Build the other panels
- LLInventoryPanel* panel;
- panel = buildInventoryPanel("Active Items", "panel_marketplace_listings_listed.xml");
- panel->getFilter().setFilterMarketplaceActiveFolders();
- panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
- panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing");
- panel->getFilter().markDefault();
- panel = buildInventoryPanel("Inactive Items", "panel_marketplace_listings_unlisted.xml");
- panel->getFilter().setFilterMarketplaceInactiveFolders();
- panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
- panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing");
- panel->getFilter().markDefault();
- panel = buildInventoryPanel("Unassociated Items", "panel_marketplace_listings_unassociated.xml");
- panel->getFilter().setFilterMarketplaceUnassociatedFolders();
- panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
- panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing");
- panel->getFilter().markDefault();
-
- // Set the tab panel
- LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs");
- tabs_panel->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onTabChange, this));
- tabs_panel->selectTabPanel(panel_all_items); // All panel selected by default
- mRootFolder = panel_all_items->getRootFolder(); // Keep the root of the all panel
-
- // Set the default sort order
- setSortOrder(gSavedSettings.getU32("MarketplaceListingsSortOrder"));
-}
-
-LLInventoryPanel* LLPanelMarketplaceListings::buildInventoryPanel(const std::string& childname, const std::string& filename)
-{
- LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs");
- LLInventoryPanel* panel = LLUICtrlFactory::createFromFile<LLInventoryPanel>(filename, tabs_panel, LLInventoryPanel::child_registry_t::instance());
- llassert(panel != NULL);
-
- // Set sort order and callbacks
- panel = getChild<LLInventoryPanel>(childname);
- panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME);
- panel->setSelectCallback(boost::bind(&LLPanelMarketplaceListings::onSelectionChange, this, panel, _1, _2));
-
- return panel;
-}
-
-void LLPanelMarketplaceListings::setSortOrder(U32 sort_order)
-{
- mSortOrder = sort_order;
- gSavedSettings.setU32("MarketplaceListingsSortOrder", sort_order);
-
- // Set each panel with that sort order
- LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs");
- LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items");
- panel->setSortOrder(mSortOrder);
- panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items");
- panel->setSortOrder(mSortOrder);
- panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items");
- panel->setSortOrder(mSortOrder);
- panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items");
- panel->setSortOrder(mSortOrder);
-}
-
-void LLPanelMarketplaceListings::onFilterEdit(const std::string& search_string)
-{
- // Find active panel
- LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
- if (panel)
- {
- // Save filter string (needed when switching tabs)
- mFilterSubString = search_string;
- // Set filter string on active panel
- panel->setFilterSubString(mFilterSubString);
- }
-}
-
-void LLPanelMarketplaceListings::draw()
-{
- if (LLMarketplaceData::instance().checkDirtyCount())
- {
- update_all_marketplace_count();
- }
-
- // Get the audit button enabled only after the whole inventory is fetched
- if (!mAuditBtn->getEnabled())
- {
- LLInventoryModelBackgroundFetch* inst = LLInventoryModelBackgroundFetch::getInstance();
- mAuditBtn->setEnabled(inst->isEverythingFetched() && !inst->folderFetchActive());
- }
-
- LLPanel::draw();
-}
-
-void LLPanelMarketplaceListings::onSelectionChange(LLInventoryPanel *panel, const std::deque<LLFolderViewItem*>& items, bool user_action)
-{
- panel->onSelectionChange(items, user_action);
-}
-
-bool LLPanelMarketplaceListings::allowDropOnRoot()
-{
- LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
- return (panel ? panel->getAllowDropOnRoot() : false);
-}
-
-void LLPanelMarketplaceListings::onTabChange()
-{
- // Find active panel
- LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
- if (panel)
- {
- // If the panel doesn't allow drop on root, it doesn't allow the creation of new folder on root either
- LLButton* add_btn = getChild<LLButton>("add_btn");
- add_btn->setEnabled(panel->getAllowDropOnRoot());
-
- // Set filter string on active panel
- panel->setFilterSubString(mFilterSubString);
-
- // Show/hide the drop zone and resize the inventory tabs panel accordingly
- LLPanel* drop_zone = (LLPanel*)getChild<LLPanel>("marketplace_drop_zone");
- bool drop_zone_visible = drop_zone->getVisible();
- if (drop_zone_visible != panel->getAllowDropOnRoot())
- {
- LLPanel* tabs = (LLPanel*)getChild<LLPanel>("tab_container_panel");
- S32 delta_height = drop_zone->getRect().getHeight();
- delta_height = (drop_zone_visible ? delta_height : -delta_height);
- tabs->reshape(tabs->getRect().getWidth(),tabs->getRect().getHeight() + delta_height);
- tabs->translate(0,-delta_height);
- }
- drop_zone->setVisible(panel->getAllowDropOnRoot());
- }
-}
-
-void LLPanelMarketplaceListings::onAddButtonClicked()
-{
- LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
- llassert(marketplacelistings_id.notNull());
- LLFolderType::EType preferred_type = LLFolderType::lookup("category");
- LLHandle<LLPanel> handle = getHandle();
- gInventory.createNewCategory(
- marketplacelistings_id,
- preferred_type,
- LLStringUtil::null,
- [handle](const LLUUID &new_cat_id)
- {
- // Find active panel
- LLPanel *marketplace_panel = handle.get();
- if (!marketplace_panel)
- {
- return;
- }
- LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
- if (panel)
- {
- gInventory.notifyObservers();
- panel->setSelectionByID(new_cat_id, true);
- panel->getRootFolder()->setNeedsAutoRename(true);
- }
- }
- );
-}
-
-void LLPanelMarketplaceListings::onAuditButtonClicked()
-{
- LLSD data(LLSD::emptyMap());
- LLFloaterReg::showInstance("marketplace_validation", data);
-}
-
-void LLPanelMarketplaceListings::onViewSortMenuItemClicked(const LLSD& userdata)
-{
- std::string chosen_item = userdata.asString();
-
- // Sort options
- if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent"))
- {
- // We're making sort options exclusive, default is SO_FOLDERS_BY_NAME
- if (chosen_item == "sort_by_stock_amount")
- {
- setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_WEIGHT);
- }
- else if (chosen_item == "sort_by_name")
- {
- setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME);
- }
- else if (chosen_item == "sort_by_recent")
- {
- setSortOrder(LLInventoryFilter::SO_DATE);
- }
- }
- // Filter option
- else if (chosen_item == "show_only_listing_folders")
- {
- mFilterListingFoldersOnly = !mFilterListingFoldersOnly;
- // Set each panel with that filter flag
- LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs");
- LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items");
- panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
- panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items");
- panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
- panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items");
- panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
- panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items");
- panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
- }
-}
-
-bool LLPanelMarketplaceListings::onViewSortMenuItemCheck(const LLSD& userdata)
-{
- std::string chosen_item = userdata.asString();
-
- if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent"))
- {
- if (chosen_item == "sort_by_stock_amount")
- {
- return (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_WEIGHT);
- }
- else if (chosen_item == "sort_by_name")
- {
- return (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME);
- }
- else if (chosen_item == "sort_by_recent")
- {
- return (mSortOrder & LLInventoryFilter::SO_DATE);
- }
- }
- else if (chosen_item == "show_only_listing_folders")
- {
- return mFilterListingFoldersOnly;
- }
- return false;
-}
-
-///----------------------------------------------------------------------------
-/// LLMarketplaceListingsAddedObserver helper class
-///----------------------------------------------------------------------------
-
-class LLMarketplaceListingsAddedObserver : public LLInventoryCategoryAddedObserver
-{
-public:
- LLMarketplaceListingsAddedObserver(LLFloaterMarketplaceListings * marketplace_listings_floater)
- : LLInventoryCategoryAddedObserver()
- , mMarketplaceListingsFloater(marketplace_listings_floater)
- {
- }
-
- void done()
- {
- for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it)
- {
- LLViewerInventoryCategory* added_category = *it;
-
- LLFolderType::EType added_category_type = added_category->getPreferredType();
-
- if (added_category_type == LLFolderType::FT_MARKETPLACE_LISTINGS)
- {
- mMarketplaceListingsFloater->initializeMarketPlace();
- }
- }
- }
-
-private:
- LLFloaterMarketplaceListings * mMarketplaceListingsFloater;
-};
-
-///----------------------------------------------------------------------------
-/// LLFloaterMarketplaceListings
-///----------------------------------------------------------------------------
-
-LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
-: LLFloater(key)
-, mCategoriesObserver(NULL)
-, mCategoryAddedObserver(NULL)
-, mRootFolderId(LLUUID::null)
-, mInventoryStatus(NULL)
-, mInventoryInitializationInProgress(NULL)
-, mInventoryPlaceholder(NULL)
-, mInventoryText(NULL)
-, mInventoryTitle(NULL)
-, mPanelListings(NULL)
-, mPanelListingsSet(false)
-, mRootFolderCreating(false)
-{
-}
-
-LLFloaterMarketplaceListings::~LLFloaterMarketplaceListings()
-{
- if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
- {
- gInventory.removeObserver(mCategoriesObserver);
- }
- delete mCategoriesObserver;
-
- if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
- {
- gInventory.removeObserver(mCategoryAddedObserver);
- }
- delete mCategoryAddedObserver;
-}
-
-bool LLFloaterMarketplaceListings::postBuild()
-{
- mInventoryStatus = getChild<LLTextBox>("marketplace_status");
- mInventoryInitializationInProgress = getChild<LLView>("initialization_progress_indicator");
- mInventoryPlaceholder = getChild<LLView>("marketplace_listings_inventory_placeholder_panel");
- mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("marketplace_listings_inventory_placeholder_text");
- mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("marketplace_listings_inventory_placeholder_title");
-
- mPanelListings = static_cast<LLPanelMarketplaceListings*>(getChild<LLUICtrl>("panel_marketplace_listing"));
-
- LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterMarketplaceListings::onFocusReceived, this));
-
- // Observe category creation to catch marketplace listings creation (moot if already existing)
- mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this);
- gInventory.addObserver(mCategoryAddedObserver);
-
-
- // Fetch aggressively so we can interact with listings as soon as possible
- if (!fetchContents())
- {
- const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
- LLInventoryModelBackgroundFetch::instance().start(marketplacelistings_id, true);
- }
-
-
- return true;
-}
-
-void LLFloaterMarketplaceListings::onClose(bool app_quitting)
-{
-}
-
-void LLFloaterMarketplaceListings::onOpen(const LLSD& key)
-{
- //
- // Initialize the Market Place or go update the marketplace listings
- //
- if (LLMarketplaceData::instance().getSLMStatus() <= MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE)
- {
- initializeMarketPlace();
- }
- else
- {
- updateView();
- }
-}
-
-void LLFloaterMarketplaceListings::onFocusReceived()
-{
- updateView();
-}
-
-bool LLFloaterMarketplaceListings::fetchContents()
-{
- if (mRootFolderId.notNull() &&
- (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_LOADING) &&
- (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_DONE))
- {
- LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this));
- LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING);
- LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true);
- LLMarketplaceData::instance().getSLMListings();
- return true;
- }
- return false;
-}
-
-void LLFloaterMarketplaceListings::setRootFolder()
-{
- if ((LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) &&
- (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT))
- {
- // If we are *not* a merchant or we have no market place connection established yet, do nothing
- return;
- }
- if (!gInventory.isInventoryUsable())
- {
- return;
- }
-
- LLFolderType::EType preferred_type = LLFolderType::FT_MARKETPLACE_LISTINGS;
- // We are a merchant. Get the Marketplace listings folder, create it if needs be.
- LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(preferred_type);
-
- if (marketplacelistings_id.isNull())
- {
- if (!mRootFolderCreating)
- {
- mRootFolderCreating = true;
- gInventory.createNewCategory(
- gInventory.getRootFolderID(),
- preferred_type,
- LLStringUtil::null,
- [](const LLUUID &new_cat_id)
- {
- LLFloaterMarketplaceListings* marketplace = LLFloaterReg::findTypedInstance<LLFloaterMarketplaceListings>("marketplace_listings");
- if (marketplace)
- {
- if (new_cat_id.notNull())
- {
- // will call setRootFolder again
- marketplace->updateView();
- }
- // don't update in case of failure, createNewCategory can return
- // immediately if cap is missing and will cause a loop
- else
- {
- // unblock
- marketplace->mRootFolderCreating = false;
- LL_WARNS("SLM") << "Inventory warning: Failed to create marketplace listings folder for a merchant" << LL_ENDL;
- }
- }
- }
- );
- }
- return;
- }
-
- mRootFolderCreating = false;
-
- // No longer need to observe new category creation
- if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
- {
- gInventory.removeObserver(mCategoryAddedObserver);
- delete mCategoryAddedObserver;
- mCategoryAddedObserver = NULL;
- }
- llassert(!mCategoryAddedObserver);
-
- if (marketplacelistings_id == mRootFolderId)
- {
- LL_WARNS("SLM") << "Inventory warning: Marketplace listings folder already set" << LL_ENDL;
- return;
- }
-
- mRootFolderId = marketplacelistings_id;
-}
-
-void LLFloaterMarketplaceListings::setPanels()
-{
- if (mRootFolderId.isNull())
- {
- return;
- }
-
- // Consolidate Marketplace listings
- // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention,
- // things get messy and conventions get broken down eventually
- gInventory.consolidateForType(mRootFolderId, LLFolderType::FT_MARKETPLACE_LISTINGS);
-
- // Now that we do have a non NULL root, we can build the inventory panels
- mPanelListings->buildAllPanels();
-
- // Create observer for marketplace listings modifications
- if (!mCategoriesObserver)
- {
- mCategoriesObserver = new LLInventoryCategoriesObserver();
- llassert(mCategoriesObserver);
- gInventory.addObserver(mCategoriesObserver);
- mCategoriesObserver->addCategory(mRootFolderId, boost::bind(&LLFloaterMarketplaceListings::onChanged, this));
- }
-
- // Get the content of the marketplace listings folder
- fetchContents();
-
- // Flag that this is done
- mPanelListingsSet = true;
-}
-
-void LLFloaterMarketplaceListings::initializeMarketPlace()
-{
- LLMarketplaceData::instance().initializeSLM(boost::bind(&LLFloaterMarketplaceListings::updateView, this));
-}
-
-S32 LLFloaterMarketplaceListings::getFolderCount()
-{
- if (mPanelListings && mRootFolderId.notNull())
- {
- LLInventoryModel::cat_array_t * cats;
- LLInventoryModel::item_array_t * items;
- gInventory.getDirectDescendentsOf(mRootFolderId, cats, items);
-
- return (cats->size() + items->size());
- }
- else
- {
- return 0;
- }
-}
-
-void LLFloaterMarketplaceListings::setStatusString(const std::string& statusString)
-{
- mInventoryStatus->setText(statusString);
-}
-
-void LLFloaterMarketplaceListings::updateView()
-{
- U32 mkt_status = LLMarketplaceData::instance().getSLMStatus();
- bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT);
- U32 data_fetched = LLMarketplaceData::instance().getSLMDataFetched();
-
- // Get or create the root folder if we are a merchant and it hasn't been done already
- if (mRootFolderId.isNull() && is_merchant)
- {
- setRootFolder();
- }
- if (mRootFolderCreating)
- {
- // waiting for callback
- return;
- }
-
- // Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading
- if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) )
- {
- // Just show the loading indicator in that case and fetch the data (fetch will be skipped if it's already loading)
- mInventoryInitializationInProgress->setVisible(true);
- mPanelListings->setVisible(false);
- fetchContents();
- return;
- }
- else
- {
- mInventoryInitializationInProgress->setVisible(false);
- }
-
- // Update the middle portion : tabs or messages
- if (getFolderCount() > 0)
- {
- if (!mPanelListingsSet)
- {
- // We need to rebuild the tabs cleanly the first time we make them visible
- setPanels();
- }
- mPanelListings->setVisible(true);
- mInventoryPlaceholder->setVisible(false);
- }
- else
- {
- mPanelListings->setVisible(false);
- mInventoryPlaceholder->setVisible(true);
-
- std::string text;
- std::string title;
- std::string tooltip;
-
- const LLSD& subs = LLMarketplaceData::getMarketplaceStringSubstitutions();
-
- // Update the top message or flip to the tabs and folders view
- // *TODO : check those messages and create better appropriate ones in strings.xml
- if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE)
- {
- std::string reason = LLMarketplaceData::instance().getSLMConnectionfailureReason();
- if (reason.empty())
- {
- text = LLTrans::getString("InventoryMarketplaceConnectionError");
- }
- else
- {
- LLSD args;
- args["[REASON]"] = reason;
- text = LLTrans::getString("InventoryMarketplaceConnectionErrorReason", args);
- }
-
- title = LLTrans::getString("InventoryOutboxErrorTitle");
- tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
- LL_WARNS() << "Marketplace status code: " << mkt_status << LL_ENDL;
- }
- else if (mRootFolderId.notNull())
- {
- // "Marketplace listings is empty!" message strings
- text = LLTrans::getString("InventoryMarketplaceListingsNoItems", subs);
- title = LLTrans::getString("InventoryMarketplaceListingsNoItemsTitle");
- tooltip = LLTrans::getString("InventoryMarketplaceListingsNoItemsTooltip");
- }
- else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING)
- {
- // "Initializing!" message strings
- text = LLTrans::getString("InventoryOutboxInitializing", subs);
- title = LLTrans::getString("InventoryOutboxInitializingTitle");
- tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip");
- }
- else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT)
- {
- // "Not a merchant!" message strings
- text = LLTrans::getString("InventoryOutboxNotMerchant", subs);
- title = LLTrans::getString("InventoryOutboxNotMerchantTitle");
- tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip");
- }
- else
- {
- // "Errors!" message strings
- text = LLTrans::getString("InventoryMarketplaceError", subs);
- title = LLTrans::getString("InventoryOutboxErrorTitle");
- tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
- LL_WARNS() << "Marketplace status code: " << mkt_status << LL_ENDL;
- }
-
- mInventoryText->setValue(text);
- mInventoryTitle->setValue(title);
- mInventoryPlaceholder->getParent()->setToolTip(tooltip);
- }
-}
-
-bool LLFloaterMarketplaceListings::isAccepted(EAcceptance accept)
-{
- return (accept >= ACCEPT_YES_COPY_SINGLE);
-}
-
-bool LLFloaterMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- // If there's no panel to accept drops or no existing marketplace listings folder, we refuse all drop
- if (!mPanelListings || mRootFolderId.isNull())
- {
- return false;
- }
-
- tooltip_msg = "";
-
- // Pass to the children
- LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- bool handled = (handled_view != NULL);
-
- // If no one handled it or it was not accepted and we drop on an empty panel, we try to accept it at the floater level
- // as if it was dropped on the marketplace listings root folder
- if ((!handled || !isAccepted(*accept)) && !mPanelListings->getVisible() && mRootFolderId.notNull())
- {
- if (!mPanelListingsSet)
- {
- setPanels();
- }
- LLFolderView* root_folder = mPanelListings->getRootFolder();
- handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- }
-
- return handled;
-}
-
-bool LLFloaterMarketplaceListings::handleHover(S32 x, S32 y, MASK mask)
-{
- return LLFloater::handleHover(x, y, mask);
-}
-
-void LLFloaterMarketplaceListings::onMouseLeave(S32 x, S32 y, MASK mask)
-{
- LLFloater::onMouseLeave(x, y, mask);
-}
-
-void LLFloaterMarketplaceListings::onChanged()
-{
- LLViewerInventoryCategory* category = gInventory.getCategory(mRootFolderId);
- if (mRootFolderId.notNull() && category)
- {
- updateView();
- }
- else
- {
- // Invalidate the marketplace listings data
- mRootFolderId.setNull();
- }
-}
-
-//-----------------------------------------------------------------------------
-// LLFloaterAssociateListing
-//-----------------------------------------------------------------------------
-
-// Tell if a listing has one only version folder
-bool hasUniqueVersionFolder(const LLUUID& folder_id)
-{
- LLInventoryModel::cat_array_t* categories;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(folder_id, categories, items);
- return (categories->size() == 1);
-}
-
-LLFloaterAssociateListing::LLFloaterAssociateListing(const LLSD& key)
-: LLFloater(key)
-, mUUID()
-{
-}
-
-LLFloaterAssociateListing::~LLFloaterAssociateListing()
-{
- gFocusMgr.releaseFocusIfNeeded( this );
-}
-
-bool LLFloaterAssociateListing::postBuild()
-{
- getChild<LLButton>("OK")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::apply, this, true));
- getChild<LLButton>("Cancel")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::cancel, this));
- getChild<LLLineEditor>("listing_id")->setPrevalidate(&LLTextValidate::validateNonNegativeS32);
- center();
-
- return LLFloater::postBuild();
-}
-
-bool LLFloaterAssociateListing::handleKeyHere(KEY key, MASK mask)
-{
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- apply();
- return true;
- }
- else if (key == KEY_ESCAPE && mask == MASK_NONE)
- {
- cancel();
- return true;
- }
-
- return LLFloater::handleKeyHere(key, mask);
-}
-
-// static
-LLFloaterAssociateListing* LLFloaterAssociateListing::show(const LLUUID& folder_id)
-{
- LLFloaterAssociateListing* floater = LLFloaterReg::showTypedInstance<LLFloaterAssociateListing>("associate_listing");
-
- floater->mUUID = folder_id;
-
- return floater;
-}
-
-// Callback for apply if DAMA required...
-void LLFloaterAssociateListing::callback_apply(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option == 0) // YES
- {
- apply(false);
- }
-}
-
-void LLFloaterAssociateListing::apply(bool user_confirm)
-{
- if (mUUID.notNull())
- {
- S32 id = (S32)getChild<LLUICtrl>("listing_id")->getValue().asInteger();
- if (id > 0)
- {
- // Check if the id exists in the merchant SLM DB: note that this record might exist in the LLMarketplaceData
- // structure even if unseen in the UI, for instance, if its listing_uuid doesn't exist in the merchant inventory
- LLUUID listing_uuid = LLMarketplaceData::instance().getListingFolder(id);
- if (listing_uuid.notNull() && user_confirm && LLMarketplaceData::instance().getActivationState(listing_uuid) && !hasUniqueVersionFolder(mUUID))
- {
- // Look for user confirmation before unlisting
- LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFloaterAssociateListing::callback_apply, this, _1, _2));
- return;
- }
- // Associate the id with the user chosen folder
- LLMarketplaceData::instance().associateListing(mUUID,listing_uuid,id);
- }
- else
- {
- LLNotificationsUtil::add("AlertMerchantListingInvalidID");
- }
- }
- closeFloater();
-}
-
-void LLFloaterAssociateListing::cancel()
-{
- closeFloater();
-}
-
-//-----------------------------------------------------------------------------
-// LLFloaterMarketplaceValidation
-//-----------------------------------------------------------------------------
-
-// Note: The key is the UUID of the folder to validate.
-// Validates the whole marketplace listings content if UUID is null.
-
-LLFloaterMarketplaceValidation::LLFloaterMarketplaceValidation(const LLSD& key)
-: LLFloater(key),
-mEditor(NULL)
-{
-}
-
-bool LLFloaterMarketplaceValidation::postBuild()
-{
- childSetAction("OK", onOK, this);
-
- // This widget displays the validation messages
- mEditor = getChild<LLTextEditor>("validation_text");
- mEditor->setEnabled(false);
- mEditor->setFocus(true);
- mEditor->setValue(LLSD());
-
- return true;
-}
-
-LLFloaterMarketplaceValidation::~LLFloaterMarketplaceValidation()
-{
-}
-
-// virtual
-void LLFloaterMarketplaceValidation::draw()
-{
- // draw children
- LLFloater::draw();
-}
-
-void LLFloaterMarketplaceValidation::onOpen(const LLSD& key)
-{
- // Clear the messages
- clearMessages();
-
- // Get the folder UUID to validate. Use the whole marketplace listing if none provided.
- LLUUID cat_id(key.asUUID());
- if (cat_id.isNull())
- {
- cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
- }
-
- // Validates the folder
- if (cat_id.notNull())
- {
- LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
- cat_id,
- NULL,
- boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3),
- false);
- }
-
- // Handle the listing folder being processed
- handleCurrentListing();
-
- // Dump result to the editor panel
- if (mEditor)
- {
- mEditor->setValue(LLSD());
- if (mMessages.empty())
- {
- // Display a no error message
- mEditor->appendText(LLTrans::getString("Marketplace Validation No Error"), false);
- }
- else
- {
- // Print out all the messages to the panel
- message_list_t::iterator mCurrentLine = mMessages.begin();
- bool new_line = false;
- while (mCurrentLine != mMessages.end())
- {
- // Errors are printed in bold, other messages in normal font
- LLStyle::Params style;
- LLFontDescriptor new_desc(mEditor->getFont()->getFontDesc());
- new_desc.setStyle(mCurrentLine->mErrorLevel == LLError::LEVEL_ERROR ? LLFontGL::BOLD : LLFontGL::NORMAL);
- LLFontGL* new_font = LLFontGL::getFont(new_desc);
- style.font = new_font;
- mEditor->appendText(mCurrentLine->mMessage, new_line, style);
- new_line = true;
- mCurrentLine++;
- }
- }
- }
- // We don't need the messages anymore
- clearMessages();
-}
-
-// static
-void LLFloaterMarketplaceValidation::onOK( void* userdata )
-{
- // destroys this object
- LLFloaterMarketplaceValidation* self = (LLFloaterMarketplaceValidation*) userdata;
- self->clearMessages();
- self->closeFloater();
-}
-
-void LLFloaterMarketplaceValidation::appendMessage(std::string& message, S32 depth, LLError::ELevel log_level)
-{
- // Dump previous listing messages if we're starting a new listing
- if (depth == 1)
- {
- handleCurrentListing();
- }
-
- // Store the message in the current listing message list
- Message current_message;
- current_message.mErrorLevel = log_level;
- current_message.mMessage = message;
- mCurrentListingMessages.push_back(current_message);
- mCurrentListingErrorLevel = (mCurrentListingErrorLevel < log_level ? log_level : mCurrentListingErrorLevel);
-}
-
-// Move the current listing messages to the general list if needs be and reset the current listing data
-void LLFloaterMarketplaceValidation::handleCurrentListing()
-{
- // Dump the current folder messages to the general message list if level warrants it
- if (mCurrentListingErrorLevel > LLError::LEVEL_INFO)
- {
- message_list_t::iterator mCurrentLine = mCurrentListingMessages.begin();
- while (mCurrentLine != mCurrentListingMessages.end())
- {
- mMessages.push_back(*mCurrentLine);
- mCurrentLine++;
- }
- }
-
- // Reset the current listing
- mCurrentListingMessages.clear();
- mCurrentListingErrorLevel = LLError::LEVEL_INFO;
-}
-
-void LLFloaterMarketplaceValidation::clearMessages()
-{
- mMessages.clear();
- mCurrentListingMessages.clear();
- mCurrentListingErrorLevel = LLError::LEVEL_INFO;
-}
-
-//-----------------------------------------------------------------------------
-// LLFloaterItemProperties
-//-----------------------------------------------------------------------------
-
-LLFloaterItemProperties::LLFloaterItemProperties(const LLSD& key)
-: LLFloater(key)
-{
-}
-
-LLFloaterItemProperties::~LLFloaterItemProperties()
-{
-}
-
-bool LLFloaterItemProperties::postBuild()
-{
- return LLFloater::postBuild();
-}
-
-void LLFloaterItemProperties::onOpen(const LLSD& key)
-{
- // Tell the panel which item it needs to visualize
- LLPanel* panel = findChild<LLPanel>("sidepanel");
-
- LLSidepanelItemInfo* item_panel = dynamic_cast<LLSidepanelItemInfo*>(panel);
- if (item_panel)
- {
- item_panel->setItemID(key["id"].asUUID());
- if (key.has("object"))
- {
- item_panel->setObjectID(key["object"].asUUID());
- }
- item_panel->setParentFloater(this);
- }
-
- LLSidepanelTaskInfo* task_panel = dynamic_cast<LLSidepanelTaskInfo*>(panel);
- if (task_panel)
- {
- task_panel->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
- }
-}
-
-LLMultiItemProperties::LLMultiItemProperties(const LLSD& key)
- : LLMultiFloater(LLSD())
-{
- // start with a small rect in the top-left corner ; will get resized
- LLRect rect;
- rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 350, 350);
- setRect(rect);
- LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup(key.asString());
- if (last_floater)
- {
- stackWith(*last_floater);
- }
- setTitle(LLTrans::getString("MultiPropertiesTitle"));
- buildTabContainer();
-}
+/** + * @file llfloatermarketplacelistings.cpp + * @brief Implementation of the marketplace listings floater and panels + * @author merov@lindenlab.com + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatermarketplacelistings.h" + +#include "llfloaterreg.h" +#include "llfiltereditor.h" +#include "llfolderview.h" +#include "llinventorybridge.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" +#include "llinventoryfunctions.h" +#include "llmarketplacefunctions.h" +#include "llnotificationhandler.h" +#include "llnotificationmanager.h" +#include "llnotificationsutil.h" +#include "llsidepaneliteminfo.h" +#include "llsidepaneltaskinfo.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lltrans.h" +#include "llviewerwindow.h" + +///---------------------------------------------------------------------------- +/// LLPanelMarketplaceListings +///---------------------------------------------------------------------------- + +static LLPanelInjector<LLPanelMarketplaceListings> t_panel_status("llpanelmarketplacelistings"); + +LLPanelMarketplaceListings::LLPanelMarketplaceListings() +: mRootFolder(NULL) +, mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME) +, mFilterListingFoldersOnly(false) +{ + mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2)); + mEnableCallbackRegistrar.add("Marketplace.ViewSort.CheckItem", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemCheck, this, _2)); +} + +bool LLPanelMarketplaceListings::postBuild() +{ + childSetAction("add_btn", boost::bind(&LLPanelMarketplaceListings::onAddButtonClicked, this)); + childSetAction("audit_btn", boost::bind(&LLPanelMarketplaceListings::onAuditButtonClicked, this)); + + mFilterEditor = getChild<LLFilterEditor>("filter_editor"); + mFilterEditor->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onFilterEdit, this, _2)); + + mAuditBtn = getChild<LLButton>("audit_btn"); + mAuditBtn->setEnabled(false); + + return LLPanel::postBuild(); +} + +bool LLPanelMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + bool handled = (handled_view != NULL); + // Special case the drop zone + if (handled && (handled_view->getName() == "marketplace_drop_zone")) + { + LLFolderView* root_folder = getRootFolder(); + handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + return handled; +} + +void LLPanelMarketplaceListings::buildAllPanels() +{ + // Build the All panel first + LLInventoryPanel* panel_all_items; + panel_all_items = buildInventoryPanel("All Items", "panel_marketplace_listings_inventory.xml"); + panel_all_items->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel_all_items->getFilter().markDefault(); + + // Build the other panels + LLInventoryPanel* panel; + panel = buildInventoryPanel("Active Items", "panel_marketplace_listings_listed.xml"); + panel->getFilter().setFilterMarketplaceActiveFolders(); + panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing"); + panel->getFilter().markDefault(); + panel = buildInventoryPanel("Inactive Items", "panel_marketplace_listings_unlisted.xml"); + panel->getFilter().setFilterMarketplaceInactiveFolders(); + panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing"); + panel->getFilter().markDefault(); + panel = buildInventoryPanel("Unassociated Items", "panel_marketplace_listings_unassociated.xml"); + panel->getFilter().setFilterMarketplaceUnassociatedFolders(); + panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().setDefaultEmptyLookupMessage("MarketplaceNoListing"); + panel->getFilter().markDefault(); + + // Set the tab panel + LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs"); + tabs_panel->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onTabChange, this)); + tabs_panel->selectTabPanel(panel_all_items); // All panel selected by default + mRootFolder = panel_all_items->getRootFolder(); // Keep the root of the all panel + + // Set the default sort order + setSortOrder(gSavedSettings.getU32("MarketplaceListingsSortOrder")); +} + +LLInventoryPanel* LLPanelMarketplaceListings::buildInventoryPanel(const std::string& childname, const std::string& filename) +{ + LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs"); + LLInventoryPanel* panel = LLUICtrlFactory::createFromFile<LLInventoryPanel>(filename, tabs_panel, LLInventoryPanel::child_registry_t::instance()); + llassert(panel != NULL); + + // Set sort order and callbacks + panel = getChild<LLInventoryPanel>(childname); + panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME); + panel->setSelectCallback(boost::bind(&LLPanelMarketplaceListings::onSelectionChange, this, panel, _1, _2)); + + return panel; +} + +void LLPanelMarketplaceListings::setSortOrder(U32 sort_order) +{ + mSortOrder = sort_order; + gSavedSettings.setU32("MarketplaceListingsSortOrder", sort_order); + + // Set each panel with that sort order + LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs"); + LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items"); + panel->setSortOrder(mSortOrder); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items"); + panel->setSortOrder(mSortOrder); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items"); + panel->setSortOrder(mSortOrder); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items"); + panel->setSortOrder(mSortOrder); +} + +void LLPanelMarketplaceListings::onFilterEdit(const std::string& search_string) +{ + // Find active panel + LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel(); + if (panel) + { + // Save filter string (needed when switching tabs) + mFilterSubString = search_string; + // Set filter string on active panel + panel->setFilterSubString(mFilterSubString); + } +} + +void LLPanelMarketplaceListings::draw() +{ + if (LLMarketplaceData::instance().checkDirtyCount()) + { + update_all_marketplace_count(); + } + + // Get the audit button enabled only after the whole inventory is fetched + if (!mAuditBtn->getEnabled()) + { + LLInventoryModelBackgroundFetch* inst = LLInventoryModelBackgroundFetch::getInstance(); + mAuditBtn->setEnabled(inst->isEverythingFetched() && !inst->folderFetchActive()); + } + + LLPanel::draw(); +} + +void LLPanelMarketplaceListings::onSelectionChange(LLInventoryPanel *panel, const std::deque<LLFolderViewItem*>& items, bool user_action) +{ + panel->onSelectionChange(items, user_action); +} + +bool LLPanelMarketplaceListings::allowDropOnRoot() +{ + LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel(); + return (panel ? panel->getAllowDropOnRoot() : false); +} + +void LLPanelMarketplaceListings::onTabChange() +{ + // Find active panel + LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel(); + if (panel) + { + // If the panel doesn't allow drop on root, it doesn't allow the creation of new folder on root either + LLButton* add_btn = getChild<LLButton>("add_btn"); + add_btn->setEnabled(panel->getAllowDropOnRoot()); + + // Set filter string on active panel + panel->setFilterSubString(mFilterSubString); + + // Show/hide the drop zone and resize the inventory tabs panel accordingly + LLPanel* drop_zone = (LLPanel*)getChild<LLPanel>("marketplace_drop_zone"); + bool drop_zone_visible = drop_zone->getVisible(); + if (drop_zone_visible != panel->getAllowDropOnRoot()) + { + LLPanel* tabs = (LLPanel*)getChild<LLPanel>("tab_container_panel"); + S32 delta_height = drop_zone->getRect().getHeight(); + delta_height = (drop_zone_visible ? delta_height : -delta_height); + tabs->reshape(tabs->getRect().getWidth(),tabs->getRect().getHeight() + delta_height); + tabs->translate(0,-delta_height); + } + drop_zone->setVisible(panel->getAllowDropOnRoot()); + } +} + +void LLPanelMarketplaceListings::onAddButtonClicked() +{ + LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + llassert(marketplacelistings_id.notNull()); + LLFolderType::EType preferred_type = LLFolderType::lookup("category"); + LLHandle<LLPanel> handle = getHandle(); + gInventory.createNewCategory( + marketplacelistings_id, + preferred_type, + LLStringUtil::null, + [handle](const LLUUID &new_cat_id) + { + // Find active panel + LLPanel *marketplace_panel = handle.get(); + if (!marketplace_panel) + { + return; + } + LLInventoryPanel* panel = (LLInventoryPanel*)marketplace_panel->getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel(); + if (panel) + { + gInventory.notifyObservers(); + panel->setSelectionByID(new_cat_id, true); + panel->getRootFolder()->setNeedsAutoRename(true); + } + } + ); +} + +void LLPanelMarketplaceListings::onAuditButtonClicked() +{ + LLSD data(LLSD::emptyMap()); + LLFloaterReg::showInstance("marketplace_validation", data); +} + +void LLPanelMarketplaceListings::onViewSortMenuItemClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + // Sort options + if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent")) + { + // We're making sort options exclusive, default is SO_FOLDERS_BY_NAME + if (chosen_item == "sort_by_stock_amount") + { + setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_WEIGHT); + } + else if (chosen_item == "sort_by_name") + { + setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME); + } + else if (chosen_item == "sort_by_recent") + { + setSortOrder(LLInventoryFilter::SO_DATE); + } + } + // Filter option + else if (chosen_item == "show_only_listing_folders") + { + mFilterListingFoldersOnly = !mFilterListingFoldersOnly; + // Set each panel with that filter flag + LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs"); + LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + } +} + +bool LLPanelMarketplaceListings::onViewSortMenuItemCheck(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent")) + { + if (chosen_item == "sort_by_stock_amount") + { + return (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_WEIGHT); + } + else if (chosen_item == "sort_by_name") + { + return (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME); + } + else if (chosen_item == "sort_by_recent") + { + return (mSortOrder & LLInventoryFilter::SO_DATE); + } + } + else if (chosen_item == "show_only_listing_folders") + { + return mFilterListingFoldersOnly; + } + return false; +} + +///---------------------------------------------------------------------------- +/// LLMarketplaceListingsAddedObserver helper class +///---------------------------------------------------------------------------- + +class LLMarketplaceListingsAddedObserver : public LLInventoryCategoryAddedObserver +{ +public: + LLMarketplaceListingsAddedObserver(LLFloaterMarketplaceListings * marketplace_listings_floater) + : LLInventoryCategoryAddedObserver() + , mMarketplaceListingsFloater(marketplace_listings_floater) + { + } + + void done() + { + for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it) + { + LLViewerInventoryCategory* added_category = *it; + + LLFolderType::EType added_category_type = added_category->getPreferredType(); + + if (added_category_type == LLFolderType::FT_MARKETPLACE_LISTINGS) + { + mMarketplaceListingsFloater->initializeMarketPlace(); + } + } + } + +private: + LLFloaterMarketplaceListings * mMarketplaceListingsFloater; +}; + +///---------------------------------------------------------------------------- +/// LLFloaterMarketplaceListings +///---------------------------------------------------------------------------- + +LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key) +: LLFloater(key) +, mCategoriesObserver(NULL) +, mCategoryAddedObserver(NULL) +, mRootFolderId(LLUUID::null) +, mInventoryStatus(NULL) +, mInventoryInitializationInProgress(NULL) +, mInventoryPlaceholder(NULL) +, mInventoryText(NULL) +, mInventoryTitle(NULL) +, mPanelListings(NULL) +, mPanelListingsSet(false) +, mRootFolderCreating(false) +{ +} + +LLFloaterMarketplaceListings::~LLFloaterMarketplaceListings() +{ + if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver)) + { + gInventory.removeObserver(mCategoriesObserver); + } + delete mCategoriesObserver; + + if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) + { + gInventory.removeObserver(mCategoryAddedObserver); + } + delete mCategoryAddedObserver; +} + +bool LLFloaterMarketplaceListings::postBuild() +{ + mInventoryStatus = getChild<LLTextBox>("marketplace_status"); + mInventoryInitializationInProgress = getChild<LLView>("initialization_progress_indicator"); + mInventoryPlaceholder = getChild<LLView>("marketplace_listings_inventory_placeholder_panel"); + mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("marketplace_listings_inventory_placeholder_text"); + mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("marketplace_listings_inventory_placeholder_title"); + + mPanelListings = static_cast<LLPanelMarketplaceListings*>(getChild<LLUICtrl>("panel_marketplace_listing")); + + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterMarketplaceListings::onFocusReceived, this)); + + // Observe category creation to catch marketplace listings creation (moot if already existing) + mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this); + gInventory.addObserver(mCategoryAddedObserver); + + + // Fetch aggressively so we can interact with listings as soon as possible + if (!fetchContents()) + { + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + LLInventoryModelBackgroundFetch::instance().start(marketplacelistings_id, true); + } + + + return true; +} + +void LLFloaterMarketplaceListings::onClose(bool app_quitting) +{ +} + +void LLFloaterMarketplaceListings::onOpen(const LLSD& key) +{ + // + // Initialize the Market Place or go update the marketplace listings + // + if (LLMarketplaceData::instance().getSLMStatus() <= MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE) + { + initializeMarketPlace(); + } + else + { + updateView(); + } +} + +void LLFloaterMarketplaceListings::onFocusReceived() +{ + updateView(); +} + +bool LLFloaterMarketplaceListings::fetchContents() +{ + if (mRootFolderId.notNull() && + (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_LOADING) && + (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_DONE)) + { + LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this)); + LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING); + LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true); + LLMarketplaceData::instance().getSLMListings(); + return true; + } + return false; +} + +void LLFloaterMarketplaceListings::setRootFolder() +{ + if ((LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) && + (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT)) + { + // If we are *not* a merchant or we have no market place connection established yet, do nothing + return; + } + if (!gInventory.isInventoryUsable()) + { + return; + } + + LLFolderType::EType preferred_type = LLFolderType::FT_MARKETPLACE_LISTINGS; + // We are a merchant. Get the Marketplace listings folder, create it if needs be. + LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(preferred_type); + + if (marketplacelistings_id.isNull()) + { + if (!mRootFolderCreating) + { + mRootFolderCreating = true; + gInventory.createNewCategory( + gInventory.getRootFolderID(), + preferred_type, + LLStringUtil::null, + [](const LLUUID &new_cat_id) + { + LLFloaterMarketplaceListings* marketplace = LLFloaterReg::findTypedInstance<LLFloaterMarketplaceListings>("marketplace_listings"); + if (marketplace) + { + if (new_cat_id.notNull()) + { + // will call setRootFolder again + marketplace->updateView(); + } + // don't update in case of failure, createNewCategory can return + // immediately if cap is missing and will cause a loop + else + { + // unblock + marketplace->mRootFolderCreating = false; + LL_WARNS("SLM") << "Inventory warning: Failed to create marketplace listings folder for a merchant" << LL_ENDL; + } + } + } + ); + } + return; + } + + mRootFolderCreating = false; + + // No longer need to observe new category creation + if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) + { + gInventory.removeObserver(mCategoryAddedObserver); + delete mCategoryAddedObserver; + mCategoryAddedObserver = NULL; + } + llassert(!mCategoryAddedObserver); + + if (marketplacelistings_id == mRootFolderId) + { + LL_WARNS("SLM") << "Inventory warning: Marketplace listings folder already set" << LL_ENDL; + return; + } + + mRootFolderId = marketplacelistings_id; +} + +void LLFloaterMarketplaceListings::setPanels() +{ + if (mRootFolderId.isNull()) + { + return; + } + + // Consolidate Marketplace listings + // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, + // things get messy and conventions get broken down eventually + gInventory.consolidateForType(mRootFolderId, LLFolderType::FT_MARKETPLACE_LISTINGS); + + // Now that we do have a non NULL root, we can build the inventory panels + mPanelListings->buildAllPanels(); + + // Create observer for marketplace listings modifications + if (!mCategoriesObserver) + { + mCategoriesObserver = new LLInventoryCategoriesObserver(); + llassert(mCategoriesObserver); + gInventory.addObserver(mCategoriesObserver); + mCategoriesObserver->addCategory(mRootFolderId, boost::bind(&LLFloaterMarketplaceListings::onChanged, this)); + } + + // Get the content of the marketplace listings folder + fetchContents(); + + // Flag that this is done + mPanelListingsSet = true; +} + +void LLFloaterMarketplaceListings::initializeMarketPlace() +{ + LLMarketplaceData::instance().initializeSLM(boost::bind(&LLFloaterMarketplaceListings::updateView, this)); +} + +S32 LLFloaterMarketplaceListings::getFolderCount() +{ + if (mPanelListings && mRootFolderId.notNull()) + { + LLInventoryModel::cat_array_t * cats; + LLInventoryModel::item_array_t * items; + gInventory.getDirectDescendentsOf(mRootFolderId, cats, items); + + return (cats->size() + items->size()); + } + else + { + return 0; + } +} + +void LLFloaterMarketplaceListings::setStatusString(const std::string& statusString) +{ + mInventoryStatus->setText(statusString); +} + +void LLFloaterMarketplaceListings::updateView() +{ + U32 mkt_status = LLMarketplaceData::instance().getSLMStatus(); + bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT); + U32 data_fetched = LLMarketplaceData::instance().getSLMDataFetched(); + + // Get or create the root folder if we are a merchant and it hasn't been done already + if (mRootFolderId.isNull() && is_merchant) + { + setRootFolder(); + } + if (mRootFolderCreating) + { + // waiting for callback + return; + } + + // Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading + if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) ) + { + // Just show the loading indicator in that case and fetch the data (fetch will be skipped if it's already loading) + mInventoryInitializationInProgress->setVisible(true); + mPanelListings->setVisible(false); + fetchContents(); + return; + } + else + { + mInventoryInitializationInProgress->setVisible(false); + } + + // Update the middle portion : tabs or messages + if (getFolderCount() > 0) + { + if (!mPanelListingsSet) + { + // We need to rebuild the tabs cleanly the first time we make them visible + setPanels(); + } + mPanelListings->setVisible(true); + mInventoryPlaceholder->setVisible(false); + } + else + { + mPanelListings->setVisible(false); + mInventoryPlaceholder->setVisible(true); + + std::string text; + std::string title; + std::string tooltip; + + const LLSD& subs = LLMarketplaceData::getMarketplaceStringSubstitutions(); + + // Update the top message or flip to the tabs and folders view + // *TODO : check those messages and create better appropriate ones in strings.xml + if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE) + { + std::string reason = LLMarketplaceData::instance().getSLMConnectionfailureReason(); + if (reason.empty()) + { + text = LLTrans::getString("InventoryMarketplaceConnectionError"); + } + else + { + LLSD args; + args["[REASON]"] = reason; + text = LLTrans::getString("InventoryMarketplaceConnectionErrorReason", args); + } + + title = LLTrans::getString("InventoryOutboxErrorTitle"); + tooltip = LLTrans::getString("InventoryOutboxErrorTooltip"); + LL_WARNS() << "Marketplace status code: " << mkt_status << LL_ENDL; + } + else if (mRootFolderId.notNull()) + { + // "Marketplace listings is empty!" message strings + text = LLTrans::getString("InventoryMarketplaceListingsNoItems", subs); + title = LLTrans::getString("InventoryMarketplaceListingsNoItemsTitle"); + tooltip = LLTrans::getString("InventoryMarketplaceListingsNoItemsTooltip"); + } + else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) + { + // "Initializing!" message strings + text = LLTrans::getString("InventoryOutboxInitializing", subs); + title = LLTrans::getString("InventoryOutboxInitializingTitle"); + tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip"); + } + else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT) + { + // "Not a merchant!" message strings + text = LLTrans::getString("InventoryOutboxNotMerchant", subs); + title = LLTrans::getString("InventoryOutboxNotMerchantTitle"); + tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip"); + } + else + { + // "Errors!" message strings + text = LLTrans::getString("InventoryMarketplaceError", subs); + title = LLTrans::getString("InventoryOutboxErrorTitle"); + tooltip = LLTrans::getString("InventoryOutboxErrorTooltip"); + LL_WARNS() << "Marketplace status code: " << mkt_status << LL_ENDL; + } + + mInventoryText->setValue(text); + mInventoryTitle->setValue(title); + mInventoryPlaceholder->getParent()->setToolTip(tooltip); + } +} + +bool LLFloaterMarketplaceListings::isAccepted(EAcceptance accept) +{ + return (accept >= ACCEPT_YES_COPY_SINGLE); +} + +bool LLFloaterMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // If there's no panel to accept drops or no existing marketplace listings folder, we refuse all drop + if (!mPanelListings || mRootFolderId.isNull()) + { + return false; + } + + tooltip_msg = ""; + + // Pass to the children + LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + bool handled = (handled_view != NULL); + + // If no one handled it or it was not accepted and we drop on an empty panel, we try to accept it at the floater level + // as if it was dropped on the marketplace listings root folder + if ((!handled || !isAccepted(*accept)) && !mPanelListings->getVisible() && mRootFolderId.notNull()) + { + if (!mPanelListingsSet) + { + setPanels(); + } + LLFolderView* root_folder = mPanelListings->getRootFolder(); + handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + + return handled; +} + +bool LLFloaterMarketplaceListings::handleHover(S32 x, S32 y, MASK mask) +{ + return LLFloater::handleHover(x, y, mask); +} + +void LLFloaterMarketplaceListings::onMouseLeave(S32 x, S32 y, MASK mask) +{ + LLFloater::onMouseLeave(x, y, mask); +} + +void LLFloaterMarketplaceListings::onChanged() +{ + LLViewerInventoryCategory* category = gInventory.getCategory(mRootFolderId); + if (mRootFolderId.notNull() && category) + { + updateView(); + } + else + { + // Invalidate the marketplace listings data + mRootFolderId.setNull(); + } +} + +//----------------------------------------------------------------------------- +// LLFloaterAssociateListing +//----------------------------------------------------------------------------- + +// Tell if a listing has one only version folder +bool hasUniqueVersionFolder(const LLUUID& folder_id) +{ + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(folder_id, categories, items); + return (categories->size() == 1); +} + +LLFloaterAssociateListing::LLFloaterAssociateListing(const LLSD& key) +: LLFloater(key) +, mUUID() +{ +} + +LLFloaterAssociateListing::~LLFloaterAssociateListing() +{ + gFocusMgr.releaseFocusIfNeeded( this ); +} + +bool LLFloaterAssociateListing::postBuild() +{ + getChild<LLButton>("OK")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::apply, this, true)); + getChild<LLButton>("Cancel")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::cancel, this)); + getChild<LLLineEditor>("listing_id")->setPrevalidate(&LLTextValidate::validateNonNegativeS32); + center(); + + return LLFloater::postBuild(); +} + +bool LLFloaterAssociateListing::handleKeyHere(KEY key, MASK mask) +{ + if (key == KEY_RETURN && mask == MASK_NONE) + { + apply(); + return true; + } + else if (key == KEY_ESCAPE && mask == MASK_NONE) + { + cancel(); + return true; + } + + return LLFloater::handleKeyHere(key, mask); +} + +// static +LLFloaterAssociateListing* LLFloaterAssociateListing::show(const LLUUID& folder_id) +{ + LLFloaterAssociateListing* floater = LLFloaterReg::showTypedInstance<LLFloaterAssociateListing>("associate_listing"); + + floater->mUUID = folder_id; + + return floater; +} + +// Callback for apply if DAMA required... +void LLFloaterAssociateListing::callback_apply(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + apply(false); + } +} + +void LLFloaterAssociateListing::apply(bool user_confirm) +{ + if (mUUID.notNull()) + { + S32 id = (S32)getChild<LLUICtrl>("listing_id")->getValue().asInteger(); + if (id > 0) + { + // Check if the id exists in the merchant SLM DB: note that this record might exist in the LLMarketplaceData + // structure even if unseen in the UI, for instance, if its listing_uuid doesn't exist in the merchant inventory + LLUUID listing_uuid = LLMarketplaceData::instance().getListingFolder(id); + if (listing_uuid.notNull() && user_confirm && LLMarketplaceData::instance().getActivationState(listing_uuid) && !hasUniqueVersionFolder(mUUID)) + { + // Look for user confirmation before unlisting + LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFloaterAssociateListing::callback_apply, this, _1, _2)); + return; + } + // Associate the id with the user chosen folder + LLMarketplaceData::instance().associateListing(mUUID,listing_uuid,id); + } + else + { + LLNotificationsUtil::add("AlertMerchantListingInvalidID"); + } + } + closeFloater(); +} + +void LLFloaterAssociateListing::cancel() +{ + closeFloater(); +} + +//----------------------------------------------------------------------------- +// LLFloaterMarketplaceValidation +//----------------------------------------------------------------------------- + +// Note: The key is the UUID of the folder to validate. +// Validates the whole marketplace listings content if UUID is null. + +LLFloaterMarketplaceValidation::LLFloaterMarketplaceValidation(const LLSD& key) +: LLFloater(key), +mEditor(NULL) +{ +} + +bool LLFloaterMarketplaceValidation::postBuild() +{ + childSetAction("OK", onOK, this); + + // This widget displays the validation messages + mEditor = getChild<LLTextEditor>("validation_text"); + mEditor->setEnabled(false); + mEditor->setFocus(true); + mEditor->setValue(LLSD()); + + return true; +} + +LLFloaterMarketplaceValidation::~LLFloaterMarketplaceValidation() +{ +} + +// virtual +void LLFloaterMarketplaceValidation::draw() +{ + // draw children + LLFloater::draw(); +} + +void LLFloaterMarketplaceValidation::onOpen(const LLSD& key) +{ + // Clear the messages + clearMessages(); + + // Get the folder UUID to validate. Use the whole marketplace listing if none provided. + LLUUID cat_id(key.asUUID()); + if (cat_id.isNull()) + { + cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + } + + // Validates the folder + if (cat_id.notNull()) + { + LLMarketplaceValidator::getInstance()->validateMarketplaceListings( + cat_id, + NULL, + boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), + false); + } + + // Handle the listing folder being processed + handleCurrentListing(); + + // Dump result to the editor panel + if (mEditor) + { + mEditor->setValue(LLSD()); + if (mMessages.empty()) + { + // Display a no error message + mEditor->appendText(LLTrans::getString("Marketplace Validation No Error"), false); + } + else + { + // Print out all the messages to the panel + message_list_t::iterator mCurrentLine = mMessages.begin(); + bool new_line = false; + while (mCurrentLine != mMessages.end()) + { + // Errors are printed in bold, other messages in normal font + LLStyle::Params style; + LLFontDescriptor new_desc(mEditor->getFont()->getFontDesc()); + new_desc.setStyle(mCurrentLine->mErrorLevel == LLError::LEVEL_ERROR ? LLFontGL::BOLD : LLFontGL::NORMAL); + LLFontGL* new_font = LLFontGL::getFont(new_desc); + style.font = new_font; + mEditor->appendText(mCurrentLine->mMessage, new_line, style); + new_line = true; + mCurrentLine++; + } + } + } + // We don't need the messages anymore + clearMessages(); +} + +// static +void LLFloaterMarketplaceValidation::onOK( void* userdata ) +{ + // destroys this object + LLFloaterMarketplaceValidation* self = (LLFloaterMarketplaceValidation*) userdata; + self->clearMessages(); + self->closeFloater(); +} + +void LLFloaterMarketplaceValidation::appendMessage(std::string& message, S32 depth, LLError::ELevel log_level) +{ + // Dump previous listing messages if we're starting a new listing + if (depth == 1) + { + handleCurrentListing(); + } + + // Store the message in the current listing message list + Message current_message; + current_message.mErrorLevel = log_level; + current_message.mMessage = message; + mCurrentListingMessages.push_back(current_message); + mCurrentListingErrorLevel = (mCurrentListingErrorLevel < log_level ? log_level : mCurrentListingErrorLevel); +} + +// Move the current listing messages to the general list if needs be and reset the current listing data +void LLFloaterMarketplaceValidation::handleCurrentListing() +{ + // Dump the current folder messages to the general message list if level warrants it + if (mCurrentListingErrorLevel > LLError::LEVEL_INFO) + { + message_list_t::iterator mCurrentLine = mCurrentListingMessages.begin(); + while (mCurrentLine != mCurrentListingMessages.end()) + { + mMessages.push_back(*mCurrentLine); + mCurrentLine++; + } + } + + // Reset the current listing + mCurrentListingMessages.clear(); + mCurrentListingErrorLevel = LLError::LEVEL_INFO; +} + +void LLFloaterMarketplaceValidation::clearMessages() +{ + mMessages.clear(); + mCurrentListingMessages.clear(); + mCurrentListingErrorLevel = LLError::LEVEL_INFO; +} + +//----------------------------------------------------------------------------- +// LLFloaterItemProperties +//----------------------------------------------------------------------------- + +LLFloaterItemProperties::LLFloaterItemProperties(const LLSD& key) +: LLFloater(key) +{ +} + +LLFloaterItemProperties::~LLFloaterItemProperties() +{ +} + +bool LLFloaterItemProperties::postBuild() +{ + return LLFloater::postBuild(); +} + +void LLFloaterItemProperties::onOpen(const LLSD& key) +{ + // Tell the panel which item it needs to visualize + LLPanel* panel = findChild<LLPanel>("sidepanel"); + + LLSidepanelItemInfo* item_panel = dynamic_cast<LLSidepanelItemInfo*>(panel); + if (item_panel) + { + item_panel->setItemID(key["id"].asUUID()); + if (key.has("object")) + { + item_panel->setObjectID(key["object"].asUUID()); + } + item_panel->setParentFloater(this); + } + + LLSidepanelTaskInfo* task_panel = dynamic_cast<LLSidepanelTaskInfo*>(panel); + if (task_panel) + { + task_panel->setObjectSelection(LLSelectMgr::getInstance()->getSelection()); + } +} + +LLMultiItemProperties::LLMultiItemProperties(const LLSD& key) + : LLMultiFloater(LLSD()) +{ + // start with a small rect in the top-left corner ; will get resized + LLRect rect; + rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 350, 350); + setRect(rect); + LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup(key.asString()); + if (last_floater) + { + stackWith(*last_floater); + } + setTitle(LLTrans::getString("MultiPropertiesTitle")); + buildTabContainer(); +} |