Giant VMM merge, still need to compile it and fix llfloatermarketplacelistings

Merge VMM up to change 187902d9c4afd2990acddeb964c928179a52d189

mAllowWear=>mAllowOpen (should probably just remove this altogether though
inventory_panels now accept the "show_root_folder", "allow_drop_on_root", "allow_open", and "use_marketplace_folders" attributes.

Other stuff in this commit:
LLPanelInjector~
Sync lltooldraganddrop to alchemy
Sync notifications up with alchemy
Reorganize notifications some, to better merge with upstream
Remove duplicate InventorySortOrder in settings map
There's a bit of a weird folderview merge mixed into here, I wouldn't trust it, but this thing is so god damn tangled I can't go back now~

Wouldn't have been possible without help from Shyotl and music by Amanda Palmer
This commit is contained in:
Inusaito Sayori
2015-07-30 11:45:19 -04:00
committed by Lirusaito
parent 167d336274
commit f140b4f35c
46 changed files with 3480 additions and 1408 deletions

View File

@@ -122,6 +122,9 @@ public:
AT_LINK_FOLDER = 25, AT_LINK_FOLDER = 25,
// Inventory folder link // Inventory folder link
AT_MARKETPLACE_FOLDER = 26,
// Marketplace folder. Same as an AT_CATEGORY but different display methods.
AT_CURRENT_OUTFIT = 46, AT_CURRENT_OUTFIT = 46,

View File

@@ -441,8 +441,31 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac
std::string name("panel"); std::string name("panel");
node->getAttributeString("name", name); node->getAttributeString("name", name);
LLPanel* panelp = factory->createFactoryPanel(name); std::string class_attr;
node->getAttributeString("class", class_attr);
LLPanel* panelp = NULL;
{
if(!class_attr.empty())
{
panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr);
}
if (!panelp)
{
panelp = factory->createFactoryPanel(name);
/* Singu TODO: Future?
llassert(panelp);
if (!panelp)
{
return NULL; // :(
}*/
}
}
LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION);
// Fall back on a default panel, if there was no special factory. // Fall back on a default panel, if there was no special factory.
if (!panelp) if (!panelp)
{ {

View File

@@ -39,8 +39,8 @@
#include "lluictrl.h" #include "lluictrl.h"
#include "llbutton.h" #include "llbutton.h"
#include "lllineeditor.h" #include "lllineeditor.h"
#include "lluiimage.h"
#include "llviewborder.h" #include "llviewborder.h"
#include "lluiimage.h"
#include "lluistring.h" #include "lluistring.h"
#include "v4color.h" #include "v4color.h"
#include <list> #include <list>
@@ -142,6 +142,7 @@ public:
CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; } CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; }
EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; } EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; }
virtual BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); virtual BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
void initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory); void initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory);
void setPanelParameters(LLXMLNodePtr node, LLView *parentp); void setPanelParameters(LLXMLNodePtr node, LLView *parentp);
@@ -151,6 +152,7 @@ public:
std::string getString(const std::string& name) const; std::string getString(const std::string& name) const;
// ** Wrappers for setting child properties by name ** -TomY // ** Wrappers for setting child properties by name ** -TomY
// WARNING: These are deprecated, please use getChild<T>("name")->doStuff() idiom instead
// LLView // LLView
void childSetVisible(const std::string& name, bool visible); void childSetVisible(const std::string& name, bool visible);
@@ -196,7 +198,7 @@ public:
BOOL childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text); BOOL childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text);
BOOL childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text); BOOL childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text);
BOOL childSetToolTipArg(const std::string& id, const std::string& key, const LLStringExplicit& text); BOOL childSetToolTipArg(const std::string& id, const std::string& key, const LLStringExplicit& text);
// LLSlider / LLMultiSlider / LLSpinCtrl // LLSlider / LLMultiSlider / LLSpinCtrl
void childSetMinValue(const std::string& id, LLSD min_value); void childSetMinValue(const std::string& id, LLSD min_value);
void childSetMaxValue(const std::string& id, LLSD max_value); void childSetMaxValue(const std::string& id, LLSD max_value);
@@ -228,6 +230,7 @@ public:
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
boost::signals2::connection setVisibleCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setVisibleCallback( const commit_signal_t::slot_type& cb );
protected: protected:
// Override to set not found list // Override to set not found list
LLButton* getDefaultButton() { return mDefaultBtn; } LLButton* getDefaultButton() { return mDefaultBtn; }
@@ -262,4 +265,56 @@ private:
}; // end class LLPanel }; // end class LLPanel
typedef boost::function<LLPanel* (void)> LLPanelClassCreatorFunc;
// local static instance for registering a particular panel class
class LLRegisterPanelClass
: public LLSingleton< LLRegisterPanelClass >
{
public:
// reigister with either the provided builder, or the generic templated builder
void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func)
{
mPanelClassesNames[tag] = func;
}
LLPanel* createPanelClass(const std::string& tag)
{
param_name_map_t::iterator iT = mPanelClassesNames.find(tag);
if(iT == mPanelClassesNames.end())
return 0;
return iT->second();
}
template<typename T>
static T* defaultPanelClassBuilder()
{
T* pT = new T();
return pT;
}
private:
typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t;
param_name_map_t mPanelClassesNames;
};
// local static instance for registering a particular panel class
template<typename T>
class LLPanelInjector
{
public:
// register with either the provided builder, or the generic templated builder
LLPanelInjector(const std::string& tag);
};
template<typename T>
LLPanelInjector<T>::LLPanelInjector(const std::string& tag)
{
LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>);
}
#endif #endif

View File

@@ -1538,15 +1538,6 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>0</integer> <integer>0</integer>
</map> </map>
<key>InventorySortOrder</key>
<map>
<key>Comment</key>
<string>Specifies sort key for inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>3</integer>
</map>
<key>Blacklist.Settings</key> <key>Blacklist.Settings</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -9477,6 +9468,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>200</integer> <integer>200</integer>
</map> </map>
<key>InventoryOutboxMaxStockItemCount</key>
<map>
<key>Comment</key>
<string>Maximum number of items allowed in a stock folder.</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>200</integer>
</map>
<key>InventorySortOrder</key> <key>InventorySortOrder</key>
<map> <map>
<key>Comment</key> <key>Comment</key>
@@ -9488,6 +9490,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key> <key>Value</key>
<integer>7</integer> <integer>7</integer>
</map> </map>
<key>MarketplaceListingsSortOrder</key>
<map>
<key>Comment</key>
<string>Specifies sort for marketplace listings</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>2</integer>
</map>
<key>InvertMouse</key> <key>InvertMouse</key>
<map> <map>
<key>Comment</key> <key>Comment</key>

View File

@@ -53,14 +53,13 @@ void HippoLimits::setOpenSimLimits()
setMaxAgentGroups(); setMaxAgentGroups();
mMaxPrimScale = 8192.0f; mMaxPrimScale = 8192.0f;
mMaxHeight = 10000.0f; mMaxHeight = 10000.0f;
mMinPrimScale = 0.001f;
if (gHippoGridManager->getConnectedGrid()->isRenderCompat()) { if (gHippoGridManager->getConnectedGrid()->isRenderCompat()) {
LL_INFOS() << "Using rendering compatible OpenSim limits." << LL_ENDL; LL_INFOS() << "Using rendering compatible OpenSim limits." << LL_ENDL;
mMinPrimScale = 0.01f;
mMinHoleSize = 0.05f; mMinHoleSize = 0.05f;
mMaxHollow = 0.95f; mMaxHollow = 0.95f;
} else { } else {
LL_INFOS() << "Using Hippo OpenSim limits." << LL_ENDL; LL_INFOS() << "Using Hippo OpenSim limits." << LL_ENDL;
mMinPrimScale = 0.001f;
mMinHoleSize = 0.01f; mMinHoleSize = 0.01f;
mMaxHollow = 0.99f; mMaxHollow = 0.99f;
} }

View File

@@ -4107,6 +4107,12 @@ void LLAgent::handleTeleportFinished()
LLNotificationsUtil::add("PreferredMaturityChanged", args); LLNotificationsUtil::add("PreferredMaturityChanged", args);
mIsMaturityRatingChangingDuringTeleport = false; mIsMaturityRatingChangingDuringTeleport = false;
} }
// Init SLM Marketplace connection so we know which UI should be used for the user as a merchant
// Note: Eventually, all merchant will be migrated to the new SLM system and there will be no reason to show the old UI at all.
// Note: Some regions will not support the SLM cap for a while so we need to do that check for each teleport.
// *TODO : Suppress that line from here once the whole grid migrated to SLM and move it to idle_startup() (llstartup.cpp)
check_merchant_status();
} }
void LLAgent::handleTeleportFailed() void LLAgent::handleTeleportFailed()

View File

@@ -919,7 +919,7 @@ bool LLAppViewer::init()
load_default_bindings(gSavedSettings.getBOOL("LiruUseZQSDKeys")); load_default_bindings(gSavedSettings.getBOOL("LiruUseZQSDKeys"));
// If we don't have the right GL requirements, exit. // If we don't have the right GL requirements, exit.
if (!gGLManager.mHasRequirements && !gNoRender) if (!gGLManager.mHasRequirements)
{ {
// can't use an alert here since we're exiting and // can't use an alert here since we're exiting and
// all hell breaks lose. // all hell breaks lose.

View File

@@ -37,8 +37,8 @@
#include "llinventoryobserver.h" #include "llinventoryobserver.h"
#include "llinventoryfunctions.h" #include "llinventoryfunctions.h"
#include "llmarketplacefunctions.h" #include "llmarketplacefunctions.h"
#include "llnotificationhandler.h" //#include "llnotificationhandler.h"
#include "llnotificationmanager.h" //#include "llnotificationmanager.h"
#include "llnotificationsutil.h" #include "llnotificationsutil.h"
//#include "llsidepaneliteminfo.h" //#include "llsidepaneliteminfo.h"
#include "lltextbox.h" #include "lltextbox.h"
@@ -48,12 +48,12 @@
/// LLPanelMarketplaceListings /// LLPanelMarketplaceListings
///---------------------------------------------------------------------------- ///----------------------------------------------------------------------------
static LLPanelInjector<LLPanelMarketplaceListings> t_panel_status("llpanelmarketplacelistings"); // Liru TODO: build this instead. static LLPanelInjector<LLPanelMarketplaceListings> t_panel_status("llpanelmarketplacelistings");
LLPanelMarketplaceListings::LLPanelMarketplaceListings() LLPanelMarketplaceListings::LLPanelMarketplaceListings()
: mRootFolder(NULL) : mRootFolder(NULL)
, mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME) , mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME)
, mFilterType(LLInventoryFilter::FILTERTYPE_NONE) , mFilterListingFoldersOnly(false)
{ {
mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2)); mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemClicked, this, _2));
mEnableCallbackRegistrar.add("Marketplace.ViewSort.CheckItem", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemCheck, this, _2)); mEnableCallbackRegistrar.add("Marketplace.ViewSort.CheckItem", boost::bind(&LLPanelMarketplaceListings::onViewSortMenuItemCheck, this, _2));
@@ -73,27 +73,44 @@ BOOL LLPanelMarketplaceListings::postBuild()
return LLPanel::postBuild(); 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() void LLPanelMarketplaceListings::buildAllPanels()
{ {
// Build the All panel first // Build the All panel first
LLInventoryPanel* panel_all_items; LLInventoryPanel* panel_all_items;
panel_all_items = buildInventoryPanel("All Items", "panel_marketplace_listings_inventory.xml"); panel_all_items = buildInventoryPanel("All Items", "panel_marketplace_listings_inventory.xml");
panel_all_items->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); //panel_all_items->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
panel_all_items->getFilter().markDefault(); panel_all_items->getFilter().markDefault();
// Build the other panels // Build the other panels
LLInventoryPanel* panel; LLInventoryPanel* panel;
panel = buildInventoryPanel("Active Items", "panel_marketplace_listings_listed.xml"); panel = buildInventoryPanel("Active Items", "panel_marketplace_listings_listed.xml");
panel->getFilter().setFilterMarketplaceActiveFolders(); panel->getFilter().setFilterMarketplaceActiveFolders();
panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); //panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
panel->getFilter().markDefault(); panel->getFilter().markDefault();
panel = buildInventoryPanel("Inactive Items", "panel_marketplace_listings_unlisted.xml"); panel = buildInventoryPanel("Inactive Items", "panel_marketplace_listings_unlisted.xml");
panel->getFilter().setFilterMarketplaceInactiveFolders(); panel->getFilter().setFilterMarketplaceInactiveFolders();
panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); //panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
panel->getFilter().markDefault(); panel->getFilter().markDefault();
panel = buildInventoryPanel("Unassociated Items", "panel_marketplace_listings_unassociated.xml"); panel = buildInventoryPanel("Unassociated Items", "panel_marketplace_listings_unassociated.xml");
panel->getFilter().setFilterMarketplaceUnassociatedFolders(); panel->getFilter().setFilterMarketplaceUnassociatedFolders();
panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); //panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems");
panel->getFilter().markDefault(); panel->getFilter().markDefault();
// Set the tab panel // Set the tab panel
@@ -101,28 +118,43 @@ void LLPanelMarketplaceListings::buildAllPanels()
tabs_panel->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onTabChange, this)); tabs_panel->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onTabChange, this));
tabs_panel->selectTabPanel(panel_all_items); // All panel selected by default tabs_panel->selectTabPanel(panel_all_items); // All panel selected by default
mRootFolder = panel_all_items->getRootFolder(); // Keep the root of the all panel 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) LLInventoryPanel* LLPanelMarketplaceListings::buildInventoryPanel(const std::string& childname, const std::string& filename)
{ {
LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs"); //LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs");
// Singu Note: These should already be built!!
LLInventoryPanel* panel = getChild<LLInventoryPanel>(childname); LLInventoryPanel* panel = getChild<LLInventoryPanel>(childname);
if (panel)
{
tabs_panel->removeTabPanel(panel);
delete panel;
}
panel = LLUICtrlFactory::createFromFile<LLInventoryPanel>(filename, tabs_panel, LLInventoryPanel::child_registry_t::instance());
llassert(panel != NULL); llassert(panel != NULL);
// Set sort order and callbacks // Set sort order and callbacks
panel = getChild<LLInventoryPanel>(childname); panel = getChild<LLInventoryPanel>(childname);
panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME); //panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME); // Singu TODO: Do this at some point, not really important.
panel->setSelectCallback(boost::bind(&LLPanelMarketplaceListings::onSelectionChange, this, panel, _1, _2)); panel->setSelectCallback(boost::bind(&LLPanelMarketplaceListings::onSelectionChange, this, panel, _1, _2));
return panel; 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) void LLPanelMarketplaceListings::onFilterEdit(const std::string& search_string)
{ {
// Find active panel // Find active panel
@@ -157,6 +189,12 @@ void LLPanelMarketplaceListings::onSelectionChange(LLInventoryPanel *panel, cons
panel->onSelectionChange(items, 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() void LLPanelMarketplaceListings::onTabChange()
{ {
// Find active panel // Find active panel
@@ -169,6 +207,19 @@ void LLPanelMarketplaceListings::onTabChange()
// Set filter string on active panel // Set filter string on active panel
panel->setFilterSubString(mFilterSubString); 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());
} }
} }
@@ -191,7 +242,7 @@ void LLPanelMarketplaceListings::onAddButtonClicked()
void LLPanelMarketplaceListings::onAuditButtonClicked() void LLPanelMarketplaceListings::onAuditButtonClicked()
{ {
LLSD data(LLSD::emptyMap()); LLSD data(LLSD::emptyMap());
LLFloaterReg::showInstance("marketplace_validation", data); new LLFloaterMarketplaceValidation(data); // It tracks itself *sigh*
} }
void LLPanelMarketplaceListings::onViewSortMenuItemClicked(const LLSD& userdata) void LLPanelMarketplaceListings::onViewSortMenuItemClicked(const LLSD& userdata)
@@ -199,28 +250,62 @@ void LLPanelMarketplaceListings::onViewSortMenuItemClicked(const LLSD& userdata)
std::string chosen_item = userdata.asString(); std::string chosen_item = userdata.asString();
// Sort options // Sort options
if (chosen_item == "sort_by_stock_amount") if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent"))
{ {
mSortOrder = (mSortOrder == LLInventoryFilter::SO_FOLDERS_BY_NAME ? LLInventoryFilter::SO_FOLDERS_BY_WEIGHT : LLInventoryFilter::SO_FOLDERS_BY_NAME); // We're making sort options exclusive, default is SO_FOLDERS_BY_NAME
// Set each panel with that sort order 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"); LLTabContainer* tabs_panel = getChild<LLTabContainer>("marketplace_filter_tabs");
LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items"); LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items");
panel->setSortOrder(mSortOrder); panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items"); panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items");
panel->setSortOrder(mSortOrder); panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items"); panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items");
panel->setSortOrder(mSortOrder); panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items"); panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items");
panel->setSortOrder(mSortOrder); panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly);
} }
} }
bool LLPanelMarketplaceListings::onViewSortMenuItemCheck(const LLSD& userdata) bool LLPanelMarketplaceListings::onViewSortMenuItemCheck(const LLSD& userdata)
{ {
std::string chosen_item = userdata.asString(); std::string chosen_item = userdata.asString();
if (chosen_item == "sort_by_stock_amount") if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent"))
return mSortOrder == LLInventoryFilter::SO_FOLDERS_BY_WEIGHT; {
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; return false;
} }
@@ -271,7 +356,7 @@ LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
, mInventoryText(NULL) , mInventoryText(NULL)
, mInventoryTitle(NULL) , mInventoryTitle(NULL)
, mPanelListings(NULL) , mPanelListings(NULL)
, mFirstViewListings(true) , mPanelListingsSet(false)
{ {
//buildFromFile("floater_marketplace_listings.xml"); //buildFromFile("floater_marketplace_listings.xml");
LLUICtrlFactory::instance().buildFloater(this, "floater_marketplace_listings.xml"); LLUICtrlFactory::instance().buildFloater(this, "floater_marketplace_listings.xml");
@@ -308,7 +393,7 @@ BOOL LLFloaterMarketplaceListings::postBuild()
mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this); mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this);
gInventory.addObserver(mCategoryAddedObserver); gInventory.addObserver(mCategoryAddedObserver);
// Debug : fetch aggressively so we can create test data right onOpen() // Fetch aggressively so we can interact with listings right onOpen()
fetchContents(); fetchContents();
return TRUE; return TRUE;
@@ -318,18 +403,8 @@ void LLFloaterMarketplaceListings::onClose(bool app_quitting)
{ {
} }
bool canAccessMarketplace() void LLFloaterMarketplaceListings::onOpen(/*const LLSD& key*/)
{ {
return (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT) || gSavedSettings.getBOOL("InventoryOutboxDisplayBoth");
}
void LLFloaterMarketplaceListings::onOpen(const LLSD& key)
{
if (!canAccessMarketplace())
{
close();
return;
}
// //
// Initialize the Market Place or go update the marketplace listings // Initialize the Market Place or go update the marketplace listings
// //
@@ -350,17 +425,21 @@ void LLFloaterMarketplaceListings::onFocusReceived()
void LLFloaterMarketplaceListings::fetchContents() void LLFloaterMarketplaceListings::fetchContents()
{ {
if (mRootFolderId.notNull()) 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); LLInventoryModelBackgroundFetch::instance().start(mRootFolderId);
// Get all the SLM Listings
LLMarketplaceData::instance().getSLMListings(); LLMarketplaceData::instance().getSLMListings();
} }
} }
void LLFloaterMarketplaceListings::setup() void LLFloaterMarketplaceListings::setRootFolder()
{ {
if (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) 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 // If we are *not* a merchant or we have no market place connection established yet, do nothing
return; return;
@@ -389,18 +468,27 @@ void LLFloaterMarketplaceListings::setup()
LL_WARNS("SLM") << "Inventory warning: Marketplace listings folder already set" << LL_ENDL; LL_WARNS("SLM") << "Inventory warning: Marketplace listings folder already set" << LL_ENDL;
return; return;
} }
mRootFolderId = marketplacelistings_id; mRootFolderId = marketplacelistings_id;
}
void LLFloaterMarketplaceListings::setPanels()
{
if (mRootFolderId.isNull())
{
return;
}
// Consolidate Marketplace listings // Consolidate Marketplace listings
// We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, // 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 // things get messy and conventions get broken down eventually
gInventory.consolidateForType(marketplacelistings_id, LLFolderType::FT_MARKETPLACE_LISTINGS); gInventory.consolidateForType(mRootFolderId, LLFolderType::FT_MARKETPLACE_LISTINGS);
// Now that we do have a non NULL root, we can build the inventory panels // Now that we do have a non NULL root, we can build the inventory panels
mPanelListings->buildAllPanels(); mPanelListings->buildAllPanels();
// Create observer for marketplace listings modifications // Create observer for marketplace listings modifications
if (!mCategoriesObserver && mRootFolderId.notNull()) if (!mCategoriesObserver)
{ {
mCategoriesObserver = new LLInventoryCategoriesObserver(); mCategoriesObserver = new LLInventoryCategoriesObserver();
llassert(mCategoriesObserver); llassert(mCategoriesObserver);
@@ -410,6 +498,9 @@ void LLFloaterMarketplaceListings::setup()
// Get the content of the marketplace listings folder // Get the content of the marketplace listings folder
fetchContents(); fetchContents();
// Flag that this is done
mPanelListingsSet = true;
} }
void LLFloaterMarketplaceListings::initializeMarketPlace() void LLFloaterMarketplaceListings::initializeMarketPlace()
@@ -441,35 +532,36 @@ void LLFloaterMarketplaceListings::setStatusString(const std::string& statusStri
void LLFloaterMarketplaceListings::updateView() void LLFloaterMarketplaceListings::updateView()
{ {
U32 mkt_status = LLMarketplaceData::instance().getSLMStatus(); 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 // Get or create the root folder if we are a merchant and it hasn't been done already
if (mRootFolderId.isNull() && (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT)) if (mRootFolderId.isNull() && is_merchant)
{ {
setup(); setRootFolder();
} }
// Update the bottom initializing status and progress dial // 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) if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) )
{ {
setStatusString(getString("MarketplaceListingsInitializing")); // Just show the loading indicator in that case and fetch the data (fetch will be skipped if it's already loading)
mInventoryInitializationInProgress->setVisible(true); mInventoryInitializationInProgress->setVisible(true);
mPanelListings->setVisible(FALSE);
fetchContents();
return;
} }
else else
{ {
setStatusString("");
mInventoryInitializationInProgress->setVisible(false); mInventoryInitializationInProgress->setVisible(false);
} }
// Update the middle portion : tabs or messages // Update the middle portion : tabs or messages
if (getFolderCount() > 0) if (getFolderCount() > 0)
{ {
if (mFirstViewListings) if (!mPanelListingsSet)
{ {
// We need to rebuild the tabs cleanly the first time we make them visible // We need to rebuild the tabs cleanly the first time we make them visible
// setup() does it if the root is nixed first setPanels();
mRootFolderId.setNull();
setup();
mFirstViewListings = false;
} }
mPanelListings->setVisible(TRUE); mPanelListings->setVisible(TRUE);
mInventoryPlaceholder->setVisible(FALSE); mInventoryPlaceholder->setVisible(FALSE);
@@ -511,7 +603,7 @@ void LLFloaterMarketplaceListings::updateView()
else else
{ {
// "Errors!" message strings // "Errors!" message strings
text = LLTrans::getString("InventoryOutboxError", subs); text = LLTrans::getString("InventoryMarketplaceError", subs);
title = LLTrans::getString("InventoryOutboxErrorTitle"); title = LLTrans::getString("InventoryOutboxErrorTitle");
tooltip = LLTrans::getString("InventoryOutboxErrorTooltip"); tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
} }
@@ -539,19 +631,22 @@ BOOL LLFloaterMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, BO
return FALSE; return FALSE;
} }
tooltip_msg = "";
// Pass to the children // Pass to the children
LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
BOOL handled = (handled_view != NULL); BOOL handled = (handled_view != NULL);
// If no one handled it or it was not accepted, we try to accept it at the floater level as if it was dropped on the // 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
// marketplace listings root folder // as if it was dropped on the marketplace listings root folder
if (!handled || !isAccepted(*accept)) if ((!handled || !isAccepted(*accept)) && !mPanelListings->getVisible() && mRootFolderId.notNull())
{ {
if (!mPanelListings->getVisible() && mRootFolderId.notNull()) if (!mPanelListingsSet)
{ {
LLFolderView* root_folder = mPanelListings->getRootFolder(); setPanels();
handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
} }
LLFolderView* root_folder = mPanelListings->getRootFolder();
handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
} }
return handled; return handled;
@@ -585,6 +680,15 @@ void LLFloaterMarketplaceListings::onChanged()
// LLFloaterAssociateListing // 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) LLFloaterAssociateListing::LLFloaterAssociateListing(const LLSD& key)
: LLFloater(key) : LLFloater(key)
, mUUID() , mUUID()
@@ -602,7 +706,7 @@ BOOL LLFloaterAssociateListing::postBuild()
{ {
getChild<LLButton>("OK")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::apply, this, TRUE)); getChild<LLButton>("OK")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::apply, this, TRUE));
getChild<LLButton>("Cancel")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::cancel, this)); getChild<LLButton>("Cancel")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::cancel, this));
getChild<LLLineEditor>("listing_id")->setPrevalidate(&LLTextValidate::validateNonNegativeS32); getChild<LLLineEditor>("listing_id")->setPrevalidate(&LLLineEditor::prevalidateNonNegativeS32);
center(); center();
return LLFloater::postBuild(); return LLFloater::postBuild();
@@ -625,11 +729,12 @@ BOOL LLFloaterAssociateListing::handleKeyHere(KEY key, MASK mask)
} }
// static // static
void LLFloaterAssociateListing::show(LLFloater* floater, const LLSD& folder_id) void LLFloaterAssociateListing::show(LLFloaterAssociateListing* floater, const LLSD& folder_id)
{ {
if (!floater) return; if (!floater) return;
floater->mUUID = folder_id.asUUID(); floater->mUUID = folder_id.asUUID();
floater->open(); floater->open();
} }
@@ -653,7 +758,7 @@ void LLFloaterAssociateListing::apply(BOOL user_confirm)
// Check if the id exists in the merchant SLM DB: note that this record might exist in the LLMarketplaceData // 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 // 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); LLUUID listing_uuid = LLMarketplaceData::instance().getListingFolder(id);
if (listing_uuid.notNull() && user_confirm && LLMarketplaceData::instance().getActivationState(listing_uuid)) if (listing_uuid.notNull() && user_confirm && LLMarketplaceData::instance().getActivationState(listing_uuid) && !hasUniqueVersionFolder(mUUID))
{ {
// Look for user confirmation before unlisting // Look for user confirmation before unlisting
LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFloaterAssociateListing::callback_apply, this, _1, _2)); LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFloaterAssociateListing::callback_apply, this, _1, _2));
@@ -661,29 +766,30 @@ void LLFloaterAssociateListing::apply(BOOL user_confirm)
} }
// Associate the id with the user chosen folder // Associate the id with the user chosen folder
LLMarketplaceData::instance().associateListing(mUUID,listing_uuid,id); LLMarketplaceData::instance().associateListing(mUUID,listing_uuid,id);
// Update the folder widgets now that the action is launched
update_marketplace_category(listing_uuid);
update_marketplace_category(mUUID);
} }
else else
{ {
LLNotificationsUtil::add("AlertMerchantListingInvalidID"); LLNotificationsUtil::add("AlertMerchantListingInvalidID");
} }
} }
closeFloater(); close();
} }
void LLFloaterAssociateListing::cancel() void LLFloaterAssociateListing::cancel()
{ {
closeFloater(); close();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// LLFloaterMarketplaceValidation // 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) LLFloaterMarketplaceValidation::LLFloaterMarketplaceValidation(const LLSD& key)
: LLFloater(key), : LLFloater(),
mKey(key),
mEditor(NULL) mEditor(NULL)
{ {
//buildFromFile("floater_marketplace_validation.xml"); //buildFromFile("floater_marketplace_validation.xml");
@@ -699,7 +805,7 @@ BOOL LLFloaterMarketplaceValidation::postBuild()
mEditor->setEnabled(FALSE); mEditor->setEnabled(FALSE);
mEditor->setFocus(TRUE); mEditor->setFocus(TRUE);
mEditor->setValue(LLSD()); mEditor->setValue(LLSD());
return TRUE; return TRUE;
} }
@@ -714,18 +820,55 @@ void LLFloaterMarketplaceValidation::draw()
LLFloater::draw(); LLFloater::draw();
} }
void LLFloaterMarketplaceValidation::onOpen(const LLSD& key) void LLFloaterMarketplaceValidation::onOpen(/*const LLSD& key*/)
{ {
// Clear the text panel // Clear the messages
mEditor->setValue(LLSD()); clearMessages();
// Validates the marketplace // Get the folder UUID to validate. Use the whole marketplace listing if none provided.
LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); LLUUID cat_id(mKey.asUUID());
if (marketplacelistings_id.notNull()) if (cat_id.isNull())
{ {
LLViewerInventoryCategory* cat = gInventory.getCategory(marketplacelistings_id); cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2), 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 // static
@@ -733,23 +876,53 @@ void LLFloaterMarketplaceValidation::onOK( void* userdata )
{ {
// destroys this object // destroys this object
LLFloaterMarketplaceValidation* self = (LLFloaterMarketplaceValidation*) userdata; LLFloaterMarketplaceValidation* self = (LLFloaterMarketplaceValidation*) userdata;
self->closeFloater(); self->clearMessages();
self->close();
} }
void LLFloaterMarketplaceValidation::appendMessage(std::string& message, LLError::ELevel log_level) void LLFloaterMarketplaceValidation::appendMessage(std::string& message, S32 depth, LLError::ELevel log_level)
{ {
if (mEditor) // Dump previous listing messages if we're starting a new listing
if (depth == 1)
{ {
// Errors are printed in bold, other messages in normal font handleCurrentListing();
LLStyle::Params style;
LLFontDescriptor new_desc(mEditor->getFont()->getFontDesc());
new_desc.setStyle(log_level == LLError::LEVEL_ERROR ? LLFontGL::BOLD : LLFontGL::NORMAL);
LLFontGL* new_font = LLFontGL::getFont(new_desc);
style.font = new_font;
mEditor->appendText(message, true, style);
} }
// 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
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -773,10 +946,10 @@ BOOL LLFloaterItemProperties::postBuild()
return LLFloater::postBuild(); return LLFloater::postBuild();
} }
void LLFloaterItemProperties::onOpen(/*const LLSD& key*/) void LLFloaterItemProperties::onOpen(const LLSD& key)
{ {
// Tell the panel which item it needs to visualize // Tell the panel which item it needs to visualize
LLPanel* panel = getChild<LLPanel>("item_panel"); LLPanel* panel = getChild<LLPanel>("item_panel");
panel->setItemID(key["id"].asUUID()); panel->setItemID(mKey["id"].asUUID());
} }
*/

View File

@@ -52,8 +52,14 @@ class LLPanelMarketplaceListings : public LLPanel
public: public:
LLPanelMarketplaceListings(); LLPanelMarketplaceListings();
BOOL postBuild(); BOOL postBuild();
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
void draw(); void draw();
LLFolderView* getRootFolder() { return mRootFolder; } LLFolderView* getRootFolder() { return mRootFolder; }
bool allowDropOnRoot();
void buildAllPanels(); void buildAllPanels();
@@ -69,19 +75,21 @@ private:
void onTabChange(); void onTabChange();
void onFilterEdit(const std::string& search_string); void onFilterEdit(const std::string& search_string);
void setSortOrder(U32 sort_order);
LLFolderView* mRootFolder; LLFolderView* mRootFolder;
LLButton* mAuditBtn; LLButton* mAuditBtn;
LLFilterEditor* mFilterEditor; LLFilterEditor* mFilterEditor;
std::string mFilterSubString; std::string mFilterSubString;
LLInventoryFilter::ESortOrderType mSortOrder; bool mFilterListingFoldersOnly;
LLInventoryFilter::EFilterType mFilterType; U32 mSortOrder;
}; };
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFloaterMarketplaceListings // Class LLFloaterMarketplaceListings
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFloaterMarketplaceListings : public LLFloater, public LLFloaterSingleton<LLFloaterMArketplaceListings> class LLFloaterMarketplaceListings : public LLFloater, public LLFloaterSingleton<LLFloaterMarketplaceListings>
{ {
public: public:
LLFloaterMarketplaceListings(const LLSD& key); LLFloaterMarketplaceListings(const LLSD& key);
@@ -103,13 +111,14 @@ public:
void onMouseLeave(S32 x, S32 y, MASK mask); void onMouseLeave(S32 x, S32 y, MASK mask);
protected: protected:
void setup(); void setRootFolder();
void setPanels();
void fetchContents(); void fetchContents();
void setStatusString(const std::string& statusString); void setStatusString(const std::string& statusString);
void onClose(bool app_quitting); void onClose(bool app_quitting);
void onOpen(const LLSD& key); void onOpen(/*const LLSD& key*/);
void onFocusReceived(); void onFocusReceived();
void onChanged(); void onChanged();
@@ -131,15 +140,15 @@ private:
LLUUID mRootFolderId; LLUUID mRootFolderId;
LLPanelMarketplaceListings * mPanelListings; LLPanelMarketplaceListings * mPanelListings;
bool mFirstViewListings; bool mPanelListingsSet;
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// LLFloaterAssociateListing // LLFloaterAssociateListing
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class LLFloaterAssociateListing : public LLFloater, public LLUISingleton<LLFloaterAssociateListing, LLFloaterAssociatedListing> class LLFloaterAssociateListing : public LLFloater, public LLUISingleton<LLFloaterAssociateListing, LLFloaterAssociateListing>
{ {
friend class LLFloaterReg; friend class LLUISingleton<LLFloaterAssociateListing, LLFloaterAssociateListing>;
public: public:
virtual BOOL postBuild(); virtual BOOL postBuild();
virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleKeyHere(KEY key, MASK mask);
@@ -163,6 +172,8 @@ private:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// LLFloaterMarketplaceValidation // LLFloaterMarketplaceValidation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Note: The key is the UUID of the folder to validate. Validates the whole
// marketplace listings content if UUID is null.
// Note: For the moment, we just display the validation text. Eventually, we should // Note: For the moment, we just display the validation text. Eventually, we should
// get the validation triggered on the server and display the html report. // get the validation triggered on the server and display the html report.
// *TODO : morph into an html/text window using the pattern in llfloatertos // *TODO : morph into an html/text window using the pattern in llfloatertos
@@ -175,12 +186,27 @@ public:
virtual BOOL postBuild(); virtual BOOL postBuild();
virtual void draw(); virtual void draw();
virtual void onOpen(const LLSD& key); virtual void onOpen(/*const LLSD& key*/);
void appendMessage(std::string& message, LLError::ELevel log_level); void clearMessages();
void appendMessage(std::string& message, S32 depth, LLError::ELevel log_level);
static void onOK( void* userdata ); static void onOK( void* userdata );
private: private:
struct Message {
LLError::ELevel mErrorLevel;
std::string mMessage;
};
typedef std::vector<Message> message_list_t;
void handleCurrentListing();
message_list_t mCurrentListingMessages;
LLError::ELevel mCurrentListingErrorLevel;
message_list_t mMessages;
LLSD mKey;
LLTextEditor* mEditor; LLTextEditor* mEditor;
}; };
@@ -195,10 +221,9 @@ public:
virtual ~LLFloaterItemProperties(); virtual ~LLFloaterItemProperties();
BOOL postBuild(); BOOL postBuild();
virtual void onOpen(const LLSD& key); virtual void onOpen(/*const LLSD& key*/);
private: private:
}; };
#endif // LL_LLFLOATERMARKETPLACELISTINGS_H #endif // LL_LLFLOATERMARKETPLACELISTINGS_H

