Files
SingularityViewer/indra/newview/llfloatermarketplacelistings.cpp

955 lines
31 KiB
C++

/**
* @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 "lltextbox.h"
#include "lltrans.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().markDefault();
panel = buildInventoryPanel("Inactive Items", "panel_marketplace_listings_unlisted.xml");
panel->getFilter().setFilterMarketplaceInactiveFolders();
//panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
panel->getFilter().markDefault();
panel = buildInventoryPanel("Unassociated Items", "panel_marketplace_listings_unassociated.xml");
panel->getFilter().setFilterMarketplaceUnassociatedFolders();
//panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
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");
// Singu Note: These should already be built!!
LLInventoryPanel* panel = tabs_panel->getChild<LLInventoryPanel>(childname, false, false);
llassert(panel != NULL);
// Set sort order and callbacks
panel->getRootFolder()->setSortOrder(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())
{
mAuditBtn->setEnabled(LLInventoryModelBackgroundFetch::instance().isEverythingFetched());
}
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()
{
// Find active panel
LLInventoryPanel* panel = (LLInventoryPanel*)getChild<LLTabContainer>("marketplace_filter_tabs")->getCurrentPanel();
if (panel)
{
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
llassert(marketplacelistings_id.notNull());
LLFolderType::EType preferred_type = LLFolderType::lookup("category");
LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null);
gInventory.notifyObservers();
panel->setSelectionByID(category, TRUE);
panel->getRootFolder()->setNeedsAutoRename(TRUE);
}
}
void LLPanelMarketplaceListings::onAuditButtonClicked()
{
LLSD data(LLSD::emptyMap());
new LLFloaterMarketplaceValidation(data); // It tracks itself *sigh*
}
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)
{
//buildFromFile("floater_marketplace_listings.xml");
LLUICtrlFactory::instance().buildFloater(this, "floater_marketplace_listings.xml");
}
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 right onOpen()
fetchContents();
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();
}
void 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);
LLMarketplaceData::instance().getSLMListings();
}
}
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;
}
// We are a merchant. Get the Marketplace listings folder, create it if needs be.
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
if (marketplacelistings_id.isNull())
{
// We should never get there unless the inventory fails badly
LL_ERRS("SLM") << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << LL_ENDL;
return;
}
// 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();
}
// 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 = 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 (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");
}
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()
{
//buildFromFile("floater_associate_listing.xml");
LLUICtrlFactory::instance().buildFloater(this, "floater_associate_listing.xml");
}
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(&LLLineEditor::prevalidateNonNegativeS32);
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
void LLFloaterAssociateListing::show(LLFloaterAssociateListing* floater, const LLSD& folder_id)
{
if (!floater) return;
floater->mUUID = folder_id.asUUID();
floater->open();
}
// 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");
}
}
close();
}
void LLFloaterAssociateListing::cancel()
{
close();
}
//-----------------------------------------------------------------------------
// 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(),
mKey(key),
mEditor(NULL)
{
//buildFromFile("floater_marketplace_validation.xml");
LLUICtrlFactory::instance().buildFloater(this, "floater_marketplace_validation.xml");
}
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(mKey.asUUID());
if (cat_id.isNull())
{
cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
}
// Validates the folder
if (cat_id.notNull())
{
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
validate_marketplacelistings(cat, 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, 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
LLStyleSP style(new LLStyle);
style->mBold = mCurrentLine->mErrorLevel == LLError::LEVEL_ERROR;
mEditor->appendText(mCurrentLine->mMessage, false, 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->close();
}
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;
}
/* Singu Note: What even is this? Where is this used?!
//-----------------------------------------------------------------------------
// LLFloaterItemProperties
//-----------------------------------------------------------------------------
LLFloaterItemProperties::LLFloaterItemProperties(const LLSD& key)
: LLFloater(key)
{
}
LLFloaterItemProperties::~LLFloaterItemProperties()
{
}
BOOL LLFloaterItemProperties::postBuild()
{
// On the standalone properties floater, we have no need for a back button...
LLPanel* panel = getChild<LLPanel>("item_panel");
LLButton* back_btn = panel->getChild<LLButton>("back_btn");
back_btn->setVisible(FALSE);
return LLFloater::postBuild();
}
void LLFloaterItemProperties::onOpen(const LLSD& key)
{
// Tell the panel which item it needs to visualize
LLPanel* panel = getChild<LLPanel>("item_panel");
panel->setItemID(mKey["id"].asUUID());
}
*/