View File

@@ -293,7 +293,7 @@ void LLFloaterOutbox::setupOutbox()
// Set the sort order newest to oldest // Set the sort order newest to oldest
inventory_panel->setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME); inventory_panel->setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME);
inventory_panel->getFilter()->markDefault(); inventory_panel->getFilter().markDefault();
// Get the content of the outbox // Get the content of the outbox
fetchOutboxContents(); fetchOutboxContents();

View File

@@ -588,7 +588,7 @@ void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags)
void LLFolderViewItem::openItem( void ) void LLFolderViewItem::openItem( void )
{ {
if (!mListener) return; if (!mListener) return;
if (mAllowWear || mListener->isItemWearable()) if (mAllowOpen || mListener->isItemWearable())
{ {
mListener->openItem(); mListener->openItem();
} }
@@ -1771,7 +1771,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo
{ {
return; return;
} }
if (selecting) if (selecting && (*it)->getVisible())
{ {
items.push_back(*it); items.push_back(*it);
} }
@@ -1790,7 +1790,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo
return; return;
} }
if (selecting) if (selecting && (*it)->getVisible())
{ {
items.push_back(*it); items.push_back(*it);
} }
@@ -1812,7 +1812,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo
return; return;
} }
if (selecting) if (selecting && (*it)->getVisible())
{ {
items.push_back(*it); items.push_back(*it);
} }
@@ -1831,7 +1831,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo
return; return;
} }
if (selecting) if (selecting && (*it)->getVisible())
{ {
items.push_back(*it); items.push_back(*it);
} }
@@ -2878,21 +2878,21 @@ bool LLInventorySort::operator()(const LLFolderViewItem* const& a, const LLFolde
} }
else if (mFoldersByWeight) else if (mFoldersByWeight)
{ {
S32 weight_a = compute_stock_count(a->getUUID()); S32 weight_a = compute_stock_count(a->getListener()->getUUID());
S32 weight_b = compute_stock_count(b->getUUID()); S32 weight_b = compute_stock_count(b->getListener()->getUUID());
if (weight_a == weight_b) if (weight_a == weight_b)
{ {
// Equal weight -> use alphabetical order // Equal weight -> use alphabetical order
return (LLStringUtil::compareDict(a->getDisplayName(), b->getDisplayName()) < 0); return (LLStringUtil::compareDict(a->getListener()->getDisplayName(), b->getListener()->getDisplayName()) < 0);
} }
else if (weight_a == -1) else if (weight_a == COMPUTE_STOCK_INFINITE)
{ {
// No weight -> move a at the end of the list // No stock -> move a at the end of the list
return false; return false;
} }
else if (weight_b == -1) else if (weight_b == COMPUTE_STOCK_INFINITE)
{ {
// No weight -> move b at the end of the list // No stock -> move b at the end of the list
return true; return true;
} }
else else

View File

@@ -141,8 +141,8 @@ protected:
BOOL mIsLoading; BOOL mIsLoading;
LLTimer mTimeSinceRequestStart; LLTimer mTimeSinceRequestStart;
bool mShowLoadStatus; bool mShowLoadStatus;
bool mAllowWear;
bool mAllowDrop; bool mAllowDrop;
bool mAllowOpen;
std::string mSearchable; std::string mSearchable;
U32 mSearchType; U32 mSearchType;
@@ -244,8 +244,8 @@ public:
void setShowLoadStatus(bool status) { mShowLoadStatus = status; } void setShowLoadStatus(bool status) { mShowLoadStatus = status; }
void setAllowWear(bool allow) { mAllowWear = allow; }
void setAllowDrop(bool allow) { mAllowDrop = allow; } void setAllowDrop(bool allow) { mAllowDrop = allow; }
void setAllowOpen(bool allow) { mAllowOpen = allow; }
// Call through to the viewed object and return true if it can be // Call through to the viewed object and return true if it can be
// removed. Returns true if it's removed. // removed. Returns true if it's removed.

View File

@@ -44,6 +44,7 @@
#include "llinventorymodelbackgroundfetch.h" #include "llinventorymodelbackgroundfetch.h"
#include "llinventorypanel.h" #include "llinventorypanel.h"
#include "llmakeoutfitdialog.h" #include "llmakeoutfitdialog.h"
#include "llmarketplacefunctions.h"
#include "llnotificationsutil.h" #include "llnotificationsutil.h"
#include "llpanelmaininventory.h" #include "llpanelmaininventory.h"
#include "llpanelobjectinventory.h" #include "llpanelobjectinventory.h"
@@ -63,6 +64,7 @@ using namespace LLOldEvents;
namespace LLInventoryAction namespace LLInventoryAction
{ {
void callback_doToSelected(const LLSD& notification, const LLSD& response, LLFolderView* folder, const std::string& action); void callback_doToSelected(const LLSD& notification, const LLSD& response, LLFolderView* folder, const std::string& action);
void callback_copySelected(const LLSD& notification, const LLSD& response, class LLFolderView* root, const std::string& action);
bool doToSelected(LLFolderView* root, std::string action, BOOL user_confirm = TRUE); bool doToSelected(LLFolderView* root, std::string action, BOOL user_confirm = TRUE);
void buildMarketplaceFolders(LLFolderView* root); void buildMarketplaceFolders(LLFolderView* root);
@@ -74,15 +76,26 @@ typedef LLMemberListener<LLPanelObjectInventory> object_inventory_listener_t;
typedef LLMemberListener<LLPanelMainInventory> inventory_listener_t; typedef LLMemberListener<LLPanelMainInventory> inventory_listener_t;
typedef LLMemberListener<LLInventoryPanel> inventory_panel_listener_t; typedef LLMemberListener<LLInventoryPanel> inventory_panel_listener_t;
std::list<LLUUID> LLInventoryAction::sMarketplaceFolders;
// Callback for doToSelected if DAMA required... // Callback for doToSelected if DAMA required...
void LLInventoryAction::callback_doToSelected(const LLSD& notification, const LLSD& response, LLFolderView* folder, const std::string& action) void LLInventoryAction::callback_doToSelected(const LLSD& notification, const LLSD& response, LLFolderView* folder, const std::string& action)
{ {
S32 option = LLNotificationsUtil::getSelectedOption(notification, response); S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0) // YES if (option == 0) // YES
{ {
doToSelected(folder, action, FALSE); doToSelected(folder, action);
}
}
void LLInventoryAction::callback_copySelected(const LLSD& notification, const LLSD& response, class LLFolderView* root, const std::string& action)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0) // YES, Move no copy item(s)
{
doToSelected(root, "copy_or_move_to_marketplace_listings");
}
else if (option == 1) // NO, Don't move no copy item(s) (leave them behind)
{
doToSelected(root, "copy_to_marketplace_listings");
} }
} }
@@ -105,7 +118,7 @@ bool LLInventoryAction::doToSelected(LLFolderView* root, std::string action, BOO
{ {
// Wearing an object from any listing, active or not, is verbotten // Wearing an object from any listing, active or not, is verbotten
LLNotificationsUtil::add("AlertMerchantListingCannotWear"); LLNotificationsUtil::add("AlertMerchantListingCannotWear");
return; return true;
} }
// Note: we do not prompt for change when opening items (e.g. textures or note cards) on the marketplace... // Note: we do not prompt for change when opening items (e.g. textures or note cards) on the marketplace...
} }
@@ -116,13 +129,30 @@ bool LLInventoryAction::doToSelected(LLFolderView* root, std::string action, BOO
if ((("cut" == action) || ("delete" == action)) && (LLMarketplaceData::instance().isListed(*set_iter) || LLMarketplaceData::instance().isVersionFolder(*set_iter))) if ((("cut" == action) || ("delete" == action)) && (LLMarketplaceData::instance().isListed(*set_iter) || LLMarketplaceData::instance().isVersionFolder(*set_iter)))
{ {
// Cut or delete of the active version folder or listing folder itself will unlist the listing so ask that question specifically // Cut or delete of the active version folder or listing folder itself will unlist the listing so ask that question specifically
LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, model, root, action)); LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, root, action));
return; return true;
} }
// Any other case will simply modify but not unlist a listing // Any other case will simply modify but not unlist a listing
LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, model, root, action)); LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, root, action));
return; return true;
} }
// Cutting or deleting a whole listing needs confirmation as SLM will be archived and inaccessible to the user
else if (LLMarketplaceData::instance().isListed(*set_iter) && (("cut" == action) || ("delete" == action)))
{
LLNotificationsUtil::add("ConfirmListingCutOrDelete", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, root, action));
return true;
}
}
}
// Copying to the marketplace needs confirmation if nocopy items are involved
if (("copy_to_marketplace_listings" == action))
{
std::set<LLUUID>::iterator set_iter = selected_items.begin();
bool contains_nocopy_items(const LLUUID& id);
if (contains_nocopy_items(*set_iter))
{
LLNotificationsUtil::add("ConfirmCopyToMarketplace", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_copySelected, _1, _2, root, action));
return true;
} }
} }
@@ -206,6 +236,7 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root)
// containing folder will need to be updated as well as their initially containing folder. For // containing folder will need to be updated as well as their initially containing folder. For
// instance, moving a stock folder from a listed folder to another will require an update of the // instance, moving a stock folder from a listed folder to another will require an update of the
// target listing *and* the original listing. So we need to keep track of both. // target listing *and* the original listing. So we need to keep track of both.
// Note: do not however put the marketplace listings root itself in this list or the whole marketplace data will be rebuilt.
sMarketplaceFolders.clear(); sMarketplaceFolders.clear();
const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
std::set<LLUUID> selected_items = root->getSelectionList(); std::set<LLUUID> selected_items = root->getSelectionList();
@@ -214,8 +245,16 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root)
const LLInventoryObject* obj(gInventory.getObject(*set_iter)); const LLInventoryObject* obj(gInventory.getObject(*set_iter));
if (gInventory.isObjectDescendentOf(obj->getParentUUID(), marketplacelistings_id)) if (gInventory.isObjectDescendentOf(obj->getParentUUID(), marketplacelistings_id))
{ {
sMarketplaceFolders.push_back(obj->getParentUUID()); const LLUUID& parent_id = obj->getParentUUID();
sMarketplaceFolders.push_back(obj->getUUID()); if (parent_id != marketplacelistings_id)
{
sMarketplaceFolders.push_back(parent_id);
}
const LLUUID& curr_id = obj->getUUID();
if (curr_id != marketplacelistings_id)
{
sMarketplaceFolders.push_back(curr_id);
}
} }
} }
// Suppress dupes in the list so we wo't update listings twice // Suppress dupes in the list so we wo't update listings twice

File diff suppressed because it is too large Load Diff

View File

@@ -72,6 +72,7 @@ public:
bool canShare() const; bool canShare() const;
bool canListOnMarketplace() const; bool canListOnMarketplace() const;
bool canListOnOutboxNow() const;
bool canListOnMarketplaceNow() const; bool canListOnMarketplaceNow() const;
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@@ -156,6 +157,7 @@ protected:
BOOL isAgentInventory() const; // false if lost or in the inventory library BOOL isAgentInventory() const; // false if lost or in the inventory library
BOOL isCOFFolder() const; // true if COF or descendant of BOOL isCOFFolder() const; // true if COF or descendant of
BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox
BOOL isOutboxFolderDirectParent() const; BOOL isOutboxFolderDirectParent() const;
BOOL isMarketplaceListingsFolder() const; // true if descendant of Marketplace listings folder BOOL isMarketplaceListingsFolder() const; // true if descendant of Marketplace listings folder
const LLUUID getOutboxFolder() const; const LLUUID getOutboxFolder() const;
@@ -175,6 +177,9 @@ public:
BOOL callback_cutToClipboard(const LLSD& notification, const LLSD& response); BOOL callback_cutToClipboard(const LLSD& notification, const LLSD& response);
BOOL perform_cutToClipboard(); BOOL perform_cutToClipboard();
public:
BOOL isOutboxFolder() const; // true if COF or descendant of marketplace outbox
protected: protected:
LLHandle<LLInventoryPanel> mInventoryPanel; LLHandle<LLInventoryPanel> mInventoryPanel;
LLFolderView* mRoot; LLFolderView* mRoot;
@@ -273,9 +278,7 @@ public:
virtual LLUIImagePtr getIcon() const; virtual LLUIImagePtr getIcon() const;
virtual LLUIImagePtr getIconOpen() const; virtual LLUIImagePtr getIconOpen() const;
virtual LLUIImagePtr getIconOverlay() const; virtual LLUIImagePtr getIconOverlay() const;
static LLUIImagePtr getIcon(LLFolderType::EType preferred_type); static LLUIImagePtr getIcon(LLFolderType::EType preferred_type);
virtual std::string getLabelSuffix() const; virtual std::string getLabelSuffix() const;
virtual LLFontGL::StyleFlags getLabelStyle() const; virtual LLFontGL::StyleFlags getLabelStyle() const;
@@ -346,10 +349,10 @@ public:
static LLHandle<LLFolderBridge> sSelf; static LLHandle<LLFolderBridge> sSelf;
static void staticFolderOptionsMenu(); static void staticFolderOptionsMenu();
private: protected:
void callback_pasteFromClipboard(const LLSD& notification, const LLSD& response); void callback_pasteFromClipboard(const LLSD& notification, const LLSD& response, bool only_copies);
void perform_pasteFromClipboard(); void perform_pasteFromClipboard(bool only_copies);
void gatherMessage(std::string& message, LLError::ELevel log_level); void gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level);
LLUIImagePtr getFolderIcon(BOOL is_open) const; LLUIImagePtr getFolderIcon(BOOL is_open) const;
bool mCallingCards; bool mCallingCards;
@@ -586,7 +589,6 @@ class LLMeshBridge : public LLItemBridge
public: public:
virtual LLUIImagePtr getIcon() const; virtual LLUIImagePtr getIcon() const;
virtual void openItem(); virtual void openItem();
virtual void previewItem();
virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
protected: protected:
@@ -654,7 +656,6 @@ class LLRecentInventoryBridgeBuilder : public LLInventoryFolderViewModelBuilder
{ {
public: public:
LLRecentInventoryBridgeBuilder() {} LLRecentInventoryBridgeBuilder() {}
// Overrides FolderBridge for Recent Inventory Panel. // Overrides FolderBridge for Recent Inventory Panel.
// It use base functionality for bridges other than FolderBridge. // It use base functionality for bridges other than FolderBridge.
virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type, virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type,
@@ -666,6 +667,31 @@ public:
U32 flags = 0x00) const; U32 flags = 0x00) const;
}; };
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Marketplace Inventory Panel related classes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLMarketplaceFolderBridge : public LLFolderBridge
{
public:
// Overloads some display related methods specific to folders in a marketplace floater context
LLMarketplaceFolderBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid);
virtual LLUIImagePtr getIcon() const;
virtual LLUIImagePtr getIconOpen() const;
virtual std::string getLabelSuffix() const;
virtual LLFontGL::StyleFlags getLabelStyle() const;
private:
LLUIImagePtr getMarketplaceFolderIcon(BOOL is_open) const;
// Those members are mutable because they are cached variables to speed up display, not a state variables
mutable S32 m_depth;
mutable S32 m_stockCountCache;
};
void rez_attachment(LLViewerInventoryItem* item, void rez_attachment(LLViewerInventoryItem* item,
LLViewerJointAttachment* attachment, LLViewerJointAttachment* attachment,
bool replace = false); bool replace = false);

View File

@@ -158,10 +158,29 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
// Marketplace folder filtering // Marketplace folder filtering
const U32 filterTypes = mFilterOps.mFilterTypes; const U32 filterTypes = mFilterOps.mFilterTypes;
const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE | FILTERTYPE_MARKETPLACE_UNASSOCIATED; const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE |
FILTERTYPE_MARKETPLACE_UNASSOCIATED | FILTERTYPE_MARKETPLACE_LISTING_FOLDER |
FILTERTYPE_NO_MARKETPLACE_ITEMS;
if (filterTypes & marketplace_filter) if (filterTypes & marketplace_filter)
{ {
S32 depth = depth_nesting_in_marketplace(folder_id); S32 depth = depth_nesting_in_marketplace(folder_id);
if (filterTypes & FILTERTYPE_NO_MARKETPLACE_ITEMS)
{
if (depth >= 0)
{
return false;
}
}
if (filterTypes & FILTERTYPE_MARKETPLACE_LISTING_FOLDER)
{
if (depth > 1)
{
return false;
}
}
if (depth > 0) if (depth > 0)
{ {
LLUUID listing_uuid = nested_parent_id(folder_id, depth); LLUUID listing_uuid = nested_parent_id(folder_id, depth);
@@ -179,7 +198,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
return false; return false;
} }
} }
else if (filterTypes & FILTER_MARKETPLACE_UNASSOCIATED) else if (filterTypes & FILTERTYPE_MARKETPLACE_UNASSOCIATED)
{ {
if (LLMarketplaceData::instance().isListed(listing_uuid)) if (LLMarketplaceData::instance().isListed(listing_uuid))
{ {
@@ -494,6 +513,25 @@ void LLInventoryFilter::setFilterMarketplaceUnassociatedFolders()
mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_UNASSOCIATED; mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_UNASSOCIATED;
} }
void LLInventoryFilter::setFilterMarketplaceListingFolders(bool select_only_listing_folders)
{
if (select_only_listing_folders)
{
mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_LISTING_FOLDER;
setModified(FILTER_MORE_RESTRICTIVE);
}
else
{
mFilterOps.mFilterTypes &= ~FILTERTYPE_MARKETPLACE_LISTING_FOLDER;
setModified(FILTER_LESS_RESTRICTIVE);
}
}
void LLInventoryFilter::setFilterNoMarketplaceFolder()
{
mFilterOps.mFilterTypes |= FILTERTYPE_NO_MARKETPLACE_ITEMS;
}
void LLInventoryFilter::setFilterUUID(const LLUUID& object_id) void LLInventoryFilter::setFilterUUID(const LLUUID& object_id)
{ {
if (mFilterOps.mFilterUUID == object_id) if (mFilterOps.mFilterUUID == object_id)

View File

@@ -58,10 +58,12 @@ public:
FILTERTYPE_UUID = 0x1 << 2, // find the object with UUID and any links to it FILTERTYPE_UUID = 0x1 << 2, // find the object with UUID and any links to it
FILTERTYPE_DATE = 0x1 << 3, // search by date range FILTERTYPE_DATE = 0x1 << 3, // search by date range
FILTERTYPE_WEARABLE = 0x1 << 4, // search by wearable type FILTERTYPE_WEARABLE = 0x1 << 4, // search by wearable type
FILTERTYPE_EMPTYFOLDERS = 0x1 << 5, // pass if folder is not a system folder to be hidden if empty FILTERTYPE_EMPTYFOLDERS = 0x1 << 5, // pass if folder is not a system folder to be hidden if empty
FILTERTYPE_MARKETPLACE_ACTIVE = 0x1 << 6, // pass if folder is a marketplace active folder FILTERTYPE_MARKETPLACE_ACTIVE = 0x1 << 6, // pass if folder is a marketplace active folder
FILTERTYPE_MARKETPLACE_INACTIVE = 0x1 << 7, // pass if folder is a marketplace inactive folder FILTERTYPE_MARKETPLACE_INACTIVE = 0x1 << 7, // pass if folder is a marketplace inactive folder
FILTERTYPE_MARKETPLACE_UNASSOCIATED = 0x1 << 8 // pass if folder is a marketplace non associated (no market ID) folder FILTERTYPE_MARKETPLACE_UNASSOCIATED = 0x1 << 8, // pass if folder is a marketplace non associated (no market ID) folder
FILTERTYPE_MARKETPLACE_LISTING_FOLDER = 0x1 << 9, // pass iff folder is a listing folder
FILTERTYPE_NO_MARKETPLACE_ITEMS = 0x1 << 10 // pass iff folder is not under the marketplace
}; };
enum EFilterLink enum EFilterLink
@@ -118,6 +120,8 @@ struct FilterOps
void setFilterMarketplaceActiveFolders(); void setFilterMarketplaceActiveFolders();
void setFilterMarketplaceInactiveFolders(); void setFilterMarketplaceInactiveFolders();
void setFilterMarketplaceUnassociatedFolders(); void setFilterMarketplaceUnassociatedFolders();
void setFilterMarketplaceListingFolders(bool select_only_listing_folders);
void setFilterNoMarketplaceFolder();
void updateFilterTypes(U64 types, U64& current_types); void updateFilterTypes(U64 types, U64& current_types);
void setFilterSubString(const std::string& string); void setFilterSubString(const std::string& string);

View File

@@ -37,6 +37,7 @@
#include "llinventorydefines.h" #include "llinventorydefines.h"
#include "llsdserialize.h" #include "llsdserialize.h"
#include "llspinctrl.h" #include "llspinctrl.h"
#include "lltrans.h"
#include "llui.h" #include "llui.h"
#include "message.h" #include "message.h"
@@ -45,6 +46,7 @@
#include "llappviewer.h" #include "llappviewer.h"
//#include "llfirstuse.h" //#include "llfirstuse.h"
#include "llfloaterinventory.h" #include "llfloaterinventory.h"
#include "llfloatermarketplacelistings.h"
#include "llfloateroutbox.h" #include "llfloateroutbox.h"
#include "llfocusmgr.h" #include "llfocusmgr.h"
#include "llfolderview.h" #include "llfolderview.h"
@@ -113,6 +115,21 @@ S32 count_copyable_items(LLInventoryModel::item_array_t& items)
return count; return count;
} }
// Helper function : Count only the non-copyable items, i.e. the stock items, skip the others
S32 count_stock_items(LLInventoryModel::item_array_t& items)
{
S32 count = 0;
for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it)
{
LLViewerInventoryItem* item = *it;
if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
{
count++;
}
}
return count;
}
// Helper function : Count the number of stock folders // Helper function : Count the number of stock folders
S32 count_stock_folders(LLInventoryModel::cat_array_t& categories) S32 count_stock_folders(LLInventoryModel::cat_array_t& categories)
{ {
@@ -128,6 +145,72 @@ S32 count_stock_folders(LLInventoryModel::cat_array_t& categories)
return count; return count;
} }
// Helper funtion : Count the number of items (not folders) in the descending hierarchy
S32 count_descendants_items(const LLUUID& cat_id)
{
LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array);
S32 count = item_array->size();
LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{
LLViewerInventoryCategory* category = *iter;
count += count_descendants_items(category->getUUID());
}
return count;
}
// Helper function : Returns true if the hierarchy contains nocopy items
bool contains_nocopy_items(const LLUUID& id)
{
LLInventoryCategory* cat = gInventory.getCategory(id);
if (cat)
{
// Get the content
LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(id,cat_array,item_array);
// Check all the items: returns true upon encountering a nocopy item
for (LLInventoryModel::item_array_t::iterator iter = item_array->begin(); iter != item_array->end(); iter++)
{
LLInventoryItem* item = *iter;
LLViewerInventoryItem * inv_item = (LLViewerInventoryItem *) item;
if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
{
return true;
}
}
// Check all the sub folders recursively
for (LLInventoryModel::cat_array_t::iterator iter = cat_array->begin(); iter != cat_array->end(); iter++)
{
LLViewerInventoryCategory* cat = *iter;
if (contains_nocopy_items(cat->getUUID()))
{
return true;
}
}
}
else
{
LLInventoryItem* item = gInventory.getItem(id);
LLViewerInventoryItem * inv_item = (LLViewerInventoryItem *) item;
if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
{
return true;
}
}
// Exit without meeting a nocopy item
return false;
}
// Generates a string containing the path to the item specified by // Generates a string containing the path to the item specified by
// item_id. // item_id.
void append_path(const LLUUID& id, std::string& path) void append_path(const LLUUID& id, std::string& path)
@@ -200,15 +283,20 @@ void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistenc
if (version_folder_uuid.notNull() && (!gInventory.isObjectDescendentOf(version_folder_uuid, listing_uuid) || (version_depth != 2))) if (version_folder_uuid.notNull() && (!gInventory.isObjectDescendentOf(version_folder_uuid, listing_uuid) || (version_depth != 2)))
{ {
LL_INFOS("SLM") << "Unlist and clear version folder as the version folder is not at the right place anymore!!" << LL_ENDL; LL_INFOS("SLM") << "Unlist and clear version folder as the version folder is not at the right place anymore!!" << LL_ENDL;
LLMarketplaceData::instance().setVersionFolder(listing_uuid, LLUUID::null); LLMarketplaceData::instance().setVersionFolder(listing_uuid, LLUUID::null,1);
}
else if (version_folder_uuid.notNull() && LLMarketplaceData::instance().getActivationState(version_folder_uuid) && (count_descendants_items(version_folder_uuid) == 0) && !LLMarketplaceData::instance().isUpdating(version_folder_uuid,version_depth))
{
LL_INFOS("SLM") << "Unlist as the version folder is empty of any item!!" << LL_ENDL;
LLNotificationsUtil::add("AlertMerchantVersionFolderEmpty");
LLMarketplaceData::instance().activateListing(listing_uuid, false,1);
} }
} }
// Check if the count on hand needs to be updated on SLM // Check if the count on hand needs to be updated on SLM
if (!LLMarketplaceData::instance().isUpdating(listing_uuid) && if (perform_consistency_enforcement && (compute_stock_count(listing_uuid) != LLMarketplaceData::instance().getCountOnHand(listing_uuid)))
(compute_stock_count(listing_uuid) != LLMarketplaceData::instance().getCountOnHand(listing_uuid)))
{ {
LLMarketplaceData::instance().updateCountOnHand(listing_uuid); LLMarketplaceData::instance().updateCountOnHand(listing_uuid,1);
} }
// Update all descendents starting from the listing root // Update all descendents starting from the listing root
update_marketplace_folder_hierarchy(listing_uuid); update_marketplace_folder_hierarchy(listing_uuid);
@@ -324,7 +412,8 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
void copy_inventory_category(LLInventoryModel* model, void copy_inventory_category(LLInventoryModel* model,
LLViewerInventoryCategory* cat, LLViewerInventoryCategory* cat,
const LLUUID& parent_id, const LLUUID& parent_id,
const LLUUID& root_copy_id) const LLUUID& root_copy_id,
bool move_no_copy_items)
{ {
// Create the initial folder // Create the initial folder
LLUUID new_cat_uuid = gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName()); LLUUID new_cat_uuid = gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName());
@@ -338,19 +427,41 @@ void copy_inventory_category(LLInventoryModel* model,
LLInventoryModel::item_array_t* item_array; LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array);
// If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder
if (root_copy_id.isNull())
{
LLMarketplaceData::instance().setValidationWaiting(root_id,count_descendants_items(cat->getUUID()));
}
// Copy all the items // Copy all the items
LLInventoryModel::item_array_t item_array_copy = *item_array; LLInventoryModel::item_array_t item_array_copy = *item_array;
for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
{ {
LLInventoryItem* item = *iter; LLInventoryItem* item = *iter;
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid));
copy_inventory_item(
gAgent.getID(), if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
item->getPermissions().getOwner(), {
item->getUUID(), // If the item is nocopy, we do nothing or, optionally, move it
new_cat_uuid, if (move_no_copy_items)
std::string(), {
cb); // Reparent the item
LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) item;
gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true);
}
// Decrement the count in root_id since that one item won't be copied over
LLMarketplaceData::instance().decrementValidationWaiting(root_id);
}
else
{
copy_inventory_item(
gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
new_cat_uuid,
std::string(),
cb);
}
} }
// Copy all the folders // Copy all the folders
@@ -360,7 +471,7 @@ void copy_inventory_category(LLInventoryModel* model,
LLViewerInventoryCategory* category = *iter; LLViewerInventoryCategory* category = *iter;
if (category->getUUID() != root_id) if (category->getUUID() != root_id)
{ {
copy_inventory_category(model, category, new_cat_uuid, root_id); copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items);
} }
} }
} }
@@ -672,6 +783,11 @@ void open_outbox()
LLFloaterOutbox::showInstance(); LLFloaterOutbox::showInstance();
} }
void open_marketplace_listings()
{
LLFloaterMarketplaceListings::showInstance();
}
// Create a new folder in destFolderId with the same name as the item name and return the uuid of the new folder // Create a new folder in destFolderId with the same name as the item name and return the uuid of the new folder
// Note: this is used locally in various situation where we need to wrap an item into a special folder // Note: this is used locally in various situation where we need to wrap an item into a special folder
LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId) LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId)
@@ -900,17 +1016,23 @@ LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth)
return cur_uuid; return cur_uuid;
} }
S32 compute_stock_count(LLUUID cat_uuid) S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */)
{ {
// Handle the case of the folder being a stock folder immediately // Handle the case of the folder being a stock folder immediately
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_uuid); LLViewerInventoryCategory* cat = gInventory.getCategory(cat_uuid);
if (!cat) if (!cat)
{ {
// Not a category so no stock count to speak of // Not a category so no stock count to speak of
return -1; return COMPUTE_STOCK_INFINITE;
} }
if (cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) if (cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)
{ {
if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
{
// If the folder is not completely fetched, we do not want to return any confusing value that could lead to unlisting
// "COMPUTE_STOCK_NOT_EVALUATED" denotes that a stock folder has a count that cannot be evaluated at this time (folder not up to date)
return COMPUTE_STOCK_NOT_EVALUATED;
}
// Note: stock folders are *not* supposed to have nested subfolder so we stop recursion here but we count only items (subfolders will be ignored) // Note: stock folders are *not* supposed to have nested subfolder so we stop recursion here but we count only items (subfolders will be ignored)
// Note: we *always* give a stock count for stock folders, it's useful even if the listing is unassociated // Note: we *always* give a stock count for stock folders, it's useful even if the listing is unassociated
LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::cat_array_t* cat_array;
@@ -919,54 +1041,60 @@ S32 compute_stock_count(LLUUID cat_uuid)
return item_array->size(); return item_array->size();
} }
// Grab marketplace data for this folder // When force_count is true, we do not do any verification of the marketplace status and simply compute
S32 depth = depth_nesting_in_marketplace(cat_uuid); // the stock amount based on the descendent hierarchy. This is used specifically when creating a listing.
LLUUID listing_uuid = nested_parent_id(cat_uuid, depth); if (!force_count)
if (!LLMarketplaceData::instance().isListed(listing_uuid))
{ {
// If not listed, the notion of stock is meaningless so it won't be computed for any level // Grab marketplace data for this folder
return -1; S32 depth = depth_nesting_in_marketplace(cat_uuid);
} LLUUID listing_uuid = nested_parent_id(cat_uuid, depth);
if (!LLMarketplaceData::instance().isListed(listing_uuid))
{
// If not listed, the notion of stock is meaningless so it won't be computed for any level
return COMPUTE_STOCK_INFINITE;
}
LLUUID version_folder_uuid = LLMarketplaceData::instace().getVersionFolder(listing_uuid); LLUUID version_folder_uuid = LLMarketplaceData::instance().getVersionFolder(listing_uuid);
// Handle the case of the first 2 levels : listing and version folders // Handle the case of the first 2 levels : listing and version folders
if (depth == 1) if (depth == 1)
{
if (version_folder_uuid.notNull())
{ {
// If there is a version folder, the stock value for the listing is the version folder stock if (version_folder_uuid.notNull())
return compute_stock_count(version_folder_uuid); {
// If there is a version folder, the stock value for the listing is the version folder stock
return compute_stock_count(version_folder_uuid, true);
}
else
{
// If there's no version folder associated, the notion of stock count has no meaning
return COMPUTE_STOCK_INFINITE;
}
} }
else else if (depth == 2)
{ {
// If there's no version folder associated, the notion of stock count has no meaning if (version_folder_uuid.notNull() && (version_folder_uuid != cat_uuid))
return -1; {
} // If there is a version folder but we're not it, our stock count is meaningless
} return COMPUTE_STOCK_INFINITE;
else if (depth == 2) }
{
if (version_folder_uuid.notNull() && (version_folder_uuid != cat_uuid))
{
// If there is a version folder but we're not it, our stock count is meaningless
return -1;
} }
} }
// In all other cases, the stock count is the min of stock folders count found in the descendents // In all other cases, the stock count is the min of stock folders count found in the descendents
// "COMPUTE_STOCK_NOT_EVALUATED" denotes that a stock folder in the hierarchy has a count that cannot be evaluated at this time (folder not up to date)
LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array; LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array);
// "-1" denotes a folder that doesn't contain any stock folders in its descendents // "COMPUTE_STOCK_INFINITE" denotes a folder that doesn't contain any stock folders in its descendents
S32 curr_count = -1; S32 curr_count = COMPUTE_STOCK_INFINITE;
// Note: marketplace listings have a maximum depth nesting of 4 // Note: marketplace listings have a maximum depth nesting of 4
LLInventoryModel::cat_array_t cat_array_copy = *cat_array; LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{ {
LLInventoryCategory* category = *iter; LLInventoryCategory* category = *iter;
S32 count = compute_stock_count(category->getUUID()); S32 count = compute_stock_count(category->getUUID(), true);
if ((curr_count == -1) || ((count != -1) && (count < curr_count))) if ((curr_count == COMPUTE_STOCK_INFINITE) || ((count != COMPUTE_STOCK_INFINITE) && (count < curr_count)))
{ {
curr_count = count; curr_count = count;
} }
@@ -1128,6 +1256,11 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve
// If the dest folder is a stock folder, we do not count the incoming items toward the total (stock items are seen as one) // If the dest folder is a stock folder, we do not count the incoming items toward the total (stock items are seen as one)
int existing_item_count = (move_in_stock ? 0 : bundle_size); int existing_item_count = (move_in_stock ? 0 : bundle_size);
// If the dest folder is a stock folder, we do assume that the incoming items are also stock items (they should anyway)
int existing_stock_count = (move_in_stock ? bundle_size : 0);
int existing_folder_count = 0;
// Get the version folder: that's where the counts start from // Get the version folder: that's where the counts start from
const LLViewerInventoryCategory* version_folder = ((root_folder && (root_folder != dest_folder)) ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); const LLViewerInventoryCategory* version_folder = ((root_folder && (root_folder != dest_folder)) ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL);
@@ -1143,6 +1276,15 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve
LLInventoryModel::item_array_t existing_items; LLInventoryModel::item_array_t existing_items;
gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE);
existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories);
existing_stock_count += count_stock_items(existing_items);
existing_folder_count += existing_categories.size();
// If the incoming item is a nocopy (stock) item, we need to consider that it will create a stock folder
if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && !move_in_stock)
{
// Note : we do not assume that all incoming items are nocopy of different kinds...
existing_folder_count += 1;
}
} }
if (existing_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) if (existing_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount"))
@@ -1153,6 +1295,22 @@ bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInve
tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects", args); tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects", args);
accept = false; accept = false;
} }
else if (existing_stock_count > gSavedSettings.getU32("InventoryOutboxMaxStockItemCount"))
{
LLStringUtil::format_map_t args;
U32 amount = gSavedSettings.getU32("InventoryOutboxMaxStockItemCount");
args["[AMOUNT]"] = llformat("%d",amount);
tooltip_msg = LLTrans::getString("TooltipOutboxTooManyStockItems", args);
accept = false;
}
else if (existing_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount"))
{
LLStringUtil::format_map_t args;
U32 amount = gSavedSettings.getU32("InventoryOutboxMaxFolderCount");
args["[AMOUNT]"] = llformat("%d",amount);
tooltip_msg = LLTrans::getString("TooltipOutboxTooManyFolders", args);
accept = false;
}
} }
return accept; return accept;
@@ -1193,7 +1351,9 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn
int dragged_folder_count = descendent_categories.size() + bundle_size; // Note: We assume that we're moving a bunch of folders in. That might be wrong... int dragged_folder_count = descendent_categories.size() + bundle_size; // Note: We assume that we're moving a bunch of folders in. That might be wrong...
int dragged_item_count = count_copyable_items(descendent_items) + count_stock_folders(descendent_categories); int dragged_item_count = count_copyable_items(descendent_items) + count_stock_folders(descendent_categories);
int dragged_stock_count = count_stock_items(descendent_items);
int existing_item_count = 0; int existing_item_count = 0;
int existing_stock_count = 0;
int existing_folder-count = 0; int existing_folder-count = 0;
if (version_folder) if (version_folder)
@@ -1203,6 +1363,7 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn
// Clear those counts or they will be counted twice because we're already inside the version category // Clear those counts or they will be counted twice because we're already inside the version category
dragged_folder_count = 0; dragged_folder_count = 0;
dragged_item_count = 0; dragged_item_count = 0;
dragged_stock_count = 0;
} }
// Tally the total number of categories and items inside the root folder // Tally the total number of categories and items inside the root folder
@@ -1212,10 +1373,12 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn
existing_folder_count += existing_categories.size(); existing_folder_count += existing_categories.size();
existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories);
existing_stock_count += count_stock_items(existing_items);
} }
const int total_folder_count = existing_folder_count + dragged_folder_count; const int total_folder_count = existing_folder_count + dragged_folder_count;
const int total_item_count = existing_item_count + dragged_item_count; const int total_item_count = existing_item_count + dragged_item_count;
const int total_stock_count = existing_stock_count + dragged_stock_count;
if (total_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) if (total_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount"))
{ {
@@ -1233,6 +1396,14 @@ bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLIn
tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects", args); tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects", args);
accept = false; accept = false;
} }
else if (total_stock_count > gSavedSettings.getU32("InventoryOutboxMaxStockItemCount"))
{
LLStringUtil::format_map_t args;
U32 amount = gSavedSettings.getU32("InventoryOutboxMaxStockItemCount");
args["[AMOUNT]"] = llformat("%d",amount);
tooltip_msg = LLTrans::getString("TooltipOutboxTooManyStockItems", args);
accept = false;
}
// Now check that each item in the folder can be moved in the marketplace // Now check that each item in the folder can be moved in the marketplace
if (accept && check_items) if (accept && check_items)
@@ -1279,6 +1450,12 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem();
viewer_inv_item = (linked_item != NULL ? linked_item : viewer_inv_item); viewer_inv_item = (linked_item != NULL ? linked_item : viewer_inv_item);
// If we want to copy but the item is no copy, fail silently (this is a common case that doesn't warrant notification)
if (copy && !viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
{
return false;
}
// Check that the agent has transfer permission on the item: this is required as a resident cannot // Check that the agent has transfer permission on the item: this is required as a resident cannot
// put on sale items she cannot transfer. Proceed with move if we have permission. // put on sale items she cannot transfer. Proceed with move if we have permission.
std::string error_msg; std::string error_msg;
@@ -1301,7 +1478,7 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) &&
(dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK)) (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK))
{ {
// We need a stock folder // We need to create a stock folder to move a no copy item
dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName()); dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName());
dest_cat = gInventory.getCategory(dest_folder); dest_cat = gInventory.getCategory(dest_folder);
depth++; depth++;
@@ -1325,7 +1502,7 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder)); LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder));
copy_inventory_item( copy_inventory_item(
gAgent.getID(), gAgent.getID(),
LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder)); viewer_inv_item->getPermissions().getOwner(),
viewer_inv_item->getUUID(), viewer_inv_item->getUUID(),
dest_folder, dest_folder,
std::string(), std::string(),
@@ -1336,11 +1513,6 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
// Reparent the item // Reparent the item
gInventory.changeItemParent(viewer_inv_item, dest_folder, true); gInventory.changeItemParent(viewer_inv_item, dest_folder, true);
} }
// Update the modified folders
update_marketplace_category(src_folder);
update_marketplace_category(dest_folder);
gInventory.notifyObservers();
} }
else else
{ {
@@ -1350,10 +1522,12 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol
return false; return false;
} }
} }
open_marketplace_listings();
return true; return true;
} }
bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy) bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy, bool move_no_copy_items)
{ {
// Check that we have adequate permission on all items being moved. Proceed if we do. // Check that we have adequate permission on all items being moved. Proceed if we do.
std::string error_msg; std::string error_msg;
@@ -1378,17 +1552,16 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU
if (copy) if (copy)
{ {
// Copy the folder // Copy the folder
copy_inventory_category(&gInventory, viewer_inv_cat, dest_folder); copy_inventory_category(&gInventory, viewer_inv_cat, dest_folder, LLUUID::null, move_no_copy_items);
} }
else else
{ {
// Reparent the folder // Reparent the folder
gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false); gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false);
// Check the destination folder recursively for no copy items and promote the including folders if any
validate_marketplacelistings(dest_cat);
} }
// Check the destination folder recursively for no copy items and promote the including folders if any
validate_marketplacelistings(dest_cat);
// Update the modified folders // Update the modified folders
update_marketplace_category(src_folder); update_marketplace_category(src_folder);
update_marketplace_category(dest_folder); update_marketplace_category(dest_folder);
@@ -1401,31 +1574,51 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU
LLNotificationsUtil::add("MerchantPasteFailed", subs); LLNotificationsUtil::add("MerchantPasteFailed", subs);
return false; return false;
} }
open_marketplace_listings();
return true; return true;
} }
bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCategory* cat2)
{
return cat1->getName().compare(cat2->getName()) < 0;
}
void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level)
{
llinfos << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << llendl;
}
// Make all relevant business logic checks on the marketplace listings starting with the folder as argument. // Make all relevant business logic checks on the marketplace listings starting with the folder as argument.
// This function does no deletion of listings but a mere audit and raises issues to the user (through the // This function does no deletion of listings but a mere audit and raises issues to the user (through the
// optional callback cb). It also returns a boolean, true if things validate, false if issues are raised. // optional callback cb). It also returns a boolean, true if things validate, false if issues are raised.
// The only inventory changes that are done is to move ad sort folders containing no-copy items to stock folders. // The only inventory changes that are done is to move ad sort folders containing no-copy items to stock folders.
bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCategory* cat2) bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_t cb, bool fix_hierarchy, S32 depth)
{
return cat1->getName().compare(cat2->getName()) < 0;
}
bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_t cb, bool fix_hierarchy)
{ {
#if 0
// Used only for debug
if (!cb)
{
cb = boost::bind(&dump_trace, _1, _2, _3);
}
#endif
// Folder is valid unless an issues is raised // Folder is valid unless an issues is raised
bool result = true; bool result = true;
// Get the type and the depth of the folder // Get the type and the depth of the folder
LLViewerInventoryCategory* viewer_cat = (LLViewerInventoryCategory*) (cat); LLViewerInventoryCategory* viewer_cat = (LLViewerInventoryCategory*) (cat);
const LLFolderType::EType folder_type = cat->getPreferredType(); const LLFolderType::EType folder_type = cat->getPreferredType();
S32 depth = depth_nesting_in_marketplace(cat->getUUID());
if (depth < 0) if (depth < 0)
{ {
// If the folder is not under the marketplace listings root, validation should not be applied // If the depth argument was not provided, evaluate the depth directlyu
return result; depth = depth_nesting_in_marketplace(cat->getUUID());
}
if (depth < 0)
{
// If the folder is not under the marketplace listings root, we run validation as if it was a listing folder and prevent any hierarchy fix
// This allows the function to be used to pre-validate a folder anywhere in the inventory
depth = 1;
fix_hierarchy = false;
} }
// Set the indentation for print output (typically, audit button in marketplace folder floater) // Set the indentation for print output (typically, audit button in marketplace folder floater)
@@ -1446,7 +1639,7 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
if (cb) if (cb)
{ {
message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message; message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message;
cb(message,LLError::LEVEL_ERROR); cb(message, depth, LLError::LEVEL_ERROR);
} }
} }
} }
@@ -1459,14 +1652,14 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
if (cb) if (cb)
{ {
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_WARN);
} }
// Nest the stock folder one level deeper in a normal folder ad restart from there // Nest the stock folder one level deeper in a normal folder ad restart from there
LLUUID parent_uuid = cat->getParentUUID(); LLUUID parent_uuid = cat->getParentUUID();
LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName()); LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName());
LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid); LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid);
gInventory.changeCategoryParent(viewer_cat, folder_uuid, false); gInventory.changeCategoryParent(viewer_cat, folder_uuid, false);
result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy); result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy, depth + 1);
return result; return result;
} }
else else
@@ -1475,25 +1668,25 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
if (cb) if (cb)
{ {
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
cb(message, LLError::LEVEL_ERROR); cb(message, depth, LLError::LEVEL_ERROR);
} }
} }
} }
// Item sorting and validation : sorting and moving the various stock items is complicated as the set of constraints is high
// We need to:
// * separate non stock items, stock items per types in different folders
// * have stock items nested at depth 2 at least
// * never ever move the non-stock items
LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array; LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array);
// Stock items : sorting and moving the various stock items is complicated as the set of constraints is high // We use a composite (type,permission) key on that map to store UUIDs of items of same (type,permissions)
// For each folder, we need to: std::map<U32, std::vector<LLUUID> > items_vector;
// * separate non stock items, stock items per types in different folders
// * have stock items nested at depth 2 at least
// * never ever move the non-stock items
std::vector<std::vector<LLViewerInventoryItem*> > items_vector; // Parse the items and create vectors of item UUIDs sorting copyable items and stock items of various types
items_vector.resize(LLInventoryType::IT_COUNT+1);
// Parse the items and create vectors of items to sort copyable items and stock items of various types
bool has_bad_items = false; bool has_bad_items = false;
LLInventoryModel::item_array_t item_array_copy = *item_array; LLInventoryModel::item_array_t item_array_copy = *item_array;
for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
@@ -1509,44 +1702,41 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
if (cb && fix_hierarchy) if (cb && fix_hierarchy)
{ {
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg; std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
cb(message, LLError::LEVEL_ERROR); cb(message, depth, LLError::LEVEL_ERROR);
} }
continue; continue;
} }
// Update the appropriate vector item for that type // Update the appropriate vector item for that type
LLInventoryType::EType type = LLInventoryType::IT_COUNT; // Default value for non stock items LLInventoryType::EType type = LLInventoryType::IT_COUNT; // Default value for non stock items
U32 perms = 0;
if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
{ {
// Get the item type for stock items // Get the item type for stock items
type = viewer_inv_item->getInventoryType(); type = viewer_inv_item->getInventoryType();
perms = viewer_inv_item->getPermissions().getMaskNextOwner();
} }
items_vector[type].push_back(viewer_inv_item); U32 key = (((U32)(type) & 0xFF) << 24) | (perms & 0xFFFFFF);
items_vector[key].push_back(viewer_inv_item->getUUID());
} }
// How many types of folders? Which type is it if only one? // How many types of items? Which type is it if only one?
S32 count = 0; S32 count = items_vector.size();
LLInventoryType::EType type = LLInventoryType::IT_COUNT; U32 default_key = (U32)(LLInventoryType::IT_COUNT) << 24; // This is the key for any normal copyable item
for (S32 i = 0; i <= LLInventoryType::IT_COUNT; i++) U32 unique_key = (count == 1 ? items_vector.begin()->first : default_key); // The key in the case of one item type only
{
if (!items_vector[i].empty())
{
count++;
type = (LLInventoryType::EType)(i);
}
}
// If we have no items in there (only folders or empty), analyze a bit further // If we have no items in there (only folders or empty), analyze a bit further
if ((count == 0) && !has_bad_items) if ((count == 0) && !has_bad_items)
{ {
if (cat_array->size() == 0) if (cat_array->size() == 0)
{ {
// So we have no item and no folder. That's at least a warning.
if (depth == 2) if (depth == 2)
{ {
// If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist) // If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist)
if (cb) if (cb)
{ {
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version");
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_WARN);
} }
} }
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2)) else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2))
@@ -1555,14 +1745,14 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
if (cb) if (cb)
{ {
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock");
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_WARN);
} }
} }
else if (cb) else if (cb)
{ {
// We warn if there's nothing in a regular folder (maybe it's an under construction listing) // We warn if there's nothing in a regular folder (maybe it's an under construction listing)
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty");
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_WARN);
} }
} }
else else
@@ -1571,34 +1761,43 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
if (cb && result && (depth >= 1)) if (cb && result && (depth >= 1))
{ {
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message, LLError::LEVEL_INFO); cb(message, depth, LLError::LEVEL_INFO);
} }
} }
} }
// If we have a single type of items of the right type in the right place, we're done // If we have a single type of items of the right type in the right place, we're done
else if ((count == 1) && !has_bad_items && (((type == LLInventoryType::IT_COUNT) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0)))) else if ((count == 1) && !has_bad_items && (((unique_key == default_key) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0))))
{ {
// Done with that folder : PRint out the folder name unless we alreaady found an error here // Done with that folder : Print out the folder name unless we alreaady found an error here
if (cb && result && (depth >= 1)) if (cb && result && (depth >= 1))
{ {
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message, LLError::LEVEL_INFO); cb(message, depth, LLError::LEVEL_INFO);
} }
} }
else else
{ {
if (fix_hierarchy && !has_bad_items) if (fix_hierarchy && !has_bad_items)
{ {
// Create one folder per vector at the right depth and of the right type // Alert the user when an existing stock folder has to be split
for (S32 i = 0; i <= LLInventoryType::IT_COUNT; i++) if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && ((count >= 2) || (cat_array->size() > 0)))
{ {
if (!items_vectory[i].empty()) LLNotificationsUtil::add("AlertMerchantStockFolderSplit");
}
// If we have more than 1 type of items or we are at the listing level or we have stock/no stock type mismatch, wrap the items in subfolders
if ((count > 1) || (depth == 1) ||
((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (unique_key == default_key)) ||
((folder_type != LLFolderType::FT_MARKETPLACE_STOCK) && (unique_key != default_key)))
{
// Create one folder per vector at the right depth and of the right type
std::map<U32, std::vector<LLUUID> >::iterator items_vector_it = items_vector.begin();
while (items_vector_it != items_vector.end())
{ {
// Create a new folder // Create a new folder
LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID()); LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
LLViewerInventoryItem* viewer_inv_item = items_vector[i].back(); LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
std::string folder_name = (depth > 1 ? viewer_cat->getName() : viewer_inv_item->getName()); std::string folder_name = (depth >= 1 ? viewer_cat->getName() : viewer_inv_item->getName());
LLFolderType::EType new_folder_type = (i == LLInventoryType::IT_COUNT ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK); LLFolderType::EType new_folder_type = (items_vector_it->first == default_key ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK);
if (cb) if (cb)
{ {
std::string message = ""; std::string message = "";
@@ -1610,35 +1809,41 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
{ {
message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version"); message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version");
} }
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_WARN);
} }
LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, new_folder_type, folder_name); LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, new_folder_type, folder_name);
// Move each item to the new folder // Move each item to the new folder
while (!items_vector[i].empty()) while (!items_vector_it->second.empty())
{ {
LLViewerInventoryItem* viewer_inv_item = items_vector[i].back(); LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
if (cb) if (cb)
{ {
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move"); std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_WARN);
} }
gInventory.changeItemParent(viewer_inv_item, folder_uuid, true); gInventory.changeItemParent(viewer_inv_item, folder_uuid, true);
items_vector[i].pop_back(); items_vector_it->second.pop_back();
} }
// Next type
update_marketplace_category(parent_uuid);
update_marketplace_category(folder_uuid); update_marketplace_category(folder_uuid);
gInventory.notifyObservers(); gInventory.notifyObservers();
items_vector_it++;
} }
} }
// Stock folder should have no sub folder so reparent those up // Stock folder should have no sub folder so reparent those up
if (folder_type == LLFolderType::FT_MARKETPLACE_STOCK) if (folder_type == LLFolderType::FT_MARKETPLACE_STOCK)
{ {
LLUUID parent_uuid = cat->getParentUUID(); LLUUID parent_uuid = cat->getParentUUID();
gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array);
LLInventoryModel::cat_array_t cat_array_copy = *cat_array; LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{ {
LLViewerInventoryCategory* viewer_cat = (LLViewerInventoryCategory*) (*iter); LLViewerInventoryCategory* viewer_cat = (LLViewerInventoryCategory*) (*iter);
gInventory.changeCategoryParent(viewer_cat, parent_uuid, false); gInventory.changeCategoryParent(viewer_cat, parent_uuid, false);
// Note : those reparented folders will be recursively visited and validated at the end of this function result &= validate_marketplacelistings(viewer_cat, cb, fix_hierarchy, depth);
} }
} }
} }
@@ -1653,20 +1858,20 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
// Report if a stock folder contains a mix of items // Report if a stock folder contains a mix of items
result = false; result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock");
cb(message, LLError::LEVEL_ERROR); cb(message, depth, LLError::LEVEL_ERROR);
} }
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0)) else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0))
{ {
// Report if a stock folder contains subfolders // Report if a stock folder contains subfolders
result = false; result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock");
cb(message, LLError::LEVEL_ERROR); cb(message, depth, LLError::LEVEL_ERROR);
} }
else else
{ {
// Simply print the folder name // Simply print the folder name
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message, LLError::LEVEL_INFO); cb(message, depth, LLError::LEVEL_INFO);
} }
} }
@@ -1682,20 +1887,21 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
// Report items that shouldn't be there to start with // Report items that shouldn't be there to start with
result = false; result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg; std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
cb(message, LLError::LEVEL_ERROR); cb(message, depth, LLError::LEVEL_ERROR);
} }
else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK)) else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK))
{ {
// Report stock items that are misplaced // Report stock items that are misplaced
result = false; result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item"); std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item");
cb(message, LLError::LEVEL_ERROR); cb(message, depth, LLError::LEVEL_ERROR);
} }
else if (depth == 1) else if (depth == 1)
{ {
// Report items not wrapped in version folder // Report items not wrapped in version folder
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item"); std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item");
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_ERROR);
} }
} }
} }
@@ -1707,21 +1913,16 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
if (cb) if (cb)
{ {
std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete"); std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete");
cb(message, LLError::LEVEL_WARN); cb(message, depth, LLError::LEVEL_WARN);
} }
gInventory.removeCategory(cat->getUUID()); gInventory.removeCategory(cat->getUUID());
gInventory.notifyObservers(); gInventory.notifyObservers();
return result && !has_bad_items; return result && !has_bad_items;
} }
else
{
// Update the current folder
update_marketplace_category(cat->getUUID());
gInventory.notifyObservers();
}
} }
// Recursion : Perform the same validation on each nested folder // Recursion : Perform the same validation on each nested folder
gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array);
LLInventoryModel::cat_array_t cat_array_copy = *cat_array; LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
// Sort the folders in alphabetical order first // Sort the folders in alphabetical order first
std::sort(cat_array_copy.begin(), cat_array_copy.end(), sort_alpha); std::sort(cat_array_copy.begin(), cat_array_copy.end(), sort_alpha);
@@ -1729,9 +1930,11 @@ bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{ {
LLInventoryCategory* category = *iter; LLInventoryCategory* category = *iter;
result &= validate_marketplacelistings(category, cb, fix_hierarchy); result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1);
} }
update_marketplace_category(cat->getUUID());
gInventory.notifyObservers();
return result && !has_bad_items; return result && !has_bad_items;
} }

View File

@@ -32,6 +32,10 @@
#include "llinventory.h" #include "llinventory.h"
#include "llwearabletype.h" #include "llwearabletype.h"
// compute_stock_count() return error code
const S32 COMPUTE_STOCK_INFINITE = -1;
const S32 COMPUTE_STOCK_NOT_EVALUATED = -2;
/******************************************************************************** /********************************************************************************
** ** ** **
** MISCELLANEOUS GLOBAL FUNCTIONS ** MISCELLANEOUS GLOBAL FUNCTIONS
@@ -62,7 +66,7 @@ void update_all_marketplace_count();
void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name); void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name);
void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null); void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null, bool move_no_copy_items = false);
// Generates a string containing the path to the item specified by item_id. // Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path); void append_path(const LLUUID& id, std::string& path);
@@ -74,16 +78,16 @@ void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LL
void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id); void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id);
void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id); void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id);
typedef boost::function<void(std::string& validation_message, LLError::ELevel log_level)> validation_callback_t; typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t;
bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false); bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false);
bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false); bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false);
bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false); bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false);
bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false); bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false, bool move_no_copy_items = false);
bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true); bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true, S32 depth = -1);
S32 depth_nesting_in_marketplace(LLUUID cur_uuid); S32 depth_nesting_in_marketplace(LLUUID cur_uuid);
LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth); LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
S32 computer_stock_count(LLUUID cat_uuid); S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
/** Miscellaneous global functions /** Miscellaneous global functions
** ** ** **

View File

@@ -38,6 +38,7 @@
#include "llinventoryobserver.h" #include "llinventoryobserver.h"
#include "llinventorypanel.h" #include "llinventorypanel.h"
#include "llnotificationsutil.h" #include "llnotificationsutil.h"
#include "llmarketplacefunctions.h"
#include "llwindow.h" #include "llwindow.h"
#include "llviewercontrol.h" #include "llviewercontrol.h"
#include "llpreview.h" #include "llpreview.h"
@@ -1161,7 +1162,7 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32
const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id)) if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id))
{ {
mask |= LLInventoryObeserver::LABEL; mask |= LLInventoryObserver::LABEL;
} }
old_cat->copyViewerCategory(cat); old_cat->copyViewerCategory(cat);
addChangedMask(mask, cat->getUUID()); addChangedMask(mask, cat->getUUID());
@@ -2093,13 +2094,18 @@ bool LLInventoryModel::loadSkeleton(
{ {
continue; continue;
} }
if (cat->getVersion() != tcat->getVersion()) else if (cat->getVersion() != tcat->getVersion())
{ {
// if the cached version does not match the server version, // if the cached version does not match the server version,
// throw away the version we have so we can fetch the // throw away the version we have so we can fetch the
// correct contents the next time the viewer opens the folder. // correct contents the next time the viewer opens the folder.
tcat->setVersion(NO_VERSION); tcat->setVersion(NO_VERSION);
} }
else if (tcat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)
{
// Do not trust stock folders being updated
tcat->setVersion(NO_VERSION);
}
else else
{ {
cached_ids.insert(tcat->getUUID()); cached_ids.insert(tcat->getUUID());
@@ -3090,7 +3096,18 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' ("
<< tfolder->getUUID() << ") in " << tfolder->getParentUUID() << tfolder->getUUID() << ") in " << tfolder->getParentUUID()
<< LL_ENDL; << LL_ENDL;
if(tfolder->getUUID().notNull())
// If the folder is a listing or a version folder, all we need to do is update the SLM data
int depth_folder = depth_nesting_in_marketplace(tfolder->getUUID());
if ((depth_folder == 1) || (depth_folder == 2))
{
// Trigger an SLM listing update
LLUUID listing_uuid = (depth_folder == 1 ? tfolder->getUUID() : tfolder->getParentUUID());
S32 listing_id = LLMarketplaceData::instance().getListingID(listing_uuid);
LLMarketplaceData::instance().getListing(listing_id);
// In that case, there is no item to update so no callback -> we skip the rest of the update
}
else if(tfolder->getUUID().notNull())
{ {
folders.push_back(tfolder); folders.push_back(tfolder);
LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());

View File

@@ -37,6 +37,7 @@
#include "llfolderview.h" #include "llfolderview.h"
#include "llimview.h" #include "llimview.h"
#include "llinventorybridge.h" #include "llinventorybridge.h"
#include "llinventoryfilter.h"
#include "llinventoryfunctions.h" #include "llinventoryfunctions.h"
#include "llinventorymodelbackgroundfetch.h" #include "llinventorymodelbackgroundfetch.h"
#include "llviewerfoldertype.h" #include "llviewerfoldertype.h"
@@ -80,12 +81,6 @@ protected:
LLInventoryPanel* mIP; LLInventoryPanel* mIP;
}; };
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInvPanelComplObserver // Class LLInvPanelComplObserver
// //
@@ -129,6 +124,10 @@ void LLInvPanelComplObserver::done()
mCallback(); mCallback();
} }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryPanel
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LLInventoryPanel::LLInventoryPanel(const std::string& name, LLInventoryPanel::LLInventoryPanel(const std::string& name,
const std::string& sort_order_setting, const std::string& sort_order_setting,
const std::string& start_folder, const std::string& start_folder,
@@ -142,6 +141,10 @@ LLInventoryPanel::LLInventoryPanel(const std::string& name,
mScroller(NULL), mScroller(NULL),
mSortOrderSetting(sort_order_setting), mSortOrderSetting(sort_order_setting),
mStartFolder(start_folder), mStartFolder(start_folder),
mShowRootFolder(false),
mAllowDropOnRoot(true),
mAllowOpen(true),
mUseMarketplaceFolders(false),
mInventory(inventory), mInventory(inventory),
mAllowMultiSelect(allow_multi_select), mAllowMultiSelect(allow_multi_select),
mViewsInitialized(false), mViewsInitialized(false),
@@ -183,7 +186,7 @@ void LLInventoryPanel::buildFolderView()
} }
LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY, LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY,
LLAssetType::AT_CATEGORY, (mUseMarketplaceFolders/*mParams.use_marketplace_folders*/ ? LLAssetType::AT_MARKETPLACE_FOLDER : LLAssetType::AT_CATEGORY),
LLInventoryType::IT_CATEGORY, LLInventoryType::IT_CATEGORY,
this, this,
NULL, NULL,
@@ -191,6 +194,8 @@ void LLInventoryPanel::buildFolderView()
LLFolderView* folder_view = createFolderView(new_listener, true/*params.use_label_suffix()*/); LLFolderView* folder_view = createFolderView(new_listener, true/*params.use_label_suffix()*/);
mFolderRoot = folder_view->getHandle(); mFolderRoot = folder_view->getHandle();
addItemID(root_id, mFolderRoot.get());
} }
BOOL LLInventoryPanel::postBuild() BOOL LLInventoryPanel::postBuild()
{ {
@@ -223,6 +228,7 @@ BOOL LLInventoryPanel::postBuild()
{ {
initializeViews(); initializeViews();
} }
gIdleCallbacks.addFunction(onIdle, (void*)this); gIdleCallbacks.addFunction(onIdle, (void*)this);
if (mSortOrderSetting != INHERIT_SORT_ORDER) if (mSortOrderSetting != INHERIT_SORT_ORDER)
@@ -240,9 +246,8 @@ BOOL LLInventoryPanel::postBuild()
//getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); // Singu Nope! //getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); // Singu Nope!
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX)); getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX));
} }
// hide marketplace listing box, unless we want to show it (note: hacky as show_root_folder is only used for marketplace...) // hide marketplace listing box, unless we are a marketplace panel
// Singu Note: Even more hacky! String compare for merchant StartFolder to create the same effect /*&& !mParams.show_root_folder*/ if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mUseMarketplaceFolders/*mParams.use_marketplace_folders*/)
if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && mStartFolder != "merchant")
{ {
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS)); getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
} }
@@ -250,7 +255,7 @@ BOOL LLInventoryPanel::postBuild()
// set the filter for the empty folder if the debug setting is on // set the filter for the empty folder if the debug setting is on
if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders")) if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
{ {
getFilter()->setFilterEmptySystemFolders(); getFilter().setFilterEmptySystemFolders();
} }
return LLPanel::postBuild(); return LLPanel::postBuild();
@@ -260,7 +265,7 @@ LLInventoryPanel::~LLInventoryPanel()
{ {
if (mFolderRoot.get()) if (mFolderRoot.get())
{ {
U32 sort_order = mFolderRoot.get()->getSortOrder(); U32 sort_order = mFolderRoot.get().getSortOrder();
if (mSortOrderSetting != INHERIT_SORT_ORDER) if (mSortOrderSetting != INHERIT_SORT_ORDER)
{ {
gSavedSettings.setU32(mSortOrderSetting, sort_order); gSavedSettings.setU32(mSortOrderSetting, sort_order);
@@ -353,6 +358,12 @@ LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
rect, &gInventory, rect, &gInventory,
allow_multi_select, parent); allow_multi_select, parent);
// Singu TODO: Turn these into mParams like upstream.
node->getAttribute_bool("show_root_folder", panel->mShowRootFolder);
node->getAttribute_bool("allow_drop_on_root", panel->mAllowDropOnRoot);
node->getAttribute_bool("allow_open", panel->mAllowOpen);
node->getAttribute_bool("use_marketplace_folders", panel->mUseMarketplaceFolders);
panel->initFromXML(node, parent); panel->initFromXML(node, parent);
panel->postBuild(); panel->postBuild();
@@ -364,33 +375,26 @@ void LLInventoryPanel::draw()
{ {
// Select the desired item (in case it wasn't loaded when the selection was requested) // Select the desired item (in case it wasn't loaded when the selection was requested)
mFolderRoot.get()->updateSelection(); mFolderRoot.get()->updateSelection();
LLPanel::draw(); LLPanel::draw();
} }
LLInventoryFilter* LLInventoryPanel::getFilter() LLInventoryFilter& LLInventoryPanel::getFilter()
{ {
if (mFolderRoot.get()) return *mFolderRoot.get()->getFilter();
{
return mFolderRoot.get()->getFilter();
}
return NULL;
} }
const LLInventoryFilter* LLInventoryPanel::getFilter() const const LLInventoryFilter& LLInventoryPanel::getFilter() const
{ {
if (mFolderRoot.get()) return *mFolderRoot.get()->getFilter();
{
return mFolderRoot.get()->getFilter();
}
return NULL;
} }
void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type) void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type)
{ {
if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT) if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT)
getFilter()->setFilterObjectTypes(types); getFilter().setFilterObjectTypes(types);
if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY) if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY)
getFilter()->setFilterCategoryTypes(types); getFilter().setFilterCategoryTypes(types);
} }
U32 LLInventoryPanel::getFilterObjectTypes() const U32 LLInventoryPanel::getFilterObjectTypes() const
@@ -406,17 +410,17 @@ U32 LLInventoryPanel::getFilterPermMask() const
void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
{ {
getFilter()->setFilterPermissions(filter_perm_mask); getFilter().setFilterPermissions(filter_perm_mask);
} }
void LLInventoryPanel::setFilterWearableTypes(U64 types) void LLInventoryPanel::setFilterWearableTypes(U64 types)
{ {
getFilter()->setFilterWearableTypes(types); getFilter().setFilterWearableTypes(types);
} }
void LLInventoryPanel::setFilterWorn(bool worn) void LLInventoryPanel::setFilterWorn(bool worn)
{ {
getFilter()->setFilterWorn(worn); getFilter().setFilterWorn(worn);
} }
void LLInventoryPanel::setFilterSubString(const std::string& string) void LLInventoryPanel::setFilterSubString(const std::string& string)
@@ -451,7 +455,7 @@ void LLInventoryPanel::setFilterSubString(const std::string& string)
getRootFolder()->saveFolderState(); getRootFolder()->saveFolderState();
} }
// set new filter string // set new filter string
getFilter()->setFilterSubString(string); getFilter().setFilterSubString(string);
} }
} }
@@ -462,8 +466,8 @@ const std::string LLInventoryPanel::getFilterSubString()
void LLInventoryPanel::setSortOrder(U32 order) void LLInventoryPanel::setSortOrder(U32 order)
{ {
getFilter()->setSortOrder(order); getFilter().setSortOrder(order);
if (getFilter()->isModified()) if (getFilter().isModified())
{ {
mFolderRoot.get()->setSortOrder(order); mFolderRoot.get()->setSortOrder(order);
// try to keep selection onscreen, even if it wasn't to start with // try to keep selection onscreen, even if it wasn't to start with
@@ -483,27 +487,27 @@ void LLInventoryPanel::requestSort()
void LLInventoryPanel::setSinceLogoff(BOOL sl) void LLInventoryPanel::setSinceLogoff(BOOL sl)
{ {
getFilter()->setDateRangeLastLogoff(sl); getFilter().setDateRangeLastLogoff(sl);
} }
void LLInventoryPanel::setHoursAgo(U32 hours) void LLInventoryPanel::setHoursAgo(U32 hours)
{ {
getFilter()->setHoursAgo(hours); getFilter().setHoursAgo(hours);
} }
void LLInventoryPanel::setFilterLinks(U64 filter_links) void LLInventoryPanel::setFilterLinks(U64 filter_links)
{ {
getFilter()->setFilterLinks(filter_links); getFilter().setFilterLinks(filter_links);
} }
void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
{ {
getFilter()->setShowFolderState(show); getFilter().setShowFolderState(show);
} }
LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
{ {
return getFilter()->getShowFolderState(); return getFilter().getShowFolderState();
} }
void LLInventoryPanel::modelChanged(U32 mask) void LLInventoryPanel::modelChanged(U32 mask)
@@ -569,7 +573,9 @@ void LLInventoryPanel::modelChanged(U32 mask)
{ {
if (model_item && view_item) if (model_item && view_item)
{ {
const LLUUID& idp = view_item->getListener()->getUUID();
view_item->destroyView(); view_item->destroyView();
removeItemID(idp);
} }
view_item = buildNewViews(item_id); view_item = buildNewViews(item_id);
view_folder = dynamic_cast<LLFolderViewFolder *>(view_item); view_folder = dynamic_cast<LLFolderViewFolder *>(view_item);
@@ -637,6 +643,7 @@ void LLInventoryPanel::modelChanged(U32 mask)
// Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI.
view_item->getParentFolder()->extractItem(view_item); view_item->getParentFolder()->extractItem(view_item);
view_item->addToFolder(new_parent, mFolderRoot.get()); view_item->addToFolder(new_parent, mFolderRoot.get());
addItemID(view_item->getListener()->getUUID(), view_item);
if (mInventory) if (mInventory)
{ {
const LLUUID trash_id = mInventory->findCategoryUUIDForType(LLFolderType::FT_TRASH); const LLUUID trash_id = mInventory->findCategoryUUIDForType(LLFolderType::FT_TRASH);
@@ -648,6 +655,10 @@ void LLInventoryPanel::modelChanged(U32 mask)
} }
else else
{ {
// Remove the item ID before destroying the view because the view-model-item gets
// destroyed when the view is destroyed
removeItemID(view_item->getListener()->getUUID());
// Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that
// doesn't include trash). Just remove the item's UI. // doesn't include trash). Just remove the item's UI.
view_item->destroyView(); view_item->destroyView();
@@ -662,12 +673,33 @@ void LLInventoryPanel::modelChanged(U32 mask)
else if (!model_item && view_item) else if (!model_item && view_item)
{ {
// Remove the item's UI. // Remove the item's UI.
LLFolderViewFolder* parent = view_item->getParentFolder();
removeItemID(view_item->getListener()->getUUID());
view_item->destroyView(); view_item->destroyView();
} }
} }
} }
} }
const LLUUID LLInventoryPanel::getRootFolderID() const
{
LLUUID root_id;
if (mFolderRoot.get() && mFolderRoot.get()->getListener())
{
root_id = mFolderRoot.get()->getListener()->getUUID();
}
else
{
root_id = getStartFolder(mStartFolder);
if (root_id.isNull())
{
LL_WARNS() << "Could not find folder of type " << mStartFolder << LL_ENDL;
root_id.generateNewID();
}
}
return root_id;
}
// static // static
void LLInventoryPanel::onIdle(void *userdata) void LLInventoryPanel::onIdle(void *userdata)
{ {
@@ -686,24 +718,7 @@ void LLInventoryPanel::onIdle(void *userdata)
} }
} }
const LLUUID& LLInventoryPanel::getRootFolderID() const
{
LLUUID root_id;
if (mFolderRoot.get() && mFolderRoot.get()->getListener())
{
root_id = mFolderRoot.get()->getListener()->getUUID();
}
else
{
root_id = getStartFolder(mStartFolder);
if (root_id.isNull())
{
llwarns << "Could not find folder of type " << preferred_type << LL_ENDL;
root_id.generateNewID();
}
}
return root_id;
}
void LLInventoryPanel::initializeViews() void LLInventoryPanel::initializeViews()
{ {
@@ -799,28 +814,22 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
const LLUUID& parent_id = objectp->getParentUUID(); const LLUUID& parent_id = objectp->getParentUUID();
LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolderRoot.get()->getItemByID(parent_id); LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolderRoot.get()->getItemByID(parent_id);
LLUUID root_id = getRootFolderID();
// Force the creation of an extra root level folder item if required by the inventory panel (default is "false") // Force the creation of an extra root level folder item if required by the inventory panel (default is "false")
bool allow_drop = true; bool allow_drop = true;
bool allow_wear = true; // Singu TODO: Remove this when we have params here.
bool create_root = false; bool create_root = false;
if (mStartFolder == "merchant") // Singu Note: Only done for "merchant" if (mShowRootFolder)
{ {
LLUUID root_id = getRootFolderID();
if (root_id == id) if (root_id == id)
{ {
// We insert an extra level that's seen by the UI but has no influence on the model // We insert an extra level that's seen by the UI but has no influence on the model
parent_folder = dynamic_cast<LLFolderViewFolder*>(folder_view_item); parent_folder = dynamic_cast<LLFolderViewFolder*>(folder_view_item);
folder_view_item = NULL; folder_view_item = NULL;
allow_drop = false; // merchant floaters upstream say false in xui allow_drop = mAllowDropOnRoot;
allow_wear = false; // merchant floaters upstream say false in xui
create_root = true; create_root = true;
} }
} }
else if (mStartFolder == "outbox")
{
allow_wear = false; // outbox floater upstream says false in xui
}
if (!folder_view_item && parent_folder) if (!folder_view_item && parent_folder)
{ {
@@ -844,12 +853,20 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
objectp->getUUID()); objectp->getUUID());
if (new_listener) if (new_listener)
{ {
// Singu Note: new_listener disappeared in the last merge, be sure that adding it back here doesn't break anything. ~Liru
LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(),
objectp->getType(),
LLInventoryType::IT_CATEGORY,
this,
mFolderRoot.get(),
objectp->getUUID());
LLFolderViewFolder* folderp = createFolderViewFolder(new_listener); LLFolderViewFolder* folderp = createFolderViewFolder(new_listener);
if (folderp) if (folderp)
{ {
folderp->setItemSortOrder(mFolderRoot.get()->getSortOrder()); folderp->setItemSortOrder(mFolderRoot.get()->getSortOrder());
folderp->setAllowDrop(allow_drop); folderp->setAllowDrop(allow_drop);
folderp->setAllowWear(allow_wear); folderp->setAllowOpen(mAllowOpen);
} }
folder_view_item = folderp; folder_view_item = folderp;
} }
@@ -876,6 +893,7 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
{ {
llassert(parent_folder != NULL); llassert(parent_folder != NULL);
folder_view_item->addToFolder(parent_folder, mFolderRoot.get()); folder_view_item->addToFolder(parent_folder, mFolderRoot.get());
addItemID(id, folder_view_item);
// In the case of the root folder been shown, open that folder by default once the widget is created // In the case of the root folder been shown, open that folder by default once the widget is created
if (create_root) if (create_root)
{ {
@@ -938,24 +956,6 @@ void LLInventoryPanel::openStartFolderOrMyInventory()
} }
} }
struct LLConfirmPurgeData
{
LLUUID mID;
LLInventoryModel* mModel;
};
class LLIsNotWorn : public LLInventoryCollectFunctor
{
public:
LLIsNotWorn() {}
virtual ~LLIsNotWorn() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
return !gAgentWearables.isWearingItem(item->getUUID());
}
};
class LLOpenFolderByID : public LLFolderViewFunctor class LLOpenFolderByID : public LLFolderViewFunctor
{ {
public: public:
@@ -1023,7 +1023,7 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
// If folder view is empty the (x, y) point won't be in its rect // If folder view is empty the (x, y) point won't be in its rect
// so the handler must be called explicitly. // so the handler must be called explicitly.
// but only if was not handled before. See EXT-6746. // but only if was not handled before. See EXT-6746.
if (!handled && /*mParams.allow_drop_on_root*/mStartFolder != "merchant" && !mFolderRoot.get()->hasVisibleChildren()) if (!handled && /*mParams.allow_drop_on_root*/mAllowDropOnRoot && !mFolderRoot.get()->hasVisibleChildren())
{ {
handled = mFolderRoot.get()->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); handled = mFolderRoot.get()->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
} }
@@ -1097,6 +1097,7 @@ void LLInventoryPanel::setSelectCallback(const boost::function<void (const std::
void LLInventoryPanel::clearSelection() void LLInventoryPanel::clearSelection()
{ {
mFolderRoot.get()->clearSelection(); mFolderRoot.get()->clearSelection();
mSelectThisID.setNull();
} }
void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action) void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action)
@@ -1155,7 +1156,7 @@ void LLInventoryPanel::createNewItem(const std::string& name,
BOOL LLInventoryPanel::getSinceLogoff() BOOL LLInventoryPanel::getSinceLogoff()
{ {
return getFilter()->isSinceLogoff(); return getFilter().isSinceLogoff();
} }
// DEBUG ONLY // DEBUG ONLY
@@ -1190,18 +1191,170 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
res = floater_inventory->getActivePanel(); res = floater_inventory->getActivePanel();
} }
return res; return res;
} }
void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type) void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
{ {
getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << folder_type)); getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type));
} }
BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const
{ {
return !(getFilter()->getFilterCategoryTypes() & (1ULL << folder_type)); return !(getFilter().getFilterCategoryTypes() & (1ULL << folder_type));
} }
void LLInventoryPanel::addItemID( const LLUUID& id, LLFolderViewItem* itemp )
{
mItemMap[id] = itemp;
}
void LLInventoryPanel::removeItemID(const LLUUID& id)
{
LLInventoryModel::cat_array_t categories;
LLInventoryModel::item_array_t items;
gInventory.collectDescendents(id, categories, items, TRUE);
mItemMap.erase(id);
for (LLInventoryModel::cat_array_t::iterator it = categories.begin(), end_it = categories.end();
it != end_it;
++it)
{
mItemMap.erase((*it)->getUUID());
}
for (LLInventoryModel::item_array_t::iterator it = items.begin(), end_it = items.end();
it != end_it;
++it)
{
mItemMap.erase((*it)->getUUID());
}
}
static LLFastTimer::DeclareTimer FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID");
LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id)
{
LLFastTimer mew(FTM_GET_ITEM_BY_ID);
std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
map_it = mItemMap.find(id);
if (map_it != mItemMap.end())
{
return map_it->second;
}
return NULL;
}
LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id)
{
LLFolderViewItem* item = getItemByID(id);
return dynamic_cast<LLFolderViewFolder*>(item);
}
void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL take_keyboard_focus )
{
LLFolderViewItem* itemp = getItemByID(obj_id);
if(itemp && itemp->getListener())
{
itemp->arrangeAndSet(TRUE, take_keyboard_focus);
mSelectThisID.setNull();
return;
}
else
{
// save the desired item to be selected later (if/when ready)
mSelectThisID = obj_id;
}
}
void LLInventoryPanel::updateSelection()
{
if (mSelectThisID.notNull())
{
setSelectionByID(mSelectThisID, false);
}
}
namespace LLInventoryAction
{
bool doToSelected(LLFolderView* root, std::string action);
}
void LLInventoryPanel::doToSelected(const LLSD& userdata)
{
LLInventoryAction::doToSelected(mFolderRoot.get(), userdata.asString());
return;
}
BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask )
{
BOOL handled = FALSE;
switch (key)
{
case KEY_RETURN:
// Open selected items if enter key hit on the inventory panel
if (mask == MASK_NONE)
{
//Don't allow attaching or opening items from Merchant Outbox
LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
if(folder_item)
{
LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener();
if(bridge && bridge->isOutboxFolder() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY))
{
return handled;
}
}
LLInventoryAction::doToSelected(mFolderRoot.get(), "open");
handled = TRUE;
}
break;
case KEY_DELETE:
case KEY_BACKSPACE:
// Delete selected items if delete or backspace key hit on the inventory panel
// Note: on Mac laptop keyboards, backspace and delete are one and the same
if (isSelectionRemovable() && (mask == MASK_NONE))
{
LLInventoryAction::doToSelected(mFolderRoot.get(), "delete");
handled = TRUE;
}
break;
}
return handled;
}
bool LLInventoryPanel::isSelectionRemovable()
{
bool can_delete = false;
if (mFolderRoot.get())
{
std::set<LLUUID> selection_set = mFolderRoot.get()->getSelectionList();
if (!selection_set.empty())
{
can_delete = true;
for (std::set<LLUUID>::iterator iter = selection_set.begin();
iter != selection_set.end();
++iter)
{
LLFolderViewItem *item = getItemByID(*iter);
const LLFolderViewEventListener* listener =item->getListener();
if (!listener)
{
can_delete = false;
}
else
{
can_delete &= listener->isItemRemovable() && !listener->isItemInTrash();
}
}
}
}
return can_delete;
}
/************************************************************************/ /************************************************************************/
/* Recent Inventory Panel related class */ /* Recent Inventory Panel related class */
@@ -1219,6 +1372,7 @@ LLInventoryRecentItemsPanel:: LLInventoryRecentItemsPanel(const std::string& nam
LLView *parent_view) : LLView *parent_view) :
LLInventoryPanel(name, sort_order_setting, start_folder,rect,inventory,allow_multi_select,parent_view) LLInventoryPanel(name, sort_order_setting, start_folder,rect,inventory,allow_multi_select,parent_view)
{ {
// replace bridge builder to have necessary View bridges.
mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER; mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
} }

View File

@@ -1,6 +1,6 @@
/** /**
* @file llpanelmaininventory.h * @file llinventorypanel.h
* @brief LLPanelMainInventory, LLInventoryFolder, and LLInventoryItem * @brief LLInventoryPanel
* class definition * class definition
* *
* $LicenseInfo:firstyear=2001&license=viewergpl$ * $LicenseInfo:firstyear=2001&license=viewergpl$
@@ -87,6 +87,7 @@ public:
// LLView methods // LLView methods
void draw(); void draw();
/*virtual*/ BOOL handleKeyHere( KEY key, MASK mask );
BOOL handleHover(S32 x, S32 y, MASK mask); BOOL handleHover(S32 x, S32 y, MASK mask);
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type, EDragAndDropType cargo_type,
@@ -104,8 +105,9 @@ public:
void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus);
void setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb); void setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb);
void clearSelection(); void clearSelection();
LLInventoryFilter* getFilter(); bool isSelectionRemovable();
const LLInventoryFilter* getFilter() const; LLInventoryFilter& getFilter();
const LLInventoryFilter& getFilter() const;
void setFilterTypes(U64 filter, LLInventoryFilter::EFilterType = LLInventoryFilter::FILTERTYPE_OBJECT); void setFilterTypes(U64 filter, LLInventoryFilter::EFilterType = LLInventoryFilter::FILTERTYPE_OBJECT);
U32 getFilterObjectTypes() const; U32 getFilterObjectTypes() const;
void setFilterPermMask(PermissionMask filter_perm_mask); void setFilterPermMask(PermissionMask filter_perm_mask);
@@ -115,7 +117,7 @@ public:
const std::string getFilterSubString(); const std::string getFilterSubString();
void setFilterWorn(bool worn); void setFilterWorn(bool worn);
bool getFilterWorn() const { return mFolderRoot.get()->getFilterWorn(); } bool getFilterWorn() const { return mFolderRoot.get()->getFilterWorn(); }
void setSinceLogoff(BOOL sl); void setSinceLogoff(BOOL sl);
void setHoursAgo(U32 hours); void setHoursAgo(U32 hours);
BOOL getSinceLogoff(); BOOL getSinceLogoff();
@@ -128,11 +130,14 @@ public:
void modelChanged(U32 mask); void modelChanged(U32 mask);
LLFolderView* getRootFolder() { return mFolderRoot.get(); } LLFolderView* getRootFolder() { return mFolderRoot.get(); }
LLScrollContainer* getScrollableContainer() { return mScroller; } LLScrollContainer* getScrollableContainer() { return mScroller; }
bool getAllowDropOnRoot() const { return mStartFolder != "merchant"; } bool getAllowDropOnRoot() const { return mAllowDropOnRoot; }
void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action); void onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
LLHandle<LLInventoryPanel> getInventoryPanelHandle() const { return getDerivedHandle<LLInventoryPanel>(); } LLHandle<LLInventoryPanel> getInventoryPanelHandle() const { return getDerivedHandle<LLInventoryPanel>(); }
// Callbacks
void doToSelected(const LLSD& userdata);
// DEBUG ONLY: // DEBUG ONLY:
static void dumpSelectionInformation(void* user_data); static void dumpSelectionInformation(void* user_data);
@@ -156,6 +161,13 @@ public:
LLInventoryType::EType inv_type, LLInventoryType::EType inv_type,
U32 next_owner_perm = 0); U32 next_owner_perm = 0);
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
void removeItemID(const LLUUID& id);
LLFolderViewItem* getItemByID(const LLUUID& id);
LLFolderViewFolder* getFolderByID(const LLUUID& id);
void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus);
void updateSelection();
// Clean up stuff when the folder root gets deleted // Clean up stuff when the folder root gets deleted
void clearFolderRoot(); void clearFolderRoot();
@@ -163,15 +175,17 @@ protected:
void openStartFolderOrMyInventory(); // open the first level of inventory void openStartFolderOrMyInventory(); // open the first level of inventory
void onItemsCompletion(); // called when selected items are complete void onItemsCompletion(); // called when selected items are complete
LLUUID mSelectThisID;
LLInventoryModel* mInventory; LLInventoryModel* mInventory;
LLInventoryObserver* mInventoryObserver; LLInventoryObserver* mInventoryObserver;
LLInvPanelComplObserver* mCompletionObserver; LLInvPanelComplObserver* mCompletionObserver;
bool mAllowMultiSelect;
BOOL mAllowMultiSelect;
LLHandle<LLFolderView> mFolderRoot; LLHandle<LLFolderView> mFolderRoot;
LLScrollContainer* mScroller; LLScrollContainer* mScroller;
LLPointer<LLFolderViewGroupedItemBridge> mGroupedItemBridge; LLPointer<LLFolderViewGroupedItemBridge> mGroupedItemBridge;
std::map<LLUUID, LLFolderViewItem*> mItemMap;
/** /**
* Pointer to LLInventoryFolderViewModelBuilder. * Pointer to LLInventoryFolderViewModelBuilder.
* *
@@ -197,6 +211,10 @@ public:
private: private:
const std::string mStartFolder; const std::string mStartFolder;
bool mShowRootFolder;
bool mAllowDropOnRoot;
bool mAllowOpen;
bool mUseMarketplaceFolders;
const std::string mSortOrderSetting; const std::string mSortOrderSetting;
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@@ -207,7 +225,7 @@ public:
public: public:
BOOL getIsViewsInitialized() const { return mViewsInitialized; } BOOL getIsViewsInitialized() const { return mViewsInitialized; }
const LLUUID& getRootFolderID() const; const LLUUID getRootFolderID() const;
protected: protected:
// Builds the UI. Call this once the inventory is usable. // Builds the UI. Call this once the inventory is usable.
void initializeViews(); void initializeViews();
@@ -225,9 +243,6 @@ protected:
class LLPanelMainInventory; class LLPanelMainInventory;
///---------------------------------------------------------------------------- ///----------------------------------------------------------------------------
/// Function declarations, constants, enums, and typedefs /// Function declarations, constants, enums, and typedefs
///---------------------------------------------------------------------------- ///----------------------------------------------------------------------------
@@ -250,6 +265,3 @@ const BOOL TAKE_FOCUS_YES = TRUE;
const BOOL TAKE_FOCUS_NO = FALSE; const BOOL TAKE_FOCUS_NO = FALSE;
#endif // LL_LLINVENTORYPANEL_H #endif // LL_LLINVENTORYPANEL_H

View File

@@ -43,8 +43,8 @@
#include "llviewerregion.h" #include "llviewerregion.h"
#include "hippogridmanager.h" #include "hippogridmanager.h"
#include "reader.h" // JSON #include "json/reader.h" // JSON
#include "writer.h" // JSON #include "json/writer.h" // JSON
// //
// Helpers // Helpers
@@ -129,17 +129,43 @@ LLSD getMarketplaceStringSubstitutions()
return marketplace_sub_map; return marketplace_sub_map;
} }
// Get the version folder: if there is only one subfolder, we will use it as a version folder
LLUUID getVersionFolderIfUnique(const LLUUID& folder_id)
{
LLUUID version_id = LLUUID::null;
LLInventoryModel::cat_array_t* categories;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(folder_id, categories, items);
if (categories->size() == 1)
{
version_id = categories->begin()->get()->getUUID();
}
else
{
LLNotificationsUtil::add("AlertMerchantListingActivateRequired");
}
return version_id;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// SLM Responders // SLM Responders
void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string description) void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
{ {
LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << description << LL_ENDL; LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << description << LL_ENDL;
// Prompt the user with the warning (so they know why things are failing) if ((status == 422) && (description == "[\"You must have an English description to list the product\", \"You must choose a category for your product before it can be listed\", \"Listing could not change state.\", \"Price can't be blank\"]"))
LLSD subs; {
subs["[ERROR_REASON]"] = reason; // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing
// We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though. LLNotificationsUtil::add("MerchantUnprocessableEntity");
subs["[ERROR_DESCRIPTION]"] = (description.length() <= 512 ? description : ""); }
LLNotificationsUtil::add("MerchantTransactionFailed", subs); else
{
// Prompt the user with the warning (so they know why things are failing)
LLSD subs;
subs["[ERROR_REASON]"] = reason;
// We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though.
subs["[ERROR_DESCRIPTION]"] = (description.length() <= 512 ? description : "");
LLNotificationsUtil::add("MerchantTransactionFailed", subs);
}
} }
void log_SLM_infos(const std::string& request, U32 status, const std::string& body) void log_SLM_infos(const std::string& request, U32 status, const std::string& body)
{ {
@@ -148,10 +174,13 @@ void log_SLM_infos(const std::string& request, U32 status, const std::string& bo
LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL; LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL;
} }
} }
void log_SLM_infos(const std::string& request, const std::string& url, const std::string& body)
// Merov: This is a temporary hack used by dev while secondlife-staging is down... {
// *TODO : Suppress that before shipping! if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
static bool sBypassMerchant = false; {
LL_INFOS("SLM") << "SLM API : Sending " << request << ". url : " << url << ", body : " << body << LL_ENDL;
}
}
class LLSLMGetMerchantResponder : public LLHTTPClient::ResponderWithResult class LLSLMGetMerchantResponder : public LLHTTPClient::ResponderWithResult
{ {
@@ -163,13 +192,7 @@ public:
protected: protected:
virtual void httpFailure() virtual void httpFailure()
{ {
if (sBypassMerchant) if (HTTP_NOT_FOUND == getStatus())
{
// *TODO : Suppress that before shipping!
log_SLM_infos("Get /merchant", getStatus(), "SLM Connection error bypassed (debug only)");
LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT);
}
else if (HTTP_NOT_FOUND == getStatus())
{ {
log_SLM_infos("Get /merchant", getStatus(), "User is not a merchant"); log_SLM_infos("Get /merchant", getStatus(), "User is not a merchant");
LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT); LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT);
@@ -213,11 +236,12 @@ public:
LLBufferStream istr(channels, buffer.get()); LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm; std::stringstream strstrm;
strstrm << istr.rdbuf(); strstrm << istr.rdbuf();
const std:string body = strstrm.str(); const std::string body = strstrm.str();
if (!isGoodStatus()) if (!isGoodStatus(mStatus))
{ {
log_SLM_warning("Get /listings", getStatus(), getReason(), "", body); log_SLM_warning("Get /listings", getStatus(), getReason(), "", body);
LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
gInventory.notifyObservers(); gInventory.notifyObservers();
return; return;
@@ -228,6 +252,7 @@ public:
if (!reader.parse(body, root)) if (!reader.parse(body, root))
{ {
log_SLM_warning("Get /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body); log_SLM_warning("Get /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
gInventory.notifyObservers(); gInventory.notifyObservers();
return; return;
@@ -253,17 +278,13 @@ public:
LLUUID version_id(version_uuid_string); LLUUID version_id(version_uuid_string);
if (folder_id.notNull()) if (folder_id.notNull())
{ {
LLMarketplaceData::instance().deleteListing(folder_id, false); LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
LLMarketplaceData::instance().addListing(folder_id, listing_id, version_id, is_listed, false);
LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false);
LLMarketplaceData::instance().setCountOnHand(folder_id, count, false);
update_marketplace_category(folder_id, false);
gInventory.notifyObservers();
} }
it++; it++;
} }
// Update all folders under the root // Update all folders under the root
LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE);
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
gInventory.notifyObservers(); gInventory.notifyObservers();
} }
@@ -280,7 +301,7 @@ public:
LLSLMCreateListingsResponder(const LLUUID& folder_id) LLSLMCreateListingsResponder(const LLUUID& folder_id)
{ {
mExpectedFolderId = folder_id mExpectedFolderId = folder_id;
} }
virtual void completedRaw(const LLChannelDescriptors& channels, virtual void completedRaw(const LLChannelDescriptors& channels,
@@ -291,9 +312,9 @@ public:
LLBufferStream istr(channels, buffer.get()); LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm; std::stringstream strstrm;
strstrm << istr.rdbuf(); strstrm << istr.rdbuf();
const std::String body = strstrm.str(); const std::string body = strstrm.str();
if (!isGoodStatus()) if (!isGoodStatus(mStatus))
{ {
log_SLM_warning("Post /listings", getStatus(), getReason(), "", body); log_SLM_warning("Post /listings", getStatus(), getReason(), "", body);
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
@@ -329,9 +350,7 @@ public:
LLUUID folder_id(folder_uuid_string); LLUUID folder_id(folder_uuid_string);
LLUUID version_id(version_uuid_string); LLUUID version_id(version_uuid_string);
LLMarketplaceData::instance().addListing(folder_id, listing_id, version_id, is_listed, false); LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false);
LLMarketplaceData::instance().setCountOnHand(folder_id, count, false);
update_marketplace_category(folder_id, false); update_marketplace_category(folder_id, false);
gInventory.notifyObservers(); gInventory.notifyObservers();
it++; it++;
@@ -361,11 +380,19 @@ public:
LLBufferStream istr(channels, buffer.get()); LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm; std::stringstream strstrm;
strstrm << istr.rdbuf(); strstrm << istr.rdbuf();
const std:string body = strstrm.str(); const std::string body = strstrm.str();
if (!isGoodStatus()) if (!isGoodStatus(mStatus))
{ {
log_SLM_warning("Get /listing", getStatus(), getReason(), "", body); if (getStatus() == 404)
{
// That listing does not exist -> delete its record from the local SLM data store
LLMarketplaceData::instance().deleteListing(mExpectedFolderId, false);
}
else
{
log_SLM_warning("Get /listing", getStatus(), getReason(), "", body);
}
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
gInventory.notifyObservers(); gInventory.notifyObservers();
return; return;
@@ -438,9 +465,9 @@ public:
LLBufferStream istr(channels, buffer.get()); LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm; std::stringstream strstrm;
strstrm << istr.rdbuf(); strstrm << istr.rdbuf();
const std:string body = strstrm.str(); const std::string body = strstrm.str();
if (!isGoodStatus()) if (!isGoodStatus(mStatus))
{ {
log_SLM_warning("Put /listing", getStatus(), getReason(), "", body); log_SLM_warning("Put /listing", getStatus(), getReason(), "", body);
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
@@ -526,9 +553,9 @@ public:
LLBufferStream istr(channels, buffer.get()); LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm; std::stringstream strstrm;
strstrm << istr.rdbuf(); strstrm << istr.rdbuf();
const std:string body = strstrm.str(); const std::string body = strstrm.str();
if (!isGoodStatus()) if (!isGoodStatus(mStatus))
{ {
log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), "", body); log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), "", body);
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
@@ -576,14 +603,13 @@ public:
} }
// Add the new association // Add the new association
LLMarketplaceData::instance().addListing(folder_id, listing_id, version_id, is_listed, false); LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false);
LLMarketplaceData::instance().setCountOnHand(folder_id, count, false);
update_marketplace_category(folder_id, false); update_marketplace_category(folder_id, false);
gInventory.notifyObservers(); gInventory.notifyObservers();
// Alert with DAMA informing the user that a version folder must be designated // the stock count needs to be updated with the new local count now
LLNotificationsUtil::add("AlertMerchantAssociateNeedsVersion"); LLMarketplaceData::instance().updateCountOnHand(folder_id,1);
it++; it++;
} }
@@ -615,9 +641,9 @@ public:
LLBufferStream istr(channels, buffer.get()); LLBufferStream istr(channels, buffer.get());
std::stringstream strstrm; std::stringstream strstrm;
strstrm << istr.rdbuf(); strstrm << istr.rdbuf();
const std:string body = strstrm.str(); const std::string body = strstrm.str();
if (!isGoodStatus()) if (!isGoodStatus(mStatus))
{ {
log_SLM_warning("Delete /listing", getStatus(), getReason(), "", body); log_SLM_warning("Delete /listing", getStatus(), getReason(), "", body);
update_marketplace_category(mExpectedFolderId, false); update_marketplace_category(mExpectedFolderId, false);
@@ -1110,13 +1136,43 @@ public:
void LLMarketplaceInventoryObserver::changed(U32 mask) void LLMarketplaceInventoryObserver::changed(U32 mask)
{ {
// When things are added to the marketplace, we might need to re-validate and fix the containing listings
if (mask & LLInventoryObserver::ADD)
{
const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
std::set<LLUUID>::const_iterator id_it = changed_items.begin();
std::set<LLUUID>::const_iterator id_end = changed_items.end();
// First, count the number of items in this list...
S32 count = 0;
for (;id_it != id_end; ++id_it)
{
LLInventoryObject* obj = gInventory.getObject(*id_it);
if (obj && (LLAssetType::AT_CATEGORY != obj->getType()))
{
count++;
}
}
// Then, decrement the folders of that amount
// Note that of all of those, only one folder will be a listing folder (if at all).
// The other will be ignored by the decrement method.
id_it = changed_items.begin();
for (;id_it != id_end; ++id_it)
{
LLInventoryObject* obj = gInventory.getObject(*id_it);
if (obj && (LLAssetType::AT_CATEGORY == obj->getType()))
{
LLMarketplaceData::instance().decrementValidationWaiting(obj->getUUID(),count);
}
}
}
// When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder: // When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder:
// * stock counts changing : no copy items coming in and out will change the stock count on folders // * stock counts changing : no copy items coming in and out will change the stock count on folders
// * version and listing folders : moving those might invalidate the marketplace data itself // * version and listing folders : moving those might invalidate the marketplace data itself
// Since we should cannot raise inventory change while the observer is called (the list will be cleared // Since we should cannot raise inventory change while the observer is called (the list will be cleared
// once observers are called) we need to raise a flag in the inventory to signal that things have been dirtied. // once observers are called) we need to raise a flag in the inventory to signal that things have been dirtied.
// That's the only changes that really do make sense for marketplace to worry about
if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE))
{ {
const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
@@ -1184,7 +1240,9 @@ LLMarketplaceTuple::LLMarketplaceTuple(const LLUUID& folder_id, S32 listing_id,
// Data map // Data map
LLMarketplaceData::LLMarketplaceData() : LLMarketplaceData::LLMarketplaceData() :
mMarketPlaceStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED), mMarketPlaceStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED),
mMarketPlaceDataFetched(MarketplaceFetchCodes::MARKET_FETCH_NOT_DONE),
mStatusUpdatedSignal(NULL), mStatusUpdatedSignal(NULL),
mDataFetchedSignal(NULL),
mDirtyCount(false) mDirtyCount(false)
{ {
mInventoryObserver = new LLMarketplaceInventoryObserver; mInventoryObserver = new LLMarketplaceInventoryObserver;
@@ -1212,13 +1270,25 @@ void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type&
else else
{ {
// Initiate SLM connection and set responder // Initiate SLM connection and set responder
mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING;
std::string url = getSLMConnectURL("/merchant"); std::string url = getSLMConnectURL("/merchant");
log_SLM_infos("LLHTTPClient::get", url, ""); if (url != "")
LLHTTPClient::get(url, new LLSLMGetMerchantResponder(), LLSD()); {
mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING;
log_SLM_infos("LLHTTPClient::get", url, "");
LLHTTPClient::get(url, LLSD(), new LLSLMGetMerchantResponder());
}
} }
} }
void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot_type& cb)
{
if (mDataFetchedSignal == NULL)
{
mDataFetchedSignal = new status_updated_signal_t();
}
mDataFetchedSignal->connect(cb);
}
// Get/Post/Put requests to the SLM Server using the SLM API // Get/Post/Put requests to the SLM Server using the SLM API
void LLMarketplaceData::getSLMListings() void LLMarketplaceData::getSLMListings()
{ {
@@ -1248,19 +1318,21 @@ void LLMarketplaceData::getSLMListing(S32 listing_id)
LLHTTPClient::get(url, new LLSLMGetListingResponder(folder_id), headers); LLHTTPClient::get(url, new LLSLMGetListingResponder(folder_id), headers);
} }
void LLMarketplaceData::createSLMListing(const LLUUID& folder_id) void LLMarketplaceData::createSLMListing(const LLUUID& folder_id, const LLUUID& version_id, S32 count)
{ {
AIHTTPHeaders headers; AIHTTPHeaders headers;
headers.addHeader("Accept", "application/json"); headers.addHeader("Accept", "application/json");
headers.addHeader("Content-Type", "application/json"); headers.addHeader("Content-Type", "application/json");
LLViewerInventoryCategory* category = gInventory.getCategory(folder_id); // Build the json message
Json::Value root; Json::Value root;
Json::FastWriter writer; Json::FastWriter writer;
LLViewerInventoryCategory* category = gInventory.getCategory(folder_id);
root["listing"]["name"] = category->getName(); root["listing"]["name"] = category->getName();
root["listing"]["inventory_info"]["listing_folder_id"] = category->getUUID().asString(); root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
root["listing"]["inventory_info"]["count_on_hand"] = count;
std::string json_str = writer.write(root); std::string json_str = writer.write(root);
@@ -1285,11 +1357,18 @@ void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id
Json::Value root; Json::Value root;
Json::FastWriter writer; Json::FastWriter writer;
// Note : auto unlist if the count is 0 (out of stock)
if (is_listed && (count == 0))
{
is_listed = false;
LLNotificationsUtil::add("AlertMerchantStockFolderEmpty");
}
// Note : we're assuming that sending unchanged info won't break anything server side... // Note : we're assuming that sending unchanged info won't break anything server side...
root["listing"]["id"] = listing_id; root["listing"]["id"] = listing_id;
root["listing"]["is_listed"] = is_listed; root["listing"]["is_listed"] = is_listed;
root["listing"]["inventory_info"]["listing_folder_id"] = folder_id; root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
root["listing"]["inventory_info"]["version_folder_id"] = version_id; root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
root["listing"]["inventory_info"]["count_on_hand"] = count; root["listing"]["inventory_info"]["count_on_hand"] = count;
std::string json_str = writer.write(root); std::string json_str = writer.write(root);
@@ -1303,10 +1382,10 @@ void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id
std::string url = getSLMConnectURL("/listing/") + llformat("%d", listing_id); std::string url = getSLMConnectURL("/listing/") + llformat("%d", listing_id);
log_SLM_infos("LLHTTPClient::putRaw", url, json_str); log_SLM_infos("LLHTTPClient::putRaw", url, json_str);
setUpdating(folder_id, true); setUpdating(folder_id, true);
LLHTTPClient::putRaw(url, data, size, new LLSLMCreateListingsResponder(folder_id, is_listed, version_id), headers); LLHTTPClient::putRaw(url, data, size, new LLSLMUpdateListingsResponder(folder_id, is_listed, version_id), headers);
} }
void LLMarketplaceData::associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& source_folder_id) void LLMarketplaceData::associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, const LLUUID& source_folder_id)
{ {
AIHTTPHeaders headers; AIHTTPHeaders headers;
headers.addHeader("Accept", "application/json"); headers.addHeader("Accept", "application/json");
@@ -1317,10 +1396,8 @@ void LLMarketplaceData::associateSLMListing(const LLUUID& folder_id, S32 listing
// Note : we're assuming that sending unchanged info won't break anything server side... // Note : we're assuming that sending unchanged info won't break anything server side...
root["listing"]["id"] = listing_id; root["listing"]["id"] = listing_id;
root["listing"]["is_listed"] = false;
root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString(); root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
root["listing"]["inventory_info"]["version_folder_id"] = LLUUID::null.asString(); root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
root["listing"]["inventory_info"]["count_on_hand"] = -1;
std::string json_str = writer.write(root); std::string json_str = writer.write(root);
@@ -1348,7 +1425,7 @@ void LLMarketplaceData::deleteSLMListing(S32 listing_id)
log_SLM_infos("LLHTTPClient::del", url, ""); log_SLM_infos("LLHTTPClient::del", url, "");
LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id); LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
setUpdating(folder_id, true); setUpdating(folder_id, true);
LLHTTPClient::del(url, new LLSLMDeleteListingsResponder(folder_id, is_listed, version_id), headers); LLHTTPClient::del(url, new LLSLMDeleteListingsResponder(folder_id), headers);
} }
std::string LLMarketplaceData::getSLMConnectURL(const std::string& route) std::string LLMarketplaceData::getSLMConnectURL(const std::string& route)
@@ -1359,16 +1436,10 @@ std::string LLMarketplaceData::getSLMConnectURL(const std::string& route)
{ {
// Get DirectDelivery cap // Get DirectDelivery cap
url = regionp->getCapability("DirectDelivery"); url = regionp->getCapability("DirectDelivery");
// *TODO : Take this DirectDelivery cap coping mechanism hack out if (url != "")
if (url == "")
{ {
url = "https://marketplace.secondlife-staging.com/api/1/viewer/" + gAgentID.asString(); url += route;
} }
else
{
llinfos << "Merov : DD cap = " << url << ", agent = " << gAgentID.asString() << llendl;
}
url += route;
} }
return url; return url;
} }
@@ -1378,7 +1449,16 @@ void LLMarketplaceData::setSLMStatus(U32 status)
mMarketPlaceStatus = status; mMarketPlaceStatus = status;
if (mStatusUpdatedSignal) if (mStatusUpdatedSignal)
{ {
(*mStatusUpdatedSigal)(); (*mStatusUpdatedSignal)();
}
}
void LLMarketplaceData::setSLMDataFetched(U32 status)
{
mMarketPlaceDataFetched = status;
if (mDataFetchedSignal)
{
(*mDataFetchedSignal)();
} }
} }
@@ -1392,13 +1472,29 @@ bool LLMarketplaceData::createListing(const LLUUID& folder_id)
return false; return false;
} }
// Get the version folder: if there is only one subfolder, we will set it as a version folder immediately
S32 count = -1;
LLUUID version_id = getVersionFolderIfUnique(folder_id);
if (version_id.notNull())
{
count = compute_stock_count(version_id, true);
}
// Validate the count on hand
if (count == COMPUTE_STOCK_NOT_EVALUATED)
{
// If the count on hand cannot be evaluated, we will consider it empty (out of stock) at creation time
// It will get reevaluated and updated once the items are fetched
count = 0;
}
// Post the listing creation request to SLM // Post the listing creation request to SLM
createSLMListing(folder_id); createSLMListing(folder_id, version_id, count);
return true; return true;
} }
bool LLMarketplaceData::clearListing(const LLUUID& folder_id) bool LLMarketplaceData::clearListing(const LLUUID& folder_id, S32 depth)
{ {
if (folder_id.isNull()) if (folder_id.isNull())
{ {
@@ -1406,8 +1502,13 @@ bool LLMarketplaceData::clearListing(const LLUUID& folder_id)
return false; return false;
} }
// Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
// Folder id can be the root of the listing of not so we need to retrieve the root first // Folder id can be the root of the listing of not so we need to retrieve the root first
S32 depth = depth_nesting_in_marketplace(folder_id);
LLUUID listing_uuid = (isListed(folder_id) ? folder_id : nested_parent_id(folder_id, depth)); LLUUID listing_uuid = (isListed(folder_id) ? folder_id : nested_parent_id(folder_id, depth));
S32 listing_id = getListingID(listing_uuid); S32 listing_id = getListingID(listing_uuid);
@@ -1423,7 +1524,7 @@ bool LLMarketplaceData::clearListing(const LLUUID& folder_id)
return true; return true;
} }
bool LLMarketplaceData::getListing(const LLUUID& folder_id) bool LLMarketplaceData::getListing(const LLUUID& folder_id, S32 depth)
{ {
if (folder_id.isNull()) if (folder_id.isNull())
{ {
@@ -1431,8 +1532,13 @@ bool LLMarketplaceData::getListing(const LLUUID& folder_id)
return false; return false;
} }
// Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
// Folder id can be the root of the listing or not so we need to retrieve the root first // Folder id can be the root of the listing or not so we need to retrieve the root first
S32 depth = depth_nesting_in_marketplace(folder_id);
LLUUID listing_uuid = (isListed(folder_id) ? folder_id : nested_parent_id(folder_id, depth)); LLUUID listing_uuid = (isListed(folder_id) ? folder_id : nested_parent_id(folder_id, depth));
S32 listing_id = getListingID(listing_uuid); S32 listing_id = getListingID(listing_uuid);
@@ -1460,10 +1566,15 @@ bool LLMarketplaceData::getListing(S32 listing_id)
return true; return true;
} }
bool LLMarketplaceData::activateListing(const LLUUID& folder_id, bool activate) bool LLMarketplaceData::activateListing(const LLUUID& folder_id, bool activate, S32 depth)
{ {
// Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
// Folder id can be the root of the listing or not so we need to retrieve the root first // Folder id can be the root of the listing or not so we need to retrieve the root first
S32 depth = depth_nesting_in_marketplace(folder_id);
LLUUID listing_uuid = nested_parent_id(folder_id, depth); LLUUID listing_uuid = nested_parent_id(folder_id, depth);
S32 listing_id = getListingID(listing_uuid); S32 listing_id = getListingID(listing_uuid);
if (listing_id == 0) if (listing_id == 0)
@@ -1472,10 +1583,22 @@ bool LLMarketplaceData::activateListing(const LLUUID& folder_id, bool activate)
return false; return false;
} }
if (getActivationState(listing_uuid) == activate)
{
// If activation state is unchanged, no point spamming SLM with an update
return true;
}
LLUUID version_uuid = getVersionFolder(listing_uuid); LLUUID version_uuid = getVersionFolder(listing_uuid);
// Also update the count on hand // Also update the count on hand
S32 count = compute_stock_count(folder_id); S32 count = compute_stock_count(folder_id);
if (count == COMPUTE_STOCK_NOT_EVALUATED)
{
// If the count on hand cannot be evaluated locally, we should not change that SLM value
// We are assuming that this issue is local and should not modify server side values
count = getCountOnHand(listing_uuid);
}
// Post the listing update request to SLM // Post the listing update request to SLM
updateSLMListing(listing_uuid, listing_id, version_uuid, activate, count); updateSLMListing(listing_uuid, listing_id, version_uuid, activate, count);
@@ -1483,10 +1606,15 @@ bool LLMarketplaceData::activateListing(const LLUUID& folder_id, bool activate)
return true; return true;
} }
bool LLMarketplaceData::setVersionFolder(const LLUUID& folder_id, const LLUUID& version_id) bool LLMarketplaceData::setVersionFolder(const LLUUID& folder_id, const LLUUID& version_id, S32 depth)
{ {
// Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
// Folder id can be the root of the listing or not so we need to retrieve the root first // Folder id can be the root of the listing or not so we need to retrieve the root first
S32 depth = depth_nesting_in_marketplace(folder_id);
LLUUID listing_uuid = nested_parent_id(folder_id, depth); LLUUID listing_uuid = nested_parent_id(folder_id, depth);
S32 listing_id = getListingID(listing_uuid); S32 listing_id = getListingID(listing_uuid);
if (listing_id == 0) if (listing_id == 0)
@@ -1495,11 +1623,23 @@ bool LLMarketplaceData::setVersionFolder(const LLUUID& folder_id, const LLUUID&
return false; return false;
} }
if (getVersionFolder(listing_uuid) == version_id)
{
// If version folder is unchanged, no point spamming SLM with an update
return true;
}
// Note: if the version_id is cleared, we need to unlist the listing, otherwise, state unchanged // Note: if the version_id is cleared, we need to unlist the listing, otherwise, state unchanged
bool is_listed = (version_id.isNull() ? false : getActivationState(listing_uuid)); bool is_listed = (version_id.isNull() ? false : getActivationState(listing_uuid));
// Also update the count on hand // Also update the count on hand
S32 count = compute_stock_count(version_id); S32 count = compute_stock_count(version_id);
if (count == COMPUTE_STOCK_NOT_EVALUATED)
{
// If the count on hand cannot be evaluated, we will consider it empty (out of stock) when resetting the version folder
// It will get reevaluated and updated once the items are fetched
count = 0;
}
// Post the listing update requesst to SLM // Post the listing update requesst to SLM
updateSLMListing(listing_uuid, listing_id, version_id, is_listed, count); updateSLMListing(listing_uuid, listing_id, version_id, is_listed, count);
@@ -1507,10 +1647,15 @@ bool LLMarketplaceData::setVersionFolder(const LLUUID& folder_id, const LLUUID&
return true; return true;
} }
bool LLMarketplaceData::updateCountOnHand(const LLUUID& folder_id) bool LLMarketplaceData::updateCountOnHand(const LLUUID& folder_id, S32 depth)
{ {
// Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
// Folder id can be the root of the listing or not so we need to retrieve the root first // Folder id can be the root of the listing or not so we need to retrieve the root first
S32 depth = depth_nesting_in_marketplace(folder_id);
LLUUID listing_uuid = nested_parent_id(folder_id, depth); LLUUID listing_uuid = nested_parent_id(folder_id, depth);
S32 listing_id = getListingID(listing_uuid); S32 listing_id = getListingID(listing_uuid);
if (listing_id == 0) if (listing_id == 0)
@@ -1519,16 +1664,31 @@ bool LLMarketplaceData::updateCountOnHand(const LLUUID& folder_id)
return false; return false;
} }
// Get the unchanged values
bool is_listed = getActivationState(lissting_uuid);
LLUUID version_uuid = getVersionFolder(listing_uuid);
// Compute the new count on hand // Compute the new count on hand
S32 count = compute_stock_count(folder_id); S32 count = compute_stock_count(folder_id);
if (count == getCountOnHand(listing_uuid))
{
// If count on hand is unchanged, no point spamming SLM with an update
return true;
}
else if (count == COMPUTE_STOCK_NOT_EVALUATED)
{
// If local count on hand is not known at that point, do *not* force an update to SLM
return false;
}
// Get the unchanged values
bool is_listed = getActivationState(listing_uuid);
LLUUID version_uuid = getVersionFolder(listing_uuid);
// Post the listing update request to SLM // Post the listing update request to SLM
updateSLMListing(listing_uuid, listing_id, version_uuid, is_listed, count); updateSLMListing(listing_uuid, listing_id, version_uuid, is_listed, count);
// Force the local value as it prevents spamming (count update may occur in burst when restocking)
// Note that if SLM has a good reason to return a different value, it'll be updated by the responder
setCountOnHand(listing_uuid, count, false);
return true; return true;
} }
@@ -1540,38 +1700,38 @@ bool LLMarketplaceData::associateListing(const LLUUID& folder_id, const LLUUID&
return false; return false;
} }
// Post the listing update request to SLM // Get the version folder: if there is only one subfolder, we will set it as a version folder immediately
associateSLMListing(folder_id, listing_id, source_folder_id); LLUUID version_id = getVersionFolderIfUnique(folder_id);
// Post the listing associate request to SLM
associateSLMListing(folder_id, listing_id, version_id, source_folder_id);
return true; return true;
} }
// Methods privately called or called by SLM responders to perform changes // Methods privately called or called by SLM responders to perform changes
bool LLMarketplaceData::addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, bool update) bool LLMarketplaceData::addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, const std::string& edit_url, S32 count)
{ {
if (isListed(folder_id))
{
// Listing already exists -> exit with error
return false;
}
mMarketplaceItems[folder_id] = LLMarketplaceTuple(folder_id, listing_id, version_id, is_listed); mMarketplaceItems[folder_id] = LLMarketplaceTuple(folder_id, listing_id, version_id, is_listed);
if (update) mMarketplaceItems[folder_id].mEditURL = edit_url;
mMarketplaceItems[folder_id].mCountOnHand = count;
if (version_id.notNull())
{ {
update_marketplace_category(folder_id, false); mVersionFolders[version_id] = folder_id;
gInventory.notifyObservers();
} }
return true; return true;
} }
bool LLMarketplaceData::deleteListing(const LLUUID& folder_id, bool update) bool LLMarketplaceData::deleteListing(const LLUUID& folder_id, bool update)
{ {
if (!isListed(folder_id)) LLUUID version_folder = getVersionFolder(folder_id);
if (mMarketplaceItems.erase(folder_id) != 1)
{ {
// Listing doesn't exist -> exit with error
return false; return false;
} }
mMarketplaceItems.erase(folder_id); mVersionFolders.erase(version_folder);
if (update) if (update)
{ {
@@ -1596,20 +1756,20 @@ bool LLMarketplaceData::deleteListing(S32 listing_id, bool update)
bool LLMarketplaceData::getActivationState(const LLUUID& folder_id) bool LLMarketplaceData::getActivationState(const LLUUID& folder_id)
{ {
// Listing folder case // Listing folder case
marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
if (isListed(folder_id)) if (isListed(folder_id))
{ {
marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
return (it->second).mIsActive; return (it->second).mIsActive;
} }
// We need to iterate through the list to check it's not a version folder // Version folder case
marketplace_items_list_t::iterator it = mMarketplaceItems.begin(); version_folders_list_t::iterator it_version = mVersionFolders.find(folder_id);
while (it != mMarketplaceItems.end()) if (it_version != mVersionFolders.end())
{ {
if ((it->second).mVersionFolderId == folder_id) marketplace_items_list_t::iterator it = mMarketplaceItems.find(it_version->second);
if (it != mMarketplaceItems.end())
{ {
return (it->second).mIsActive; return (it->second).mIsActive;
} }
it++;
} }
return false; return false;
} }
@@ -1646,9 +1806,15 @@ LLUUID LLMarketplaceData::getListingFolder(S32 listing_id)
} }
} }
std::string LLMarketplaceData::getListingURL(const LLUUID& folder_id) std::string LLMarketplaceData::getListingURL(const LLUUID& folder_id, S32 depth)
{ {
S32 depth = depth_nesting_in_marketplace(folder_id); // Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
LLUUID listing_uuid = nested_parent_id(folder_id, depth); LLUUID listing_uuid = nested_parent_id(folder_id, depth);
marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
@@ -1661,44 +1827,53 @@ bool LLMarketplaceData::isListed(const LLUUID& folder_id)
return (it != mMarketplaceItems.end()); return (it != mMarketplaceItems.end());
} }
bool LLMarketplaceData:isListedAndActive(const LLUUID& folder_id) bool LLMarketplaceData::isListedAndActive(const LLUUID& folder_id)
{ {
return (isListed(folder_id) && getActivationState(folder_id)); return (isListed(folder_id) && getActivationState(folder_id));
} }
bool LLMarketplaceData::isVersionFolder(const LLUUID& folder_id) bool LLMarketplaceData::isVersionFolder(const LLUUID& folder_id)
{ {
marketplace_items_list_t::iterator it = mMarketplaceItems.begin(): version_folders_list_t::iterator it = mVersionFolders.find(folder_id);
while (it != mMarketplaceItems.end()) return (it != mVersionFolders.end());
{
if ((it->second).mVersionFolderId == folder_id)
{
return true;
}
it++;
}
return false;
} }
bool LLMarketplaceData::isInActiveFolder(const LLUUID& obj_id) bool LLMarketplaceData::isInActiveFolder(const LLUUID& obj_id, S32 depth)
{ {
S32 depth = depth_nesting_in_marketplace(obj_id); // Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(obj_id);
}
LLUUID listing_uuid = nested_parent_id(obj_id, depth); LLUUID listing_uuid = nested_parent_id(obj_id, depth);
bool active = getActivationState(listing_uuid); bool active = getActivationState(listing_uuid);
LLUUID version_uuid = getVersionFolder(listing_uuid); LLUUID version_uuid = getVersionFolder(listing_uuid);
return (active && ((obj_id == version_uuid) || gInventory.isObjectDescendentOf(obj_id, version_uuid))); return (active && ((obj_id == version_uuid) || gInventory.isObjectDescendentOf(obj_id, version_uuid)));
} }
LLUUID LLMarketplaceData::getActiveFolder(const LLUUID& obj_id) LLUUID LLMarketplaceData::getActiveFolder(const LLUUID& folder_id, S32 depth)
{ {
S32 depth = depth_nesting_in_marketplace(obj_id); // Evaluate the depth if it wasn't passed as a parameter
LLUUID listing_uuid = nested_parent_id(obj_id, depth); if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
LLUUID listing_uuid = nested_parent_id(folder_id, depth);
return (getActivationState(listing_uuid) ? getVersionFolder(listing_uuid) : LLUUID::null); return (getActivationState(listing_uuid) ? getVersionFolder(listing_uuid) : LLUUID::null);
} }
bool LLMarketplaceData::isUpdating(const LLUUID& folder_id) bool LLMarketplaceData::isUpdating(const LLUUID& folder_id, S32 depth)
{ {
S32 depth = depth_nesting_in_marketplace(folder_id); // Evaluate the depth if it wasn't passed as a parameter
if (depth < 0)
{
depth = depth_nesting_in_marketplace(folder_id);
}
if ((depth <= 0) || (depth > 2)) if ((depth <= 0) || (depth > 2))
{ {
// Only listing and version folders though are concerned by that status // Only listing and version folders though are concerned by that status
@@ -1736,6 +1911,28 @@ void LLMarketplaceData::setUpdating(const LLUUID& folder_id, bool isUpdating)
} }
} }
void LLMarketplaceData::setValidationWaiting(const LLUUID& folder_id, S32 count)
{
mValidationWaitingList[folder_id] = count;
}
void LLMarketplaceData::decrementValidationWaiting(const LLUUID& folder_id, S32 count)
{
waiting_list_t::iterator found = mValidationWaitingList.find(folder_id);
if (found != mValidationWaitingList.end())
{
found->second -= count;
if (found->second <= 0)
{
mValidationWaitingList.erase(found);
LLInventoryCategory *cat = gInventory.getCategory(folder_id);
validate_marketplacelistings(cat);
update_marketplace_category(folder_id);
gInventory.notifyObservers();
}
}
}
// Private Modifiers // Private Modifiers
bool LLMarketplaceData::setListingID(const LLUUID& folder_id, S32 listing_id, bool update) bool LLMarketplaceData::setListingID(const LLUUID& folder_id, S32 listing_id, bool update)
{ {
@@ -1783,6 +1980,11 @@ bool LLMarketplaceData::setVersionFolderID(const LLUUID& folder_id, const LLUUID
} }
(it->second).mVersionFolderId = version_id; (it->second).mVersionFolderId = version_id;
mVersionFolders.erase(old_version_id);
if (version_id.notNull())
{
mVersionFolders[version_id] = folder_id;
}
if (update) if (update)
{ {
@@ -1811,7 +2013,7 @@ bool LLMarketplaceData::setActivationState(const LLUUID& folder_id, bool activat
return true; return true;
} }
bool LLMarketplaceData:setListingURL(const LLUUID& folder_id, const std::string& edit_url, bool update) bool LLMarketplaceData::setListingURL(const LLUUID& folder_id, const std::string& edit_url, bool update)
{ {
marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
if (it == mMarketplaceItems.end()) if (it == mMarketplaceItems.end())

View File

@@ -71,13 +71,24 @@ namespace MarketplaceStatusCodes
MARKET_PLACE_NOT_INITIALIZED = 0, MARKET_PLACE_NOT_INITIALIZED = 0,
MARKET_PLACE_INITIALIZING = 1, MARKET_PLACE_INITIALIZING = 1,
MARKET_PLACE_CONNECTION_FAILURE = 2, MARKET_PLACE_CONNECTION_FAILURE = 2,
MARKET_PLACE_MERCHANT = 3, MARKET_PLACE_NOT_MERCHANT = 3,
MARKET_PLACE_NOT_MERCHANT = 4, MARKET_PLACE_MERCHANT = 4,
MARKET_PLACE_NOT_MIGRATED_MERCHANT = 5, MARKET_PLACE_NOT_MIGRATED_MERCHANT = 5,
MARKET_PLACE_MIGRATED_MERCHANT = 6 MARKET_PLACE_MIGRATED_MERCHANT = 6
}; };
} }
namespace MarketplaceFetchCodes
{
enum sCode
{
MARKET_FETCH_NOT_DONE = 0,
MARKET_FETCH_LOADING = 1,
MARKET_FETCH_FAILED = 2,
MARKET_FETCH_DONE = 3
};
}
class LLMarketplaceInventoryImporter class LLMarketplaceInventoryImporter
: public LLSingleton<LLMarketplaceInventoryImporter> : public LLSingleton<LLMarketplaceInventoryImporter>
@@ -159,6 +170,7 @@ private:
// * The mListingFolderId is used as a key to this map. It could therefore be taken off the LLMarketplaceTuple object themselves. // * The mListingFolderId is used as a key to this map. It could therefore be taken off the LLMarketplaceTuple object themselves.
// * The SLM DB however uses the mListingId as its primary key and it shows in its API. In the viewer though, the mListingFolderId is what we use to grab an inventory record. // * The SLM DB however uses the mListingId as its primary key and it shows in its API. In the viewer though, the mListingFolderId is what we use to grab an inventory record.
typedef std::map<LLUUID, LLMarketplaceTuple> marketplace_items_list_t; typedef std::map<LLUUID, LLMarketplaceTuple> marketplace_items_list_t;
typedef std::map<LLUUID, LLUUID> version_folders_list_t;
// Session cache of all Marketplace tuples // Session cache of all Marketplace tuples
// Notes: // Notes:
@@ -192,17 +204,21 @@ public:
typedef boost::signals2::signal<void()> status_updated_signal_t; typedef boost::signals2::signal<void()> status_updated_signal_t;
void initializeSLM(const status_updated_signal_t::slot_type& cb); void initializeSLM(const status_updated_signal_t::slot_type& cb);
U32 getSLMStatus() const { return mMarketPlaceStatus; } U32 getSLMStatus() const { return mMarketPlaceStatus; }
void setSLMStatus(U32 status);
void getSLMListings(); void getSLMListings();
bool isEmpty() const { return (mMarketplaceItems.size() == 0); } bool isEmpty() const { return (mMarketplaceItems.size() == 0); }
void setDataFetchedSignal(const status_updated_signal_t::slot_type& cb);
void setSLMDataFetched(U32 status);
U32 getSLMDataFetched() { return mMarketPlaceDataFetched; }
// High level create/delete/set Marketplace data: each method returns true if the function succeeds, false if error // High level create/delete/set Marketplace data: each method returns true if the function succeeds, false if error
bool createListing(const LLUUID& folder_id); bool createListing(const LLUUID& folder_id);
bool activateListing(const LLUUID& folder_id, bool activate); bool activateListing(const LLUUID& folder_id, bool activate, S32 depth = -1);
bool clearListing(const LLUUID& folder_id); bool clearListing(const LLUUID& folder_id, S32 depth = -1);
bool setVersionFolder(const LLUUID& folder_id, const LLUUID& version_id); bool setVersionFolder(const LLUUID& folder_id, const LLUUID& version_id, S32 depth = -1);
bool associateListing(const LLUUID& folder_id, const LLUUID& source_folder_id, S32 listing_id); bool associateListing(const LLUUID& folder_id, const LLUUID& source_folder_id, S32 listing_id);
bool updateCountOnHand(const LLUUID& folder_id); bool updateCountOnHand(const LLUUID& folder_id, S32 depth = -1);
bool getListing(const LLUUID& folder_id); bool getListing(const LLUUID& folder_id, S32 depth = -1);
bool getListing(S32 listing_id); bool getListing(S32 listing_id);
bool deleteListing(S32 listing_id, bool update = true); bool deleteListing(S32 listing_id, bool update = true);
@@ -210,15 +226,15 @@ public:
bool isListed(const LLUUID& folder_id); // returns true if folder_id is a Listing folder bool isListed(const LLUUID& folder_id); // returns true if folder_id is a Listing folder
bool isListedAndActive(const LLUUID& folder_id); // returns true if folder_id is an active (listed) Listing folder bool isListedAndActive(const LLUUID& folder_id); // returns true if folder_id is an active (listed) Listing folder
bool isVersionFolder(const LLUUID& folder_id); // returns true if folder_id is a Version folder bool isVersionFolder(const LLUUID& folder_id); // returns true if folder_id is a Version folder
bool isInActiveFolder(const LLUUID& obj_id); // returns true if the obj_id is buried in an active version folder bool isInActiveFolder(const LLUUID& obj_id, S32 depth = -1); // returns true if the obj_id is buried in an active version folder
LLUUID getActiveFolder(const LLUUID& obj_id); // returns the UUID of the active version folder obj_id is in LLUUID getActiveFolder(const LLUUID& obj_id, S32 depth = -1); // returns the UUID of the active version folder obj_id is in
bool isUpdating(const LLUUID& folder_id); // returns true if we're waiting from SLM incoming data for folder_id bool isUpdating(const LLUUID& folder_id, S32 depth = -1); // returns true if we're waiting from SLM incoming data for folder_id
// Access MArketplace data set : each method returns a default value if the argument can't be found // Access MArketplace data set : each method returns a default value if the argument can't be found
bool getActivationState(const LLUUID& folder_id); bool getActivationState(const LLUUID& folder_id);
S32 getListingID(const LLUUID& folder_id); S32 getListingID(const LLUUID& folder_id);
LLUUID getVersionFolder(const LLUUID& folder_id); LLUUID getVersionFolder(const LLUUID& folder_id);
std::string getListingURL(const LLUUID& folder_id); std::string getListingURL(const LLUUID& folder_id, S32 depth = -1);
LLUUID getListingFolder(S32 listing_id); LLUUID getListingFolder(S32 listing_id);
S32 getCountOnHand(const LLUUID& folder_id); S32 getCountOnHand(const LLUUID& folder_id);
@@ -227,10 +243,14 @@ public:
void setDirtyCount() { mDirtyCount = true; } void setDirtyCount() { mDirtyCount = true; }
void setUpdating(const LLUUID& folder_id, bool isUpdating); void setUpdating(const LLUUID& folder_id, bool isUpdating);
// Used to decide when to run a validation on listing folders
void setValidationWaiting(const LLUUID& folder_id, S32 count);
void decrementValidationWaiting(const LLUUID& folder_id, S32 count = 1);
private: private:
// Modify Marketplace data set : each method returns true if the function succeeds, false if error // Modify Marketplace data set : each method returns true if the function succeeds, false if error
// Used internally only by SLM Responders when data are received from the SLM Server // Used internally only by SLM Responders when data are received from the SLM Server
bool addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, bool update = true); bool addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, const std::string& edit_url, S32 count);
bool deleteListing(const LLUUID& folder_id, bool update = true); bool deleteListing(const LLUUID& folder_id, bool update = true);
bool setListingID(const LLUUID& folder_id, S32 listing_id, bool update = true); bool setListingID(const LLUUID& folder_id, S32 listing_id, bool update = true);
bool setVersionFolderID(const LLUUID& folder_id, const LLUUID& version_id, bool update = true); bool setVersionFolderID(const LLUUID& folder_id, const LLUUID& version_id, bool update = true);
@@ -239,25 +259,32 @@ private:
bool setCountOnHand(const LLUUID& folder_id, S32 count, bool update = true); bool setCountOnHand(const LLUUID& folder_id, S32 count, bool update = true);
// Private SLM API : package data and get/post/put requests to the SLM Server through the SLM API // Private SLM API : package data and get/post/put requests to the SLM Server through the SLM API
void setSLMStatus(U32 status); void createSLMListing(const LLUUID& folder_id, const LLUUID& version_id, S32 count);
void createSLMListing(const LLUUID& folder_id);
void getSLMListing(S32 listing_id); void getSLMListing(S32 listing_id);
void updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count); void updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count);
void associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id); void associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, const LLUUID& source_folder_id);
void deleteSLMListing(S32 listing_id); void deleteSLMListing(S32 listing_id);
std::string getSLMConnectURL(const std::string& route); std::string getSLMConnectURL(const std::string& route);
// Handling Marketplace connection and inventory connection // Handling Marketplace connection and inventory connection
U32 mMarketPlaceStatus U32 mMarketPlaceStatus;
status_updated_signal_t* mStatusUpdatedSignal; status_updated_signal_t* mStatusUpdatedSignal;
LLInventoryObserver* mInventoryObserver; LLInventoryObserver* mInventoryObserver;
bool mDirtyCount; // If true, stock count value need to be updated at the next check bool mDirtyCount; // If true, stock count value need to be updated at the next check
// Update data // Update data
U32 mMarketPlaceDataFetched;
status_updated_signal_t* mDataFetchedSignal;
std::set<LLUUID> mPendingUpdateSet; std::set<LLUUID> mPendingUpdateSet;
// Listing folders waiting for validation
typedef std::map<LLUUID,S32> waiting_list_t;
waiting_list_t mValidationWaitingList;
// The cache of SLM data (at last...) // The cache of SLM data (at last...)
marketplace_items_list_t mMarketplaceItems; marketplace_items_list_t mMarketplaceItems;
// We need a list (version folder -> listing folder) because such reverse lookups are frequent
version_folders_list_t mVersionFolders;
}; };

View File

@@ -157,7 +157,7 @@ BOOL LLPanelMainInventory::postBuild()
{ {
// "All Items" is the previous only view, so it gets the InventorySortOrder // "All Items" is the previous only view, so it gets the InventorySortOrder
mActivePanel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); mActivePanel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER));
mActivePanel->getFilter()->markDefault(); mActivePanel->getFilter().markDefault();
mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2)); mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2));
mResortActivePanel = true; mResortActivePanel = true;
} }
@@ -167,7 +167,7 @@ BOOL LLPanelMainInventory::postBuild()
recent_items_panel->setSinceLogoff(TRUE); recent_items_panel->setSinceLogoff(TRUE);
recent_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::RECENTITEMS_SORT_ORDER)); recent_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::RECENTITEMS_SORT_ORDER));
recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
recent_items_panel->getFilter()->markDefault(); recent_items_panel->getFilter().markDefault();
recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2)); recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2));
} }
LLInventoryPanel* worn_items_panel = getChild<LLInventoryPanel>("Worn Items"); LLInventoryPanel* worn_items_panel = getChild<LLInventoryPanel>("Worn Items");
@@ -175,7 +175,7 @@ BOOL LLPanelMainInventory::postBuild()
{ {
worn_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::WORNITEMS_SORT_ORDER)); worn_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::WORNITEMS_SORT_ORDER));
worn_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); worn_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
worn_items_panel->getFilter()->markDefault(); worn_items_panel->getFilter().markDefault();
worn_items_panel->setFilterWorn(true); worn_items_panel->setFilterWorn(true);
worn_items_panel->setFilterLinks(LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS); worn_items_panel->setFilterLinks(LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS);
worn_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, worn_items_panel, _1, _2)); worn_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, worn_items_panel, _1, _2));
@@ -196,11 +196,11 @@ BOOL LLPanelMainInventory::postBuild()
// Note that the "All Items" and "Worn Items" settings do not persist per-account. // Note that the "All Items" and "Worn Items" settings do not persist per-account.
if(recent_items_panel) if(recent_items_panel)
{ {
if(savedFilterState.has(recent_items_panel->getFilter()->getName())) if(savedFilterState.has(recent_items_panel->getFilter().getName()))
{ {
LLSD recent_items = savedFilterState.get( LLSD recent_items = savedFilterState.get(
recent_items_panel->getFilter()->getName()); recent_items_panel->getFilter().getName());
recent_items_panel->getFilter()->fromLLSD(recent_items); recent_items_panel->getFilter().fromLLSD(recent_items);
} }
} }
} }
@@ -238,37 +238,28 @@ LLPanelMainInventory::~LLPanelMainInventory( void )
LLInventoryPanel* all_items_panel = getChild<LLInventoryPanel>("All Items"); LLInventoryPanel* all_items_panel = getChild<LLInventoryPanel>("All Items");
if (all_items_panel) if (all_items_panel)
{ {
LLInventoryFilter* filter = all_items_panel->getFilter(); LLInventoryFilter& filter = all_items_panel->getFilter();
if (filter) LLSD filterState;
{ filter.toLLSD(filterState);
LLSD filterState; filterRoot[filter.getName()] = filterState;
filter->toLLSD(filterState);
filterRoot[filter->getName()] = filterState;
}
} }
LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items"); LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items");
if (recent_items_panel) if (recent_items_panel)
{ {
LLInventoryFilter* filter = recent_items_panel->getFilter(); LLInventoryFilter& filter = recent_items_panel->getFilter();
if (filter) LLSD filterState;
{ filter.toLLSD(filterState);
LLSD filterState; filterRoot[filter.getName()] = filterState;
filter->toLLSD(filterState);
filterRoot[filter->getName()] = filterState;
}
} }
LLInventoryPanel* worn_items_panel = getChild<LLInventoryPanel>("Worn Items"); LLInventoryPanel* worn_items_panel = getChild<LLInventoryPanel>("Worn Items");
if (worn_items_panel) if (worn_items_panel)
{ {
LLInventoryFilter* filter = worn_items_panel->getFilter(); LLInventoryFilter& filter = worn_items_panel->getFilter();
if (filter) LLSD filterState;
{ filter.toLLSD(filterState);
LLSD filterState; filterRoot[filter.getName()] = filterState;
filter->toLLSD(filterState);
filterRoot[filter->getName()] = filterState;
}
} }
std::ostringstream filterSaveName; std::ostringstream filterSaveName;
@@ -496,7 +487,7 @@ void LLPanelMainInventory::updateSortControls()
void LLPanelMainInventory::resetFilters() void LLPanelMainInventory::resetFilters()
{ {
LLFloaterInventoryFinder *finder = getFinder(); LLFloaterInventoryFinder *finder = getFinder();
getActivePanel()->getFilter()->resetDefault(); getActivePanel()->getFilter().resetDefault();
if (finder) if (finder)
{ {
finder->updateElementsFromFilter(); finder->updateElementsFromFilter();
@@ -732,7 +723,7 @@ void LLPanelMainInventory::onFilterSelected()
return; return;
} }
LLInventoryFilter* filter = mActivePanel->getFilter(); LLInventoryFilter* filter = &mActivePanel->getFilter();
LLFloaterInventoryFinder *finder = getFinder(); LLFloaterInventoryFinder *finder = getFinder();
if (finder) if (finder)
{ {
@@ -837,7 +828,7 @@ void LLPanelMainInventory::updateItemcountText()
} }
void LLPanelMainInventory::setFilterTextFromFilter() void LLPanelMainInventory::setFilterTextFromFilter()
{ {
mFilterText = mActivePanel->getFilter()->getFilterText(); mFilterText = mActivePanel->getFilter().getFilterText();
} }
void LLPanelMainInventory::toggleFindOptions() void LLPanelMainInventory::toggleFindOptions()
@@ -899,7 +890,7 @@ LLFloaterInventoryFinder::LLFloaterInventoryFinder(const std::string& name,
INV_FINDER_WIDTH, INV_FINDER_HEIGHT, DRAG_ON_TOP, INV_FINDER_WIDTH, INV_FINDER_HEIGHT, DRAG_ON_TOP,
MINIMIZE_NO, CLOSE_YES), MINIMIZE_NO, CLOSE_YES),
mPanelMainInventory(inventory_view), mPanelMainInventory(inventory_view),
mFilter(inventory_view->getPanel()->getFilter()) mFilter(&inventory_view->getPanel()->getFilter())
{ {
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml"); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml");
@@ -978,9 +969,6 @@ void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter)
void LLFloaterInventoryFinder::updateElementsFromFilter() void LLFloaterInventoryFinder::updateElementsFromFilter()
{ {
if (!mFilter)
return;
// Get data needed for filter display // Get data needed for filter display
U32 filter_types = mFilter->getFilterObjectTypes(); U32 filter_types = mFilter->getFilterObjectTypes();
std::string filter_string = mFilter->getFilterSubString(); std::string filter_string = mFilter->getFilterSubString();

View File

@@ -2340,10 +2340,8 @@ bool idle_startup()
display_startup(); display_startup();
// Init SLM Marketplace connection so we know which UI should be used for the user as a merchant // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp)
// Note: Eventually, all merchant will be migrated to the new SLM system and there will be no reason to show the old UI at all. //check_merchant_status();
// *TODO : Suppress the Merchant Outbox UI completely
check_merchant_status();
display_startup(); display_startup();

View File

@@ -42,7 +42,7 @@
#include "llappearancemgr.h" #include "llappearancemgr.h"
#include "lldictionary.h" #include "lldictionary.h"
#include "llfirstuse.h" #include "llfirstuse.h"
#include "llfloaterinventory.h" #include "llfloateravatarpicker.h"
#include "llfloatertools.h" #include "llfloatertools.h"
#include "llgesturemgr.h" #include "llgesturemgr.h"
#include "llgiveinventory.h" #include "llgiveinventory.h"
@@ -52,40 +52,26 @@
#include "llinventorybridge.h" #include "llinventorybridge.h"
#include "llinventorydefines.h" #include "llinventorydefines.h"
#include "llinventoryfunctions.h" #include "llinventoryfunctions.h"
#include "llinventorypanel.h" #include "llparcel.h" //<alchemy> Rez under Land Group
#include "llmutelist.h"
#include "llnotify.h"
#include "llpreviewnotecard.h" #include "llpreviewnotecard.h"
#include "llrootview.h"
#include "llselectmgr.h" #include "llselectmgr.h"
#include "lltoolmgr.h" #include "lltoolmgr.h"
#include "lltrans.h" #include "lltrans.h"
#include "llviewertexturelist.h"
#include "llviewerinventory.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h" #include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h" //<alchemy> Rez under Land Group
#include "llviewerregion.h" #include "llviewerregion.h"
#include "llviewerstats.h" #include "llviewerstats.h"
#include "llviewerwindow.h" #include "llviewerwindow.h"
#include "llvoavatarself.h" #include "llvoavatarself.h"
#include "llvolume.h"
#include "llworld.h" #include "llworld.h"
#include "llpanelface.h" #include "llpanelface.h"
// <edit>
#include "llappviewer.h" // System Folders
#include "llparcel.h" // always rez
#include "llviewerparcelmgr.h" // always rez
// </edit>
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
#include "rlvhandler.h" #include "rlvhandler.h"
#include "rlvlocks.h" #include "rlvlocks.h"
// [/RLVa:KB] // [/RLVa:KB]
// MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
// or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
// bit from there to give some pad.
const S32 MAX_ITEMS = 42;
// syntactic sugar // syntactic sugar
#define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember)) #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember))
@@ -288,15 +274,15 @@ void LLCategoryDropDescendentsObserver::done()
std::set<LLUUID> unique_ids; std::set<LLUUID> unique_ids;
for(S32 i = 0; i < count; ++i) for(S32 i = 0; i < count; ++i)
{ {
unique_ids.insert(items.at(i)->getUUID()); unique_ids.insert(items.get(i)->getUUID());
} }
uuid_vec_t ids; uuid_vec_t ids;
std::back_insert_iterator<uuid_vec_t> copier(ids); std::back_insert_iterator<uuid_vec_t> copier(ids);
std::copy(unique_ids.begin(), unique_ids.end(), copier); std::copy(unique_ids.begin(), unique_ids.end(), copier);
LLCategoryDropObserver* dropper; LLCategoryDropObserver* dropper;
dropper = new LLCategoryDropObserver(mObjectID, mSource); dropper = new LLCategoryDropObserver(ids, mObjectID, mSource);
dropper->fetchItems(ids); dropper->startFetch();
if(dropper->isEverythingComplete()) if (dropper->isDone())
{ {
dropper->done(); dropper->done();
} }
@@ -360,14 +346,15 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary()
}; };
LLToolDragAndDrop::LLToolDragAndDrop() LLToolDragAndDrop::LLToolDragAndDrop()
: LLTool(std::string("draganddrop"), NULL), : LLTool(std::string("draganddrop"), NULL),
mDragStartX(0), mCargoCount(0),
mDragStartY(0), mDragStartX(0),
mSource(SOURCE_AGENT), mDragStartY(0),
mCursor(UI_CURSOR_NO), mSource(SOURCE_AGENT),
mLastAccept(ACCEPT_NO), mCursor(UI_CURSOR_NO),
mDrop(FALSE), mLastAccept(ACCEPT_NO),
mCurItemIndex(0) mDrop(FALSE),
mCurItemIndex(0)
{ {
} }
@@ -524,6 +511,7 @@ void LLToolDragAndDrop::beginMultiDrag(
void LLToolDragAndDrop::endDrag() void LLToolDragAndDrop::endDrag()
{ {
mEndDragSignal();
LLSelectMgr::getInstance()->unhighlightAll(); LLSelectMgr::getInstance()->unhighlightAll();
setMouseCapture(FALSE); setMouseCapture(FALSE);
} }
@@ -580,6 +568,8 @@ ECursorType LLToolDragAndDrop::acceptanceToCursor( EAcceptance acceptance )
mCursor = UI_CURSOR_NOLOCKED; mCursor = UI_CURSOR_NOLOCKED;
break; break;
case ACCEPT_NO: case ACCEPT_NO:
mCursor = UI_CURSOR_NO; mCursor = UI_CURSOR_NO;
break; break;
@@ -674,33 +664,41 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
sOperationId++; sOperationId++;
} }
// For people drag and drop we don't need an actual inventory object,
// instead we need the current cargo id, which should be a person id.
bool is_uuid_dragged = (mSource == SOURCE_PEOPLE);
if(top_view) if(top_view)
{ {
handled = TRUE; handled = TRUE;
for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
{ {
LLInventoryObject* cargo = locateInventory(item, cat); S32 local_x, local_y;
top_view->screenPointToLocal( x, y, &local_x, &local_y );
EAcceptance item_acceptance = ACCEPT_NO;
LLInventoryObject* cargo = locateInventory(item, cat);
if (cargo) if (cargo)
{ {
S32 local_x, local_y;
top_view->screenPointToLocal( x, y, &local_x, &local_y );
EAcceptance item_acceptance = ACCEPT_NO;
handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE, handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE,
mCargoTypes[mCurItemIndex], mCargoTypes[mCurItemIndex],
(void*)cargo, (void*)cargo,
&item_acceptance, &item_acceptance,
mToolTipMsg); mToolTipMsg);
if (handled)
{
// use sort order to determine priority of acceptance
*acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
}
} }
else else if (is_uuid_dragged)
{ {
return; handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE,
mCargoTypes[mCurItemIndex],
(void*)&mCargoIDs[mCurItemIndex],
&item_acceptance,
mToolTipMsg);
}
if (handled)
{
// use sort order to determine priority of acceptance
*acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance);
} }
} }
@@ -717,20 +715,27 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
{ {
LLInventoryObject* cargo = locateInventory(item, cat); S32 local_x, local_y;
EAcceptance item_acceptance;
top_view->screenPointToLocal( x, y, &local_x, &local_y );
LLInventoryObject* cargo = locateInventory(item, cat);
if (cargo) if (cargo)
{ {
S32 local_x, local_y;
EAcceptance item_acceptance;
top_view->screenPointToLocal( x, y, &local_x, &local_y );
handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, TRUE, handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, TRUE,
mCargoTypes[mCurItemIndex], mCargoTypes[mCurItemIndex],
(void*)cargo, (void*)cargo,
&item_acceptance, &item_acceptance,
mToolTipMsg); mToolTipMsg);
} }
else if (is_uuid_dragged)
{
handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE,
mCargoTypes[mCurItemIndex],
(void*)&mCargoIDs[mCurItemIndex],
&item_acceptance,
mToolTipMsg);
}
} }
} }
if (handled) if (handled)
@@ -747,20 +752,27 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
{ {
EAcceptance item_acceptance = ACCEPT_NO;
LLInventoryObject* cargo = locateInventory(item, cat); LLInventoryObject* cargo = locateInventory(item, cat);
if (!cargo) // fix for EXT-3191
if (cargo)
{ {
handled = FALSE; handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE,
break; mCargoTypes[mCurItemIndex],
(void*)cargo,
&item_acceptance,
mToolTipMsg);
}
else if (is_uuid_dragged)
{
handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE,
mCargoTypes[mCurItemIndex],
(void*)&mCargoIDs[mCurItemIndex],
&item_acceptance,
mToolTipMsg);
} }
EAcceptance item_acceptance = ACCEPT_NO;
handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE,
mCargoTypes[mCurItemIndex],
(void*)cargo,
&item_acceptance,
mToolTipMsg);
if (handled) if (handled)
{ {
// use sort order to determine priority of acceptance // use sort order to determine priority of acceptance
@@ -780,17 +792,25 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++)
{ {
LLInventoryObject* cargo = locateInventory(item, cat); EAcceptance item_acceptance;
LLInventoryObject* cargo = locateInventory(item, cat);
if (cargo) if (cargo)
{ {
EAcceptance item_acceptance;
handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE, handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE,
mCargoTypes[mCurItemIndex], mCargoTypes[mCurItemIndex],
(void*)cargo, (void*)cargo,
&item_acceptance, &item_acceptance,
mToolTipMsg); mToolTipMsg);
} }
else if (is_uuid_dragged)
{
handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE,
mCargoTypes[mCurItemIndex],
(void*)&mCargoIDs[mCurItemIndex],
&item_acceptance,
mToolTipMsg);
}
} }
} }
@@ -944,8 +964,7 @@ void LLToolDragAndDrop::pick(const LLPickInfo& pick_info)
const S32 item_index = mCurItemIndex; const S32 item_index = mCurItemIndex;
const EDragAndDropType dad_type = mCargoTypes[item_index]; const EDragAndDropType dad_type = mCargoTypes[item_index];
// Call the right implementation function // Call the right implementation function
(U32)callMemberFunction(*this, callMemberFunction(*this, LLDragAndDropDictionary::instance().get(dad_type, target))
LLDragAndDropDictionary::instance().get(dad_type, target))
(hit_obj, hit_face, pick_info.mKeyMask, TRUE); (hit_obj, hit_face, pick_info.mKeyMask, TRUE);
} }
} }
@@ -1185,6 +1204,7 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
{ {
switch (LLSelectMgr::getInstance()->getTextureChannel()) switch (LLSelectMgr::getInstance()->getTextureChannel())
{ {
case 0: case 0:
default: default:
{ {
@@ -1393,19 +1413,21 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
// Alway rez objects as land group if available. //<alchemy> Rez under Land Group
if (gSavedSettings.getBOOL("AscentAlwaysRezInGroup")) static LLCachedControl<bool> AlchemyRezUnderLandGroup(gSavedSettings, "AscentAlwaysRezInGroup");
LLUUID group_id = gAgent.getGroupID();
if (AlchemyRezUnderLandGroup)
{ {
LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); LLParcel* land_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
if(gAgent.isInGroup(parcel->getGroupID())) // Is the agent in the land group
msg->addUUIDFast(_PREHASH_GroupID, parcel->getGroupID()); if (gAgent.isInGroup(land_parcel->getGroupID()))
else if(gAgent.isInGroup(parcel->getOwnerID())) group_id = land_parcel->getGroupID();
msg->addUUIDFast(_PREHASH_GroupID, parcel->getOwnerID()); // Is the agent in the land group (the group owns the land)
else else if (gAgent.isInGroup(land_parcel->getOwnerID()))
msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); group_id = land_parcel->getOwnerID();
} }
else
msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); msg->addUUIDFast(_PREHASH_GroupID, group_id);
msg->nextBlock("RezData"); msg->nextBlock("RezData");
// if it's being rezzed from task inventory, we need to enable // if it's being rezzed from task inventory, we need to enable
@@ -1468,6 +1490,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
gInventory.deleteObject(item->getUUID()); gInventory.deleteObject(item->getUUID());
gInventory.notifyObservers(); gInventory.notifyObservers();
} }
// <edit> // <edit>
if (gSavedSettings.getBOOL("BroadcastViewerEffects")) if (gSavedSettings.getBOOL("BroadcastViewerEffects"))
{ {
@@ -1481,6 +1504,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
// <edit> // <edit>
} }
// </edit> // </edit>
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_REZ_COUNT); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_REZ_COUNT);
} }
@@ -1536,6 +1560,7 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj,
// *FIX: only show this if panel not expanded? // *FIX: only show this if panel not expanded?
gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS);
} }
// <edit> // <edit>
if (gSavedSettings.getBOOL("BroadcastViewerEffects")) if (gSavedSettings.getBOOL("BroadcastViewerEffects"))
{ {
@@ -1552,18 +1577,6 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj,
gFloaterTools->dirty(); gFloaterTools->dirty();
} }
struct LLGiveInventoryInfo
{
LLUUID mToAgentID;
LLUUID mInventoryObjectID;
LLUUID mIMSessionID;
LLGiveInventoryInfo(const LLUUID& to_agent, const LLUUID& obj_id, const LLUUID &im_session_id = LLUUID::null) :
mToAgentID(to_agent),
mInventoryObjectID(obj_id),
mIMSessionID(im_session_id)
{}
};
// accessor that looks at permissions, copyability, and names of // accessor that looks at permissions, copyability, and names of
// inventory items to determine if a drop would be ok. // inventory items to determine if a drop would be ok.
EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item) EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item)
@@ -1572,9 +1585,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
if(!item || !obj) return ACCEPT_NO; if(!item || !obj) return ACCEPT_NO;
// HACK: downcast // HACK: downcast
LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item; LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item;
if(!vitem->isFinished()) return ACCEPT_NO; if(!vitem->isFinished()) return ACCEPT_NO;
if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links
// deny attempts to drop from an object onto itself. This is to // deny attempts to drop from an object onto itself. This is to
@@ -1658,12 +1669,87 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
} }
static void give_inventory_cb(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
// if Cancel pressed
if (option == 1)
{
return;
}
LLSD payload = notification["payload"];
const LLUUID& session_id = payload["session_id"];
const LLUUID& agent_id = payload["agent_id"];
LLViewerInventoryItem * inv_item = gInventory.getItem(payload["item_id"]);
LLViewerInventoryCategory * inv_cat = gInventory.getCategory(payload["item_id"]);
if (NULL == inv_item && NULL == inv_cat)
{
llassert( FALSE );
return;
}
bool successfully_shared;
if (inv_item)
{
successfully_shared = LLGiveInventory::doGiveInventoryItem(agent_id, inv_item, session_id);
}
else
{
successfully_shared = LLGiveInventory::doGiveInventoryCategory(agent_id, inv_cat, session_id);
}
if (successfully_shared)
{
if ("avatarpicker" == payload["d&d_dest"].asString())
{
if (LLFloaterAvatarPicker::instanceExists())
LLFloaterAvatarPicker::getInstance()->close();
}
LLNotificationsUtil::add("ItemsShared");
}
}
static void show_object_sharing_confirmation(const std::string name,
LLInventoryObject* inv_item,
const LLSD& dest,
const LLUUID& dest_agent,
const LLUUID& session_id = LLUUID::null)
{
if (!inv_item)
{
llassert(NULL != inv_item);
return;
}
LLSD substitutions;
substitutions["RESIDENTS"] = name;
substitutions["ITEMS"] = inv_item->getName();
LLSD payload;
payload["agent_id"] = dest_agent;
payload["item_id"] = inv_item->getUUID();
payload["session_id"] = session_id;
payload["d&d_dest"] = dest.asString();
LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, payload, &give_inventory_cb);
}
static void get_name_cb(const LLUUID& id,
const std::string& full_name,
LLInventoryObject* inv_obj,
const LLSD& dest,
const LLUUID& dest_agent)
{
show_object_sharing_confirmation(full_name,
inv_obj,
dest,
id,
LLUUID::null);
}
// function used as drag-and-drop handler for simple agent give inventory requests // function used as drag-and-drop handler for simple agent give inventory requests
//static //static
bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_id, BOOL drop, bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_id, BOOL drop,
EDragAndDropType cargo_type, EDragAndDropType cargo_type,
void* cargo_data, void* cargo_data,
EAcceptance* accept) EAcceptance* accept,
const LLSD& dest)
{ {
// check the type // check the type
switch(cargo_type) switch(cargo_type)
@@ -1768,13 +1854,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
} }
// must not be already wearing it // must not be already wearing it
// <edit> /* <edit>
//LLVOAvatar* my_avatar = gAgentAvatarp; LLVOAvatarSelf* avatar = gAgentAvatarp;
//if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) if( !avatar || avatar->isWearingAttachment(item->getUUID()) )
//{ {
// return ACCEPT_NO; return ACCEPT_NO;
//} }
// </edit> </edit> */
const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id)) if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id))
@@ -1842,13 +1928,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
locateInventory(item, cat); locateInventory(item, cat);
if (!item || !item->isFinished()) return ACCEPT_NO; if (!item || !item->isFinished()) return ACCEPT_NO;
// <edit> /* <edit>
//LLVOAvatar* my_avatar = gAgentAvatarp; LLVOAvatarSelf* my_avatar = gAgentAvatarp;
//if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
//{ {
// return ACCEPT_NO; return ACCEPT_NO;
//} }
// </edit> </edit> */
EAcceptance accept; EAcceptance accept;
BOOL remove_inventory; BOOL remove_inventory;
@@ -1917,13 +2004,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
LLViewerInventoryCategory* cat; LLViewerInventoryCategory* cat;
locateInventory(item, cat); locateInventory(item, cat);
if(!item || !item->isFinished()) return ACCEPT_NO; if(!item || !item->isFinished()) return ACCEPT_NO;
// <edit> /* <edit>
//LLVOAvatar* my_avatar = gAgentAvatarp; LLVOAvatarSelf* my_avatar = gAgentAvatarp;
//if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
//{ {
// return ACCEPT_NO; return ACCEPT_NO;
//} }
// </edit> </edit> */
if((mask & MASK_CONTROL)) if((mask & MASK_CONTROL))
{ {
@@ -2026,23 +2113,20 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject(
{ {
LL_DEBUGS() << "LLToolDragAndDrop::dad3dApplyToObject()" << LL_ENDL; LL_DEBUGS() << "LLToolDragAndDrop::dad3dApplyToObject()" << LL_ENDL;
// <edit> /* <edit>
// Fuck this // Fuck this
// *HACK: In order to resolve SL-22177, we need to block drags // *HACK: In order to resolve SL-22177, we need to block drags
// from notecards and objects onto other objects. // from notecards and objects onto other objects.
//if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
//{ {
// return ACCEPT_NO; return ACCEPT_NO;
//} }
// </edit> </edit> */
LLViewerInventoryItem* item; LLViewerInventoryItem* item;
LLViewerInventoryCategory* cat; LLViewerInventoryCategory* cat;
locateInventory(item, cat); locateInventory(item, cat);
if(!item || !item->isFinished()) return ACCEPT_NO; if(!item || !item->isFinished()) return ACCEPT_NO;
EAcceptance rv = willObjectAcceptInventory(obj, item); EAcceptance rv = willObjectAcceptInventory(obj, item);
if((mask & MASK_CONTROL)) if((mask & MASK_CONTROL))
{ {
@@ -2704,11 +2788,11 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats, LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats,
LLViewerInventoryItem::item_array_t& items) LLViewerInventoryItem::item_array_t& items)
{ {
if(mCargoIDs.count() == 0) return NULL; if(mCargoIDs.size() == 0) return NULL;
if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)) if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
{ {
// The object should be in user inventory. // The object should be in user inventory.
for (S32 i = 0; i < mCargoIDs.count(); i++) for (S32 i = 0; i < mCargoIDs.size(); i++)
{ {
LLInventoryItem* item = gInventory.getItem(mCargoIDs[i]); LLInventoryItem* item = gInventory.getItem(mCargoIDs[i]);
if (item) if (item)
@@ -2732,7 +2816,7 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC
|| (mCargoType == DAD_ROOT_CATEGORY)) || (mCargoType == DAD_ROOT_CATEGORY))
{ {
// The object should be in user inventory. // The object should be in user inventory.
for (S32 i = 0; i < mCargoIDs.count(); i++) for (S32 i = 0; i < mCargoIDs.size(); i++)
{ {
LLInventoryCategory* category = (LLInventoryCategory*)obj->getInventoryObject(mCargoIDs[i]); LLInventoryCategory* category = (LLInventoryCategory*)obj->getInventoryObject(mCargoIDs[i]);
if (category) if (category)
@@ -2743,7 +2827,7 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC
} }
else else
{ {
for (S32 i = 0; i < mCargoIDs.count(); i++) for (S32 i = 0; i < mCargoIDs.size(); i++)
{ {
LLInventoryItem* item = (LLInventoryItem*)obj->getInventoryObject(mCargoIDs[i]); LLInventoryItem* item = (LLInventoryItem*)obj->getInventoryObject(mCargoIDs[i]);
if (item) if (item)

View File

@@ -33,10 +33,10 @@
#ifndef LL_TOOLDRAGANDDROP_H #ifndef LL_TOOLDRAGANDDROP_H
#define LL_TOOLDRAGANDDROP_H #define LL_TOOLDRAGANDDROP_H
#include "lldictionary.h"
#include "lltool.h" #include "lltool.h"
#include "llview.h" #include "llview.h"
#include "lluuid.h" #include "lluuid.h"
#include "stdenums.h"
#include "llassetstorage.h" #include "llassetstorage.h"
#include "llpermissions.h" #include "llpermissions.h"
#include "llwindow.h" #include "llwindow.h"
@@ -50,6 +50,8 @@ class LLPickInfo;
class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop> class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
{ {
public: public:
typedef boost::signals2::signal<void ()> enddrag_signal_t;
LLToolDragAndDrop(); LLToolDragAndDrop();
// overridden from LLTool // overridden from LLTool
@@ -68,7 +70,9 @@ public:
SOURCE_AGENT, SOURCE_AGENT,
SOURCE_WORLD, SOURCE_WORLD,
SOURCE_NOTECARD, SOURCE_NOTECARD,
SOURCE_LIBRARY SOURCE_LIBRARY,
SOURCE_VIEWER,
SOURCE_PEOPLE
}; };
void beginDrag(EDragAndDropType type, void beginDrag(EDragAndDropType type,
@@ -86,9 +90,22 @@ public:
const LLUUID& getObjectID() const { return mObjectID; } const LLUUID& getObjectID() const { return mObjectID; }
EAcceptance getLastAccept() { return mLastAccept; } EAcceptance getLastAccept() { return mLastAccept; }
uuid_vec_t::size_type getCargoIDsCount() const { return mCargoIDs.size(); } boost::signals2::connection setEndDragCallback( const enddrag_signal_t::slot_type& cb ) { return mEndDragSignal.connect(cb); }
void setCargoCount(U32 count) { mCargoCount = count; }
void resetCargoCount() { mCargoCount = 0; }
U32 getCargoCount() const { return (mCargoCount > 0) ? mCargoCount : mCargoIDs.size(); }
S32 getCargoIndex() const { return mCurItemIndex; }
static S32 getOperationId() { return sOperationId; } static S32 getOperationId() { return sOperationId; }
// deal with permissions of object, etc. returns TRUE if drop can
// proceed, otherwise FALSE.
static BOOL handleDropTextureProtections(LLViewerObject* hit_obj,
LLInventoryItem* item,
LLToolDragAndDrop::ESource source,
const LLUUID& src_id);
protected: protected:
enum EDropTarget enum EDropTarget
{ {
@@ -100,6 +117,7 @@ protected:
DT_COUNT = 5 DT_COUNT = 5
}; };
protected:
// dragOrDrop3dImpl points to a member of LLToolDragAndDrop that // dragOrDrop3dImpl points to a member of LLToolDragAndDrop that
// takes parameters (LLViewerObject* obj, S32 face, MASK, BOOL // takes parameters (LLViewerObject* obj, S32 face, MASK, BOOL
// drop) and returns a BOOL if drop is ok // drop) and returns a BOOL if drop is ok
@@ -110,11 +128,14 @@ protected:
EAcceptance* acceptance); EAcceptance* acceptance);
void dragOrDrop3D(S32 x, S32 y, MASK mask, BOOL drop, void dragOrDrop3D(S32 x, S32 y, MASK mask, BOOL drop,
EAcceptance* acceptance); EAcceptance* acceptance);
static void pickCallback(const LLPickInfo& pick_info); static void pickCallback(const LLPickInfo& pick_info);
void pick(const LLPickInfo& pick_info); void pick(const LLPickInfo& pick_info);
protected: protected:
U32 mCargoCount;
S32 mDragStartX; S32 mDragStartX;
S32 mDragStartY; S32 mDragStartY;
@@ -135,6 +156,9 @@ protected:
BOOL mDrop; BOOL mDrop;
S32 mCurItemIndex; S32 mCurItemIndex;
std::string mToolTipMsg; std::string mToolTipMsg;
std::string mCustomMsg;
enddrag_signal_t mEndDragSignal;
protected: protected:
// 3d drop functions. these call down into the static functions // 3d drop functions. these call down into the static functions
@@ -209,13 +233,6 @@ protected:
// inventory items to determine if a drop would be ok. // inventory items to determine if a drop would be ok.
static EAcceptance willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item); static EAcceptance willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item);
// deal with permissions of object, etc. returns TRUE if drop can
// proceed, otherwise FALSE.
static BOOL handleDropTextureProtections(LLViewerObject* hit_obj,
LLInventoryItem* item,
LLToolDragAndDrop::ESource source,
const LLUUID& src_id);
public: public:
// helper functions // helper functions
static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); } static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); }
@@ -253,7 +270,8 @@ public:
static bool handleGiveDragAndDrop(LLUUID agent, LLUUID session, BOOL drop, static bool handleGiveDragAndDrop(LLUUID agent, LLUUID session, BOOL drop,
EDragAndDropType cargo_type, EDragAndDropType cargo_type,
void* cargo_data, void* cargo_data,
EAcceptance* accept); EAcceptance* accept,
const LLSD& dest = LLSD());
// Classes used for determining 3d drag and drop types. // Classes used for determining 3d drag and drop types.
private: private:

View File

@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h" #include "llviewerprecompiledheaders.h"
#include "llviewerfoldertype.h" #include "llviewerfoldertype.h"
#include "llcontrol.h"
#include "lldictionary.h" #include "lldictionary.h"
#include "llmemory.h" #include "llmemory.h"
#include "llvisualparam.h" #include "llvisualparam.h"

View File

@@ -811,8 +811,13 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const
bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item) bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item)
{ {
bool accept = true; if (!inv_item)
{
return false;
}
// Only stock folders have limitation on which item they will accept // Only stock folders have limitation on which item they will accept
bool accept = true;
if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)
{ {
// If the item is copyable (i.e. non stock) do not accept the drop in a stock folder // If the item is copyable (i.e. non stock) do not accept the drop in a stock folder

View File

@@ -620,8 +620,10 @@ void check_merchant_status()
{ {
if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth"))
{ {
// Hide both merchant related menu items // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status()
gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(FALSE); LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED);
// Hide SLM related menu item
gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(FALSE); gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(FALSE);
// Also disable the toolbar button for Marketplace Listings // Also disable the toolbar button for Marketplace Listings
@@ -630,9 +632,16 @@ void check_merchant_status()
// Launch an SLM test connection to get the merchant status // Launch an SLM test connection to get the merchant status
LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu));
// Launch a Merchant Outbox test connection to get the migration status // Do the Merchant Outbox init only once per session
LLMarketplaceInventoryImporter::instance().setStatusReportCallback(boost::bind(&set_merchant_outbox_menu, _1, _2)); if (LLMarketplaceInventoryImporter::instance().getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
LLMarketplaceInventoryImporter::instance().initialize(); {
// Hide merchant outbox related menu item
gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(FALSE);
// Launch a Merchant Outbox test connection to get the migration status
LLMarketplaceInventoryImporter::instance().setStatusReportCallback(boost::bind(&set_merchant_outbox_menu, _1, _2));
LLMarketplaceInventoryImporter::instance().initialize();
}
} }
} }
@@ -8866,16 +8875,6 @@ class LLWorldEnableEnvSettings : public view_listener_t
} }
}; };
bool canAccessMarketplace();
class LLMarketplaceEnabled : public LLMemberListener<LLView>
{
bool handleEvent(LLPointer<LLOldEvents::LLEvent>, const LLSD& userdata)
{
gMenuHolder->findControl(userdata["control"].asString())->setValue(canAccessMarketplace());
return true;
}
};
class SinguCloseAllDialogs : public view_listener_t class SinguCloseAllDialogs : public view_listener_t
{ {
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
@@ -9439,7 +9438,6 @@ void initialize_menus()
addMenu(new LLWorldVisibleDestinations(), "World.VisibleDestinations"); addMenu(new LLWorldVisibleDestinations(), "World.VisibleDestinations");
(new LLWorldEnvSettings())->registerListener(gMenuHolder, "World.EnvSettings"); (new LLWorldEnvSettings())->registerListener(gMenuHolder, "World.EnvSettings");
(new LLWorldEnableEnvSettings())->registerListener(gMenuHolder, "World.EnableEnvSettings"); (new LLWorldEnableEnvSettings())->registerListener(gMenuHolder, "World.EnableEnvSettings");
addMenu(new LLMarketplaceEnabled, "Marketplace.Enabled");
// Tools menu // Tools menu

View File

@@ -164,7 +164,7 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
mScreenp(NULL), mScreenp(NULL),
mLastRegionHandle(0), mLastRegionHandle(0),
mRegionCrossingCount(0), mRegionCrossingCount(0),
mInitialBakesLoaded(false), //mInitialBakesLoaded(false),
// Value outside legal range, so will always be a mismatch the // Value outside legal range, so will always be a mismatch the
// first time through. // first time through.
mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)) mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f))

View File

@@ -120,7 +120,7 @@ private:
private: private:
LLUUID mInitialBakeIDs[6]; LLUUID mInitialBakeIDs[6];
bool mInitialBakesLoaded; //bool mInitialBakesLoaded;
/******************************************************************************** /********************************************************************************

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

View File

@@ -434,4 +434,6 @@ with the same filename but different name
<texture name="icn_slide-thumb_dark.tga" scale.left="2" scale.top="5" scale.right="29" scale.bottom="4"/> <texture name="icn_slide-thumb_dark.tga" scale.left="2" scale.top="5" scale.right="29" scale.bottom="4"/>
<texture name="map_avatar_you_8.tga"/> <texture name="map_avatar_you_8.tga"/>
<texture name="icon_avatar_expand.png" preload="true" /> <texture name="icon_avatar_expand.png" preload="true" />
<texture name="Marketplace_Dropzone_Background" file_name="Marketplace_Dropzone_Background.png" preload="true" />
</textures> </textures>

View File

@@ -13,7 +13,6 @@
save_rect="true" save_rect="true"
save_visibility="false" save_visibility="false"
reuse_instance="true"> reuse_instance="true">
<string name="MarketplaceListingsInitializing">Initializing...</string>
<panel <panel
name="marketplace_listings_panel" name="marketplace_listings_panel"
follows="all" follows="all"

View File

@@ -11,16 +11,16 @@
name="Marketplace Associate Listing"> name="Marketplace Associate Listing">
<on_click function="Inventory.DoToSelected" userdata="marketplace_associate_listing"/> <on_click function="Inventory.DoToSelected" userdata="marketplace_associate_listing"/>
</menu_item_call> </menu_item_call>
<menu_item_call
label="Unassociate listing"
name="Marketplace Disassociate Listing">
<on_click function="Inventory.DoToSelected" userdata="marketplace_disassociate_listing"/>
</menu_item_call>
<menu_item_call <menu_item_call
label="Get (Refresh) listing" label="Get (Refresh) listing"
name="Marketplace Get Listing"> name="Marketplace Get Listing">
<on_click function="Inventory.DoToSelected" userdata="marketplace_get_listing"/> <on_click function="Inventory.DoToSelected" userdata="marketplace_get_listing"/>
</menu_item_call> </menu_item_call>
<menu_item_call
label="Check for errors"
name="Marketplace Check Listing">
<on_click function="Inventory.DoToSelected" userdata="marketplace_check_listing"/>
</menu_item_call>
<menu_item_call <menu_item_call
label="Edit listing" label="Edit listing"
name="Marketplace Edit Listing"> name="Marketplace Edit Listing">
@@ -396,6 +396,12 @@
name="Merchant Copy" width="128"> name="Merchant Copy" width="128">
<on_click filter="" function="Inventory.DoToSelected" userdata="copy_to_outbox" /> <on_click filter="" function="Inventory.DoToSelected" userdata="copy_to_outbox" />
</menu_item_call> </menu_item_call>
<menu_item_call label="Copy to Marketplace Listings" name="Marketplace Copy">
<on_click function="Inventory.DoToSelected" userdata="copy_to_marketplace_listings" />
</menu_item_call>
<menu_item_call label="Move to Marketplace Listings" name="Marketplace Move">
<on_click function="Inventory.DoToSelected" userdata="move_to_marketplace_listings" />
</menu_item_call>
<!-- Singu TODO: Remove Marketplace Send when removing Outbox --> <!-- Singu TODO: Remove Marketplace Send when removing Outbox -->
<menu_item_call bottom_delta="-18" height="18" label="Send to Marketplace" left="0" mouse_opaque="true" <menu_item_call bottom_delta="-18" height="18" label="Send to Marketplace" left="0" mouse_opaque="true"
name="Marketplace Send" width="128"> name="Marketplace Send" width="128">

View File

@@ -4,13 +4,45 @@
left="0" bottom="0" visible="false" left="0" bottom="0" visible="false"
mouse_opaque="false"> mouse_opaque="false">
<menu_item_check <menu_item_check
label="Sort by stock amount (low to high)" label="Sort by name"
name="sort_by_stock_amount"> name="sort_by_name">
<menu_item_check.on_click <menu_item_check.on_click
function="Marketplace.ViewSort.Action" function="Marketplace.ViewSort.Action"
parameter="sort_by_stock_amount"/> parameter="sort_by_name" />
<menu_item_check.on_check <menu_item_check.on_check
function="Marketplace.ViewSort.CheckItem" function="Marketplace.ViewSort.CheckItem"
parameter="sort_by_stock_amount"/> parameter="sort_by_name" />
</menu_item_check>
<menu_item_check
label="Sort by most recent"
name="sort_by_recent">
<menu_item_check.on_click
function="Marketplace.ViewSort.Action"
parameter="sort_by_recent" />
<menu_item_check.on_check
function="Marketplace.ViewSort.CheckItem"
parameter="sort_by_recent" />
</menu_item_check>
<menu_item_check
label="Sort by stock amount (low to high)"
name="sort_by_stock_amount">
<menu_item_check.on_click
function="Marketplace.ViewSort.Action"
parameter="sort_by_stock_amount"/>
<menu_item_check.on_check
function="Marketplace.ViewSort.CheckItem"
parameter="sort_by_stock_amount"/>
</menu_item_check>
<menu_item_separator
layout="topleft" />
<menu_item_check
label="Show only listing folders"
name="show_only_listing_folders">
<menu_item_check.on_click
function="Marketplace.ViewSort.Action"
parameter="show_only_listing_folders"/>
<menu_item_check.on_check
function="Marketplace.ViewSort.CheckItem"
parameter="show_only_listing_folders"/>
</menu_item_check> </menu_item_check>
</toggleable_menu> </toggleable_menu>

File diff suppressed because it is too large Load Diff

View File

@@ -56,7 +56,7 @@
layout="topleft" layout="topleft"
default_tab_group="1" default_tab_group="1"
width="308" width="308"
height="400"> height="350">
<filter_editor <filter_editor
text_pad_left="10" text_pad_left="10"
follows="left|top|right" follows="left|top|right"
@@ -76,7 +76,7 @@
left="0" left="0"
top_pad="0" top_pad="0"
width="308" width="308"
height="370" height="320"
halign="center" halign="center"
tab_height="30" tab_height="30"
tab_group="1" tab_group="1"
@@ -84,4 +84,34 @@
tab_min_width="50"> tab_min_width="50">
</tab_container> </tab_container>
</panel> </panel>
</panel> <panel
name="marketplace_drop_zone"
mouse_opaque="false"
follows="bottom|left|right"
left="2"
width="306"
height="40"
background_visible="true"
background_opaque="true"
bg_alpha_image="none"
bg_alpha_color="0.38, 0.694, 0.573, 0.35"
bg_opaque_image="Marketplace_Dropzone_Background"
border="true"
bevel_style="in"
visible="true">
<text
type="string"
follows="bottom|left|right"
layout="topleft"
top="13"
height="20"
left="2"
width="306"
halign="center"
font="SansSerifMedium"
font_shadow="hard"
valign="top">
Drop folders here to creat4e new listings
</text>
</panel>
</panel>

View File

@@ -11,7 +11,8 @@
left="0" left="0"
start_folder.name="Marketplace listings" start_folder.name="Marketplace listings"
show_empty_message="true" show_empty_message="true"
show_root_folder="true" show_root_folder="false"
use_marketplace_folders="true"
start_folder.type="merchant" start_folder.type="merchant"
tool_tip="Drag and drop items here to list them" tool_tip="Drag and drop items here to list them"
bg_opaque_color="DkGray2" bg_opaque_color="DkGray2"

View File

@@ -10,7 +10,8 @@
left_delta="0" left_delta="0"
start_folder.name="Marketplace listings" start_folder.name="Marketplace listings"
show_empty_message="true" show_empty_message="true"
show_root_folder="true" show_root_folder="false"
use_marketplace_folders="true"
allow_drop_on_root="false" allow_drop_on_root="false"
start_folder.type="merchant" start_folder.type="merchant"
bg_opaque_color="DkGray2" bg_opaque_color="DkGray2"

View File

@@ -10,7 +10,8 @@
left_delta="0" left_delta="0"
start_folder.name="Marketplace listings" start_folder.name="Marketplace listings"
show_empty_message="true" show_empty_message="true"
show_root_folder="true" show_root_folder="false"
use_marketplace_folders="true"
start_folder.type="merchant" start_folder.type="merchant"
bg_opaque_color="DkGray2" bg_opaque_color="DkGray2"
bg_alpha_color="DkGray2" bg_alpha_color="DkGray2"

View File

@@ -10,7 +10,8 @@
left_delta="0" left_delta="0"
start_folder.name="Marketplace listings" start_folder.name="Marketplace listings"
show_empty_message="true" show_empty_message="true"
show_root_folder="true" show_root_folder="false"
use_marketplace_folders="true"
allow_drop_on_root="false" allow_drop_on_root="false"
start_folder.type="merchant" start_folder.type="merchant"
bg_opaque_color="DkGray2" bg_opaque_color="DkGray2"

View File

@@ -12,6 +12,8 @@
bevel_style="none" bevel_style="none"
show_item_link_overlays="true" show_item_link_overlays="true"
tool_tip="Drag and drop items here to prepare them for sale on your storefront" tool_tip="Drag and drop items here to prepare them for sale on your storefront"
allow_open="false"
allow_drop_on_root="false"
> >
<scroll reserve_scroll_corner="false" /> <scroll reserve_scroll_corner="false" />
</outbox_inventory_panel> </outbox_inventory_panel>

View File

@@ -109,17 +109,18 @@ Make sure you entered the correct Login URI. An example of a Login URI is: \"htt
<string name="TooltipLand">Land:</string> <string name="TooltipLand">Land:</string>
<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string> <string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>
<string name="TooltipOutboxDragToWorld">You can not rez items on the marketplace</string> <string name="TooltipOutboxDragToWorld">You can not rez items from the Marketplace Listings folder</string>
<string name="TooltipOutboxWorn">You can't put items you are wearing in the Marketplace Listings folder</string>
<string name="TooltipOutboxFolderLevels">Depth of nested folders exceeds [AMOUNT]. Decrease the depth of folders-within-folders; box items if necessary.</string>
<string name="TooltipOutboxTooManyFolders">Subfolder count exceeds [AMOUNT]. Decrease the number of folders in your listing; box items if necessary.</string>
<string name="TooltipOutboxTooManyObjects">Item count exceeds [AMOUNT]. In order to sell more than [AMOUNT] items in one listing, you must box some of them.</string>
<string name="TooltipOutboxTooManyStockItems">Stock items count exceeds [AMOUNT].</string>
<string name="TooltipOutboxCannotDropOnRoot">You can only drop items or folders in the ALL or UNASSOCIATED tabs. Please select that tab and move your item(s) or folder(s) again.</string>
<string name="TooltipOutboxNoTransfer">One or more of these objects cannot be sold or transferred</string> <string name="TooltipOutboxNoTransfer">One or more of these objects cannot be sold or transferred</string>
<string name="TooltipOutboxNotInInventory">You can only put items from your inventory on the marketplace</string> <string name="TooltipOutboxNotInInventory">You can only put items from your inventory on the marketplace</string>
<string name="TooltipOutboxWorn">You can't put items you are wearing on the marketplace</string>
<string name="TooltipOutboxLinked">You can't put linked items or folders on the marketplace</string> <string name="TooltipOutboxLinked">You can't put linked items or folders on the marketplace</string>
<string name="TooltipOutboxCallingCard">You can't put calling cards on the marketplace</string> <string name="TooltipOutboxCallingCard">You can't put calling cards on the marketplace</string>
<string name="TooltipOutboxFolderLevels">Depth of nested folders exceeds [AMOUNT]</string>
<string name="TooltipOutboxTooManyFolders">Subfolder count exceeds [AMOUNT]</string>
<string name="TooltipOutboxTooManyObjects">Item count exceeds [AMOUNT]</string>
<string name="TooltipOutboxDragActive">You can't move a listed listing</string> <string name="TooltipOutboxDragActive">You can't move a listed listing</string>
<string name="TooltipOutboxCannotDropOnRoot">You can't drop items on filtered tabs root</string>
<string name="TooltipOutboxCannotMoveRoot">You can't move the marketplace listings root folder</string> <string name="TooltipOutboxCannotMoveRoot">You can't move the marketplace listings root folder</string>
<string name="TooltipOutboxMixedStock">All items in a stock folder must have the same type and permission</string> <string name="TooltipOutboxMixedStock">All items in a stock folder must have the same type and permission</string>
@@ -3213,6 +3214,9 @@ The
</string> </string>
<string name="InventoryOutboxErrorSubs">Marketplace store</string> <string name="InventoryOutboxErrorSubs">Marketplace store</string>
<string name="InventoryOutboxError2">is returning errors.</string> <string name="InventoryOutboxError2">is returning errors.</string>
<string name="InventoryMarketplaceError">
This feature is currently in Beta. Please add your name to this [http://goo.gl/forms/FCQ7UXkakz Google form] if you would like to participate.
</string>
<string name="InventoryMarketplaceListingsNoItemsTitle">Your Marketplace Listings folder is empty.</string> <string name="InventoryMarketplaceListingsNoItemsTitle">Your Marketplace Listings folder is empty.</string>
<string name="InventoryMarketplaceListingsNoItemsTooltip"></string> <string name="InventoryMarketplaceListingsNoItemsTooltip"></string>
<string name="InventoryMarketplaceListingsNoItems"> <string name="InventoryMarketplaceListingsNoItems">
@@ -3234,6 +3238,8 @@ The
<string name="Marketplace Validation Warning">: Warning: </string> <string name="Marketplace Validation Warning">: Warning: </string>
<string name="Marketplace Validation Error Empty Version">: Warning: version folder must contain at least 1 item</string> <string name="Marketplace Validation Error Empty Version">: Warning: version folder must contain at least 1 item</string>
<string name="Marketplace Validation Error Empty Stock">: Warning: stock folder must contain at least 1 item</string> <string name="Marketplace Validation Error Empty Stock">: Warning: stock folder must contain at least 1 item</string>
<string name="Marketplace Validation No Error">No errors or warnings to report</string>
<string name="Marketplace Error None">No errors</string> <string name="Marketplace Error None">No errors</string>
<string name="Marketplace Error Prefix">Error: </string> <string name="Marketplace Error Prefix">Error: </string>
<string name="Marketplace Error Not Merchant">Before sending items to the Marketplace you will need to set yourself up as a merchant (free of charge).</string> <string name="Marketplace Error Not Merchant">Before sending items to the Marketplace you will need to set yourself up as a merchant (free of charge).</string>