summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rwxr-xr-xindra/llcommon/llfoldertype.cpp2
-rw-r--r--indra/llcommon/llfoldertype.h2
-rwxr-xr-xindra/newview/llfloateroutbox.cpp524
-rwxr-xr-xindra/newview/llfloateroutbox.h71
-rwxr-xr-xindra/newview/llinventorybridge.cpp64
-rwxr-xr-xindra/newview/llinventorybridge.h4
-rwxr-xr-xindra/newview/llinventoryfilter.cpp42
-rwxr-xr-xindra/newview/llinventoryfilter.h11
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp10
-rwxr-xr-xindra/newview/llinventoryfunctions.h3
-rwxr-xr-xindra/newview/llinventorypanel.cpp2
-rwxr-xr-xindra/newview/llmarketplacefunctions.cpp119
-rwxr-xr-xindra/newview/llmarketplacefunctions.h57
-rwxr-xr-xindra/newview/llviewerfloaterreg.cpp1
-rw-r--r--indra/newview/llviewerfoldertype.cpp2
-rwxr-xr-xindra/newview/skins/default/xui/en/floater_marketplace_listings.xml107
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_marketplace_view.xml49
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml7
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_marketplace_listings.xml138
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml8
20 files changed, 1216 insertions, 7 deletions
diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp
index 9c38349cf7..5b80189d2a 100755
--- a/indra/llcommon/llfoldertype.cpp
+++ b/indra/llcommon/llfoldertype.cpp
@@ -96,6 +96,8 @@ LLFolderDictionary::LLFolderDictionary()
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", FALSE));
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
+
+ addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", FALSE));
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
};
diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h
index a0c847914f..91dc1da543 100644
--- a/indra/llcommon/llfoldertype.h
+++ b/indra/llcommon/llfoldertype.h
@@ -87,6 +87,8 @@ public:
FT_BASIC_ROOT = 52,
+ FT_MARKETPLACE_LISTINGS = 53,
+
FT_COUNT,
FT_NONE = -1
diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp
index de96f75602..9ea83e9621 100755
--- a/indra/newview/llfloateroutbox.cpp
+++ b/indra/newview/llfloateroutbox.cpp
@@ -1,6 +1,8 @@
/**
* @file llfloateroutbox.cpp
- * @brief Implementation of the merchant outbox window
+ * @brief Implementation of the merchant outbox window and of the marketplace listings window
+ *
+ * *TODO : Eventually, take out all the merchant outbox stuff and rename that file to llfloatermarketplacelistings
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -105,6 +107,39 @@ private:
};
///----------------------------------------------------------------------------
+/// LLMarketplaceListingsAddedObserver helper class
+///----------------------------------------------------------------------------
+
+class LLMarketplaceListingsAddedObserver : public LLInventoryCategoryAddedObserver
+{
+public:
+ LLMarketplaceListingsAddedObserver(LLFloaterMarketplaceListings * marketplace_listings_floater)
+ : LLInventoryCategoryAddedObserver()
+ , mMarketplaceListingsFloater(marketplace_listings_floater)
+ {
+ }
+
+ void done()
+ {
+ for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it)
+ {
+ LLViewerInventoryCategory* added_category = *it;
+
+ LLFolderType::EType added_category_type = added_category->getPreferredType();
+
+ if (added_category_type == LLFolderType::FT_MARKETPLACE_LISTINGS)
+ {
+ mMarketplaceListingsFloater->initializeMarketPlace();
+ }
+ }
+ }
+
+private:
+ LLFloaterMarketplaceListings * mMarketplaceListingsFloater;
+};
+
+
+///----------------------------------------------------------------------------
/// LLFloaterOutbox
///----------------------------------------------------------------------------
@@ -617,3 +652,490 @@ void LLFloaterOutbox::showNotification(const LLNotificationPtr& notification)
notification_handler->processNotification(notification);
}
+///----------------------------------------------------------------------------
+/// LLFloaterMarketplaceListings
+///----------------------------------------------------------------------------
+
+LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key)
+: LLFloater(key)
+, mCategoriesObserver(NULL)
+, mCategoryAddedObserver(NULL)
+, mRootFolderId(LLUUID::null)
+, mInventoryStatus(NULL)
+, mInventoryInitializationInProgress(NULL)
+, mInventoryPlaceholder(NULL)
+, mInventoryText(NULL)
+, mInventoryTitle(NULL)
+, mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME)
+, mFilterType(LLInventoryFilter::FILTERTYPE_NONE)
+{
+ mCommitCallbackRegistrar.add("Marketplace.ViewSort.Action", boost::bind(&LLFloaterMarketplaceListings::onViewSortMenuItemClicked, this, _2));
+ mEnableCallbackRegistrar.add("Marketplace.ViewSort.CheckItem", boost::bind(&LLFloaterMarketplaceListings::onViewSortMenuItemCheck, this, _2));
+}
+
+LLFloaterMarketplaceListings::~LLFloaterMarketplaceListings()
+{
+ if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ }
+ delete mCategoriesObserver;
+
+ if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
+ {
+ gInventory.removeObserver(mCategoryAddedObserver);
+ }
+ delete mCategoryAddedObserver;
+}
+
+BOOL LLFloaterMarketplaceListings::postBuild()
+{
+ mInventoryStatus = getChild<LLTextBox>("marketplace_status");
+ mInventoryInitializationInProgress = getChild<LLView>("initialization_progress_indicator");
+ mInventoryPlaceholder = getChild<LLView>("marketplace_listings_inventory_placeholder_panel");
+ mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("marketplace_listings_inventory_placeholder_text");
+ mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("marketplace_listings_inventory_placeholder_title");
+
+ LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterMarketplaceListings::onFocusReceived, this));
+
+ // Observe category creation to catch marketplace listings creation (moot if already existing)
+ mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this);
+ gInventory.addObserver(mCategoryAddedObserver);
+
+ // Merov : Debug : fetch aggressively so we can create test data right onOpen()
+ llinfos << "Merov : postBuild, do fetchContent() ahead of time" << llendl;
+ fetchContents();
+
+ return TRUE;
+}
+
+void LLFloaterMarketplaceListings::clean()
+{
+ // Note: we cannot delete the mOutboxInventoryPanel as that point
+ // as this is called through callback observers of the panel itself.
+ // Doing so would crash rapidly.
+
+ // Invalidate the outbox data
+ mRootFolderId.setNull();
+}
+
+void LLFloaterMarketplaceListings::onClose(bool app_quitting)
+{
+}
+
+void LLFloaterMarketplaceListings::onOpen(const LLSD& key)
+{
+ //
+ // Initialize the Market Place or go update the outbox
+ //
+ if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
+ {
+ initializeMarketPlace();
+ }
+ else
+ {
+ setup();
+ }
+
+ // Merov : Debug : Create fake Marketplace data if none is present
+ if (LLMarketplaceData::instance().isEmpty() && (getFolderCount() > 0))
+ {
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(mRootFolderId, cats, items);
+
+ int index = 0;
+ for (LLInventoryModel::cat_array_t::iterator iter = cats->begin(); iter != cats->end(); iter++, index++)
+ {
+ LLViewerInventoryCategory* category = *iter;
+ if (index%3)
+ {
+ LLMarketplaceData::instance().addTestItem(category->getUUID());
+ if (index%3 == 1)
+ {
+ LLMarketplaceData::instance().setListingID(category->getUUID(),"TestingID1234");
+ }
+ LLMarketplaceData::instance().setActivation(category->getUUID(),(index%2));
+ }
+ }
+ }
+
+ //
+ // Update the floater view
+ //
+ updateView();
+
+ //
+ // Trigger fetch of the contents
+ //
+ fetchContents();
+}
+
+void LLFloaterMarketplaceListings::onFocusReceived()
+{
+ fetchContents();
+}
+
+
+void LLFloaterMarketplaceListings::onViewSortMenuItemClicked(const LLSD& userdata)
+{
+ std::string chosen_item = userdata.asString();
+
+ LLInventoryPanel* panel = mInventoryPanel.get();
+
+ llinfos << "Merov : MenuItemClicked, item = " << chosen_item << ", panel on = " << panel->hasFocus() << llendl;
+
+ // Sort options
+ if (chosen_item == "sort_by_stock_amount")
+ {
+ mSortOrder = (mSortOrder == LLInventoryFilter::SO_FOLDERS_BY_NAME ? LLInventoryFilter::SO_FOLDERS_BY_WEIGHT : LLInventoryFilter::SO_FOLDERS_BY_NAME);
+ panel->getFolderViewModel()->setSorter(mSortOrder);
+ }
+ // View/filter options
+ else if (chosen_item == "show_all")
+ {
+ mFilterType = LLInventoryFilter::FILTERTYPE_NONE;
+ panel->getFilter().resetDefault();
+ }
+ else if (chosen_item == "show_non_associated_listings")
+ {
+ mFilterType = LLInventoryFilter::FILTERTYPE_MARKETPLACE_UNASSOCIATED;
+ panel->getFilter().setFilterMarketplaceUnassociatedFolders();
+ }
+ else if (chosen_item == "show_active")
+ {
+ mFilterType = LLInventoryFilter::FILTERTYPE_MARKETPLACE_ACTIVE;
+ panel->getFilter().setFilterMarketplaceActiveFolders();
+ }
+ else if (chosen_item == "show_inactive_listings")
+ {
+ mFilterType = LLInventoryFilter::FILTERTYPE_MARKETPLACE_INACTIVE;
+ panel->getFilter().setFilterMarketplaceInactiveFolders();
+ }
+}
+
+bool LLFloaterMarketplaceListings::onViewSortMenuItemCheck(const LLSD& userdata)
+{
+ std::string chosen_item = userdata.asString();
+
+ LLInventoryPanel* panel = mInventoryPanel.get();
+
+ llinfos << "Merov : MenuItemCheck, item = " << chosen_item << ", panel on = " << panel->hasFocus() << llendl;
+
+ if (!panel->hasFocus())
+ {
+ return false;
+ }
+
+ if (chosen_item == "sort_by_stock_amount")
+ return mSortOrder == LLInventoryFilter::SO_FOLDERS_BY_WEIGHT;
+ if (chosen_item == "show_all")
+ return mFilterType == LLInventoryFilter::FILTERTYPE_NONE;
+ if (chosen_item == "show_non_associated_listings")
+ return mFilterType == LLInventoryFilter::FILTERTYPE_MARKETPLACE_UNASSOCIATED;
+ if (chosen_item == "show_active")
+ return mFilterType == LLInventoryFilter::FILTERTYPE_MARKETPLACE_ACTIVE;
+ if (chosen_item == "show_inactive_listings")
+ return mFilterType == LLInventoryFilter::FILTERTYPE_MARKETPLACE_INACTIVE;
+ return false;
+}
+
+
+void LLFloaterMarketplaceListings::fetchContents()
+{
+ if (mRootFolderId.notNull())
+ {
+ LLInventoryModelBackgroundFetch::instance().start(mRootFolderId);
+ }
+}
+
+void LLFloaterMarketplaceListings::setup()
+{
+ if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT)
+ {
+ // If we are *not* a merchant or we have no market place connection established yet, do nothing
+ return;
+ }
+
+ // We are a merchant. Get the Marketplace listings folder, create it if needs be.
+ LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true);
+ if (outbox_id.isNull())
+ {
+ // We should never get there unless the inventory fails badly
+ llinfos << "Merov : Inventory problem: failure to create the marketplace listings folder for a merchant!" << llendl;
+ llerrs << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << llendl;
+ return;
+ }
+
+ // Consolidate Marketplace listings
+ // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, things get messy and conventions get broken down eventually
+ gInventory.consolidateForType(outbox_id, LLFolderType::FT_MARKETPLACE_LISTINGS);
+
+ if (outbox_id == mRootFolderId)
+ {
+ llinfos << "Merov : Inventory warning: Marketplace listings folder already set" << llendl;
+ llwarns << "Inventory warning: Marketplace listings folder already set" << llendl;
+ return;
+ }
+ mRootFolderId = outbox_id;
+
+ // No longer need to observe new category creation
+ if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
+ {
+ gInventory.removeObserver(mCategoryAddedObserver);
+ delete mCategoryAddedObserver;
+ mCategoryAddedObserver = NULL;
+ }
+ llassert(!mCategoryAddedObserver);
+
+ // Create observer for marketplace listings modifications : clear the old one and create a new one
+ if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
+ {
+ gInventory.removeObserver(mCategoriesObserver);
+ delete mCategoriesObserver;
+ }
+ mCategoriesObserver = new LLInventoryCategoriesObserver();
+ gInventory.addObserver(mCategoriesObserver);
+ mCategoriesObserver->addCategory(mRootFolderId, boost::bind(&LLFloaterMarketplaceListings::onChanged, this));
+ llassert(mCategoriesObserver);
+
+ // Set up the marketplace listings inventory view
+ LLPanel* inventory_panel = LLUICtrlFactory::createFromFile<LLPanel>("panel_marketplace_listings.xml", mInventoryPlaceholder->getParent(), LLInventoryPanel::child_registry_t::instance());
+ LLInventoryPanel* items_panel = inventory_panel->getChild<LLInventoryPanel>("All Items");
+ mInventoryPanel = items_panel->getInventoryPanelHandle();
+ llassert(mInventoryPanel.get() != NULL);
+
+ // Reshape the inventory to the proper size
+ LLRect inventory_placeholder_rect = mInventoryPlaceholder->getRect();
+ inventory_panel->setShape(inventory_placeholder_rect);
+
+ // Set the sort order newest to oldest
+ items_panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME);
+ items_panel->getFilter().markDefault();
+
+ // Set filters on the 3 prefiltered panels
+ items_panel = inventory_panel->getChild<LLInventoryPanel>("Active Items");
+ items_panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME);
+ items_panel->getFilter().setFilterMarketplaceActiveFolders();
+ items_panel->getFilter().markDefault();
+ items_panel = inventory_panel->getChild<LLInventoryPanel>("Inactive Items");
+ items_panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME);
+ items_panel->getFilter().setFilterMarketplaceInactiveFolders();
+ items_panel->getFilter().markDefault();
+ items_panel = inventory_panel->getChild<LLInventoryPanel>("Unassociated Items");
+ items_panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME);
+ items_panel->getFilter().setFilterMarketplaceUnassociatedFolders();
+ items_panel->getFilter().markDefault();
+
+ // Get the content of the marketplace listings folder
+ fetchContents();
+}
+
+void LLFloaterMarketplaceListings::initializeMarketPlace()
+{
+ //
+ // Initialize the marketplace import API
+ //
+ LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance();
+
+ if (!importer.isInitialized())
+ {
+ importer.setInitializationErrorCallback(boost::bind(&LLFloaterMarketplaceListings::initializationReportError, this, _1, _2));
+ importer.setStatusChangedCallback(boost::bind(&LLFloaterMarketplaceListings::importStatusChanged, this, _1));
+ importer.setStatusReportCallback(boost::bind(&LLFloaterMarketplaceListings::importReportResults, this, _1, _2));
+ importer.initialize();
+ }
+}
+
+S32 LLFloaterMarketplaceListings::getFolderCount()
+{
+ if (mInventoryPanel.get() && mRootFolderId.notNull())
+ {
+ LLInventoryModel::cat_array_t * cats;
+ LLInventoryModel::item_array_t * items;
+ gInventory.getDirectDescendentsOf(mRootFolderId, cats, items);
+
+ return (cats->count() + items->count());
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void LLFloaterMarketplaceListings::setStatusString(const std::string& statusString)
+{
+ mInventoryStatus->setText(statusString);
+}
+
+void LLFloaterMarketplaceListings::updateView()
+{
+ LLInventoryPanel* panel = mInventoryPanel.get();
+
+ if (getFolderCount() > 0)
+ {
+ panel->setVisible(TRUE);
+ mInventoryPlaceholder->setVisible(FALSE);
+ }
+ else
+ {
+ if (panel)
+ {
+ panel->setVisible(FALSE);
+ }
+
+ std::string text;
+ std::string title;
+ std::string tooltip;
+
+ const LLSD& subs = getMarketplaceStringSubstitutions();
+ U32 mkt_status = LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus();
+
+ // *TODO : check those messages and create better appropriate ones in strings.xml
+ if (mRootFolderId.notNull())
+ {
+ // Does the outbox needs recreation?
+ if ((panel == NULL) || !gInventory.getCategory(mRootFolderId))
+ {
+ setup();
+ }
+ // "Marketplace listings is empty!" message strings
+ text = LLTrans::getString("InventoryMarketplaceListingsNoItems", subs);
+ title = LLTrans::getString("InventoryMarketplaceListingsNoItemsTitle");
+ tooltip = LLTrans::getString("InventoryMarketplaceListingsNoItemsTooltip");
+ }
+ else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING)
+ {
+ // "Initializing!" message strings
+ text = LLTrans::getString("InventoryOutboxInitializing", subs);
+ title = LLTrans::getString("InventoryOutboxInitializingTitle");
+ tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip");
+ }
+ else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT)
+ {
+ // "Not a merchant!" message strings
+ text = LLTrans::getString("InventoryOutboxNotMerchant", subs);
+ title = LLTrans::getString("InventoryOutboxNotMerchantTitle");
+ tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip");
+ }
+ else
+ {
+ // "Errors!" message strings
+ text = LLTrans::getString("InventoryOutboxError", subs);
+ title = LLTrans::getString("InventoryOutboxErrorTitle");
+ tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
+ }
+
+ mInventoryText->setValue(text);
+ mInventoryTitle->setValue(title);
+ mInventoryPlaceholder->getParent()->setToolTip(tooltip);
+ }
+}
+
+bool LLFloaterMarketplaceListings::isAccepted(EAcceptance accept)
+{
+ // *TODO : Need a bit more test on what we accept: depends of what and where...
+ return (accept >= ACCEPT_YES_COPY_SINGLE);
+}
+
+
+BOOL LLFloaterMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ if ((mInventoryPanel.get() == NULL) || mRootFolderId.isNull())
+ {
+ return FALSE;
+ }
+
+ LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
+ BOOL handled = (handled_view != NULL);
+
+ // Determine if the mouse is inside the inventory panel itself or just within the floater
+ bool pointInInventoryPanel = false;
+ bool pointInInventoryPanelChild = false;
+ LLInventoryPanel* panel = mInventoryPanel.get();
+ LLFolderView* root_folder = panel->getRootFolder();
+ if (panel->getVisible())
+ {
+ S32 inv_x, inv_y;
+ localPointToOtherView(x, y, &inv_x, &inv_y, panel);
+
+ pointInInventoryPanel = panel->getRect().pointInRect(inv_x, inv_y);
+
+ LLView * inventory_panel_child_at_point = panel->childFromPoint(inv_x, inv_y, true);
+ pointInInventoryPanelChild = (inventory_panel_child_at_point != root_folder);
+ }
+
+ // Pass all drag and drop for this floater to the outbox inventory control
+ if (!handled || !isAccepted(*accept))
+ {
+ // Handle the drag and drop directly to the root of the outbox if we're not in the inventory panel
+ // (otherwise the inventory panel itself will handle the drag and drop operation, without any override)
+ if (!pointInInventoryPanel)
+ {
+ handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
+ }
+ }
+
+ return handled;
+}
+
+BOOL LLFloaterMarketplaceListings::handleHover(S32 x, S32 y, MASK mask)
+{
+ return LLFloater::handleHover(x, y, mask);
+}
+
+void LLFloaterMarketplaceListings::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ LLFloater::onMouseLeave(x, y, mask);
+}
+
+void LLFloaterMarketplaceListings::onChanged()
+{
+ LLViewerInventoryCategory* category = gInventory.getCategory(mRootFolderId);
+ if (mRootFolderId.notNull() && category)
+ {
+ fetchContents();
+ updateView();
+ }
+ else
+ {
+ clean();
+ }
+}
+
+void LLFloaterMarketplaceListings::initializationReportError(U32 status, const LLSD& content)
+{
+ updateView();
+}
+
+void LLFloaterMarketplaceListings::importStatusChanged(bool inProgress)
+{
+ if (mRootFolderId.isNull() && (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT))
+ {
+ setup();
+ }
+
+ if (inProgress)
+ {
+ setStatusString(getString("MarketplaceListingsInitializing"));
+ mInventoryInitializationInProgress->setVisible(true);
+ }
+ else
+ {
+ setStatusString("");
+ mInventoryInitializationInProgress->setVisible(false);
+ }
+
+ updateView();
+}
+
+void LLFloaterMarketplaceListings::importReportResults(U32 status, const LLSD& content)
+{
+ updateView();
+}
+
+
diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h
index 40519c8fd2..4908e4342b 100755
--- a/indra/newview/llfloateroutbox.h
+++ b/indra/newview/llfloateroutbox.h
@@ -1,7 +1,8 @@
/**
* @file llfloateroutbox.h
- * @brief LLFloaterOutbox
- * class definition
+ * @brief Implementation of the merchant outbox window and of the marketplace listings window
+ *
+ * *TODO : Eventually, take out all the merchant outbox stuff and rename that file to llfloatermarketplacelistings
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -30,6 +31,7 @@
#include "llfloater.h"
#include "llfoldertype.h"
+#include "llinventoryfilter.h"
#include "llnotificationptr.h"
@@ -113,4 +115,69 @@ private:
LLWindowShade * mWindowShade;
};
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLFloaterMarketplaceListings
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLFloaterMarketplaceListings : public LLFloater
+{
+public:
+ LLFloaterMarketplaceListings(const LLSD& key);
+ ~LLFloaterMarketplaceListings();
+
+ void initializeMarketPlace();
+
+ // virtuals
+ 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 showNotification(const LLNotificationPtr& notification);
+
+ BOOL handleHover(S32 x, S32 y, MASK mask);
+ void onMouseLeave(S32 x, S32 y, MASK mask);
+
+protected:
+ void setup();
+ void clean();
+ void fetchContents();
+
+ void importReportResults(U32 status, const LLSD& content);
+ void importStatusChanged(bool inProgress);
+ void initializationReportError(U32 status, const LLSD& content);
+ void setStatusString(const std::string& statusString);
+
+ void onClose(bool app_quitting);
+ void onOpen(const LLSD& key);
+ void onFocusReceived();
+ void onChanged();
+
+ bool isAccepted(EAcceptance accept);
+
+ void updateView();
+
+private:
+ S32 getFolderCount();
+ // UI callbacks
+ void onViewSortMenuItemClicked(const LLSD& userdata);
+ bool onViewSortMenuItemCheck(const LLSD& userdata);
+
+ LLInventoryCategoriesObserver * mCategoriesObserver;
+ LLInventoryCategoryAddedObserver * mCategoryAddedObserver;
+
+ LLTextBox * mInventoryStatus;
+ LLView * mInventoryInitializationInProgress;
+ LLView * mInventoryPlaceholder;
+ LLTextBox * mInventoryText;
+ LLTextBox * mInventoryTitle;
+
+ LLUUID mRootFolderId;
+ LLHandle<LLInventoryPanel> mInventoryPanel;
+ LLInventoryFilter::ESortOrderType mSortOrder;
+ LLInventoryFilter::EFilterType mFilterType;
+};
+
#endif // LL_LLFLOATEROUTBOX_H
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 44943d8722..3d418105e3 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -959,6 +959,18 @@ BOOL LLInvFVBridge::isInboxFolder() const
return gInventory.isObjectDescendentOf(mUUID, inbox_id);
}
+BOOL LLInvFVBridge::isMarketplaceListingsFolder() const
+{
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+
+ if (folder_id.isNull())
+ {
+ return FALSE;
+ }
+
+ return gInventory.isObjectDescendentOf(mUUID, folder_id);
+}
+
BOOL LLInvFVBridge::isOutboxFolder() const
{
const LLUUID outbox_id = getOutboxFolder();
@@ -1931,6 +1943,58 @@ void LLFolderBridge::buildDisplayName() const
}
}
+std::string LLFolderBridge::getLabelSuffix() const
+{
+ // *TODO : We need to display some suffix also for the version folder!
+ /*
+ LLInventoryCategory* cat = gInventory.getCategory(getUUID());
+ if(cat)
+ {
+ const LLUUID& parent_folder_id = cat->getParentUUID();
+ accessories = (parent_folder_id == gInventory.getLibraryRootFolderID());
+ }
+ */
+ if (isMarketplaceListingsFolder())
+ {
+ if (LLMarketplaceData::instance().isListed(getUUID()))
+ {
+ llinfos << "Merov : in merchant folder and listed : id = " << getUUID() << llendl;
+ std::string suffix = LLMarketplaceData::instance().getListingID(getUUID());
+ if (suffix.empty())
+ {
+ suffix = LLTrans::getString("MarketplaceNoID");
+ }
+ suffix = " (" + suffix + ")";
+ if (LLMarketplaceData::instance().getActivationState(getUUID()))
+ {
+ suffix += " (" + LLTrans::getString("MarketplaceActive") + ")";
+ }
+ return LLInvFVBridge::getLabelSuffix() + suffix;
+ }
+ else
+ {
+ llinfos << "Merov : in merchant folder but not listed : id = " << getUUID() << llendl;
+ return LLInvFVBridge::getLabelSuffix();
+ }
+ }
+ else
+ {
+ return LLInvFVBridge::getLabelSuffix();
+ }
+}
+
+LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const
+{
+ if (isMarketplaceListingsFolder() && LLMarketplaceData::instance().getActivationState(getUUID()))
+ {
+ return LLFontGL::BOLD;
+ }
+ else
+ {
+ return LLFontGL::NORMAL;
+ }
+}
+
void LLFolderBridge::update()
{
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index bc875e8f37..26c48fdc57 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -160,6 +160,7 @@ protected:
BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox
BOOL isOutboxFolder() const; // true if COF or descendant of marketplace outbox
BOOL isOutboxFolderDirectParent() const;
+ BOOL isMarketplaceListingsFolder() const; // true if descendant of Marketplace listings folder
const LLUUID getOutboxFolder() const;
virtual BOOL isItemPermissive() const;
@@ -274,7 +275,8 @@ public:
virtual LLUIImagePtr getIcon() const;
virtual LLUIImagePtr getIconOpen() const;
virtual LLUIImagePtr getIconOverlay() const;
-
+ virtual std::string getLabelSuffix() const;
+ virtual LLFontGL::StyleFlags getLabelStyle() const;
static LLUIImagePtr getIcon(LLFolderType::EType preferred_type);
virtual BOOL renameItem(const std::string& new_name);
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index 15463e0d33..6a800cf5ba 100755
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -33,6 +33,7 @@
#include "llfolderviewitem.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
+#include "llmarketplacefunctions.h"
#include "llviewercontrol.h"
#include "llfolderview.h"
#include "llinventorybridge.h"
@@ -131,6 +132,30 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
LLInventoryModelBackgroundFetch::instance().start(folder_id);
}
+ // Marketplace folder filtering
+ const U32 filterTypes = mFilterOps.mFilterTypes;
+ if (filterTypes & FILTERTYPE_MARKETPLACE_ACTIVE)
+ {
+ if (!LLMarketplaceData::instance().getActivationState(folder_id))
+ {
+ return false;
+ }
+ }
+ if (filterTypes & FILTERTYPE_MARKETPLACE_INACTIVE)
+ {
+ if (LLMarketplaceData::instance().getActivationState(folder_id))
+ {
+ return false;
+ }
+ }
+ if (filterTypes & FILTERTYPE_MARKETPLACE_UNASSOCIATED)
+ {
+ if (!LLMarketplaceData::instance().getListingID(folder_id).empty())
+ {
+ return false;
+ }
+ }
+
// Always check against the clipboard
const BOOL passed_clipboard = checkAgainstClipboard(folder_id);
@@ -250,7 +275,7 @@ bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewModelItemInvent
}
}
}
-
+
return TRUE;
}
@@ -475,6 +500,21 @@ void LLInventoryFilter::setFilterEmptySystemFolders()
mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS;
}
+void LLInventoryFilter::setFilterMarketplaceActiveFolders()
+{
+ mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_ACTIVE;
+}
+
+void LLInventoryFilter::setFilterMarketplaceInactiveFolders()
+{
+ mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_INACTIVE;
+}
+
+void LLInventoryFilter::setFilterMarketplaceUnassociatedFolders()
+{
+ mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_UNASSOCIATED;
+}
+
void LLInventoryFilter::setFilterUUID(const LLUUID& object_id)
{
if (mFilterOps.mFilterUUID == LLUUID::null)
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index ce516af0b9..113596b0eb 100755
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -52,7 +52,10 @@ public:
FILTERTYPE_UUID = 0x1 << 2, // find the object with UUID and any links to it
FILTERTYPE_DATE = 0x1 << 3, // search by date range
FILTERTYPE_WEARABLE = 0x1 << 4, // search by wearable type
- FILTERTYPE_EMPTYFOLDERS = 0x1 << 5 // pass if folder is not a system folder to be hidden if
+ 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_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
};
enum EFilterLink
@@ -67,7 +70,8 @@ public:
SO_NAME = 0, // Sort inventory by name
SO_DATE = 0x1, // Sort inventory by date
SO_FOLDERS_BY_NAME = 0x1 << 1, // Force folder sort by name
- SO_SYSTEM_FOLDERS_TO_TOP = 0x1 << 2 // Force system folders to be on top
+ SO_SYSTEM_FOLDERS_TO_TOP = 0x1 << 2,// Force system folders to be on top
+ SO_FOLDERS_BY_WEIGHT = 0x1 << 3, // Force folder sort by weight, usually, amount of some elements in their descendents
};
struct FilterOps
@@ -160,6 +164,9 @@ public:
void setFilterUUID(const LLUUID &object_id);
void setFilterWearableTypes(U64 types);
void setFilterEmptySystemFolders();
+ void setFilterMarketplaceActiveFolders();
+ void setFilterMarketplaceInactiveFolders();
+ void setFilterMarketplaceUnassociatedFolders();
void updateFilterTypes(U64 types, U64& current_types);
void setFilterSubString(const std::string& string);
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index f1a4889f5a..203eb4ec4e 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -111,6 +111,16 @@ void append_path(const LLUUID& id, std::string& path)
path.append(temp);
}
+void update_marketplace_category(const LLUUID& cat_id)
+{
+ // When changing the marketplace status of a folder, the only thing that needs to happen is
+ // for all observers of the folder to, possibly, change the display label of said folder.
+ // At least that's the status for the moment so, even if that function seems small, we
+ // prefer to encapsulate that behavior here.
+ gInventory.addChangedMask(LLInventoryObserver::LABEL, cat_id);
+ gInventory.notifyObservers();
+}
+
void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name)
{
LLViewerInventoryCategory* cat;
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index f1066a4dc9..1443c186cf 100755
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -58,6 +58,9 @@ void show_task_item_profile(const LLUUID& item_uuid, const LLUUID& object_id);
void show_item_original(const LLUUID& item_uuid);
void reset_inventory_filter();
+// Just nudge the category in the global inventory to signal that its marketplace status changed
+void update_marketplace_category(const LLUUID& cat_id);
+
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);
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 81ee7ac07e..bf8f7819ef 100755
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -288,6 +288,7 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
{
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX));
+ getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
}
// set the filter for the empty folder if the debug setting is on
@@ -1489,5 +1490,6 @@ namespace LLInitParam
declare(LLFolderType::lookup(LLFolderType::FT_INBOX) , LLFolderType::FT_INBOX);
declare(LLFolderType::lookup(LLFolderType::FT_OUTBOX) , LLFolderType::FT_OUTBOX);
declare(LLFolderType::lookup(LLFolderType::FT_BASIC_ROOT) , LLFolderType::FT_BASIC_ROOT);
+ declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_LISTINGS) , LLFolderType::FT_MARKETPLACE_LISTINGS);
}
}
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index 05c9d76810..6f35cc217d 100755
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -30,6 +30,7 @@
#include "llagent.h"
#include "llhttpclient.h"
+#include "llinventoryfunctions.h"
#include "llsdserialize.h"
#include "lltimer.h"
#include "lltrans.h"
@@ -528,3 +529,121 @@ void LLMarketplaceInventoryImporter::updateImport()
}
}
+//
+// Direct Delivery : Marketplace tuples and data
+//
+
+// Tuple == Item
+LLMarketplaceTuple::LLMarketplaceTuple() :
+ mFolderListingId(),
+ mListingId(""),
+ mActiveVersionFolderId(),
+ mIsActive(false)
+{
+}
+
+LLMarketplaceTuple::LLMarketplaceTuple(const LLUUID& folder_id) :
+ mFolderListingId(folder_id),
+ mListingId(""),
+ mActiveVersionFolderId(),
+ mIsActive(false)
+{
+}
+
+LLMarketplaceTuple::LLMarketplaceTuple(const LLUUID& folder_id, std::string listing_id, const LLUUID& version_id, bool is_listed) :
+ mFolderListingId(folder_id),
+ mListingId(listing_id),
+ mActiveVersionFolderId(version_id),
+ mIsActive(is_listed)
+{
+}
+
+
+// Data map
+LLMarketplaceData::LLMarketplaceData()
+{
+}
+
+// Accessors
+bool LLMarketplaceData::getActivationState(const LLUUID& folder_id)
+{
+ marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
+ return (it == mMarketplaceItems.end() ? false : (it->second).mIsActive);
+}
+std::string LLMarketplaceData::getListingID(const LLUUID& folder_id)
+{
+ marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
+ return (it == mMarketplaceItems.end() ? "" : (it->second).mListingId);
+}
+LLUUID LLMarketplaceData::getVersionFolderID(const LLUUID& folder_id)
+{
+ marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
+ return (it == mMarketplaceItems.end() ? LLUUID::null : (it->second).mActiveVersionFolderId);
+}
+bool LLMarketplaceData::isListed(const LLUUID& folder_id)
+{
+ marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
+ return (it != mMarketplaceItems.end());
+}
+
+// Modifiers
+bool LLMarketplaceData::setListingID(const LLUUID& folder_id, std::string listing_id)
+{
+ marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
+ if (it == mMarketplaceItems.end())
+ {
+ return false;
+ }
+ else
+ {
+ (it->second).mListingId = listing_id;
+ update_marketplace_category(folder_id);
+ return true;
+ }
+}
+bool LLMarketplaceData::setVersionFolderID(const LLUUID& folder_id, const LLUUID& version_id)
+{
+ marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
+ if (it == mMarketplaceItems.end())
+ {
+ return false;
+ }
+ else
+ {
+ (it->second).mActiveVersionFolderId = version_id;
+ update_marketplace_category(folder_id);
+ return true;
+ }
+}
+bool LLMarketplaceData::setActivation(const LLUUID& folder_id, bool activate)
+{
+ marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id);
+ if (it == mMarketplaceItems.end())
+ {
+ return false;
+ }
+ else
+ {
+ (it->second).mIsActive = activate;
+ update_marketplace_category(folder_id);
+ return true;
+ }
+}
+
+// Test methods
+void LLMarketplaceData::addTestItem(const LLUUID& folder_id)
+{
+ llinfos << "Merov : addTestItem, id = " << folder_id << llendl;
+ mMarketplaceItems[folder_id] = LLMarketplaceTuple(folder_id);
+ update_marketplace_category(folder_id);
+}
+void LLMarketplaceData::addTestItem(const LLUUID& folder_id, const LLUUID& version_id)
+{
+ llinfos << "Merov : addTestItem, id = " << folder_id << ", version = " << version_id << llendl;
+ mMarketplaceItems[folder_id] = LLMarketplaceTuple(folder_id);
+ setVersionFolderID(folder_id, version_id);
+ update_marketplace_category(folder_id);
+ update_marketplace_category(version_id);
+}
+
+
diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h
index abe60890a3..00840c6e23 100755
--- a/indra/newview/llmarketplacefunctions.h
+++ b/indra/newview/llmarketplacefunctions.h
@@ -109,6 +109,63 @@ private:
};
+// Classes handling the data coming from and going to the Marketplace DB:
+// * implement the Marketplace API (TBD)
+// * cache the current Marketplace data (tuples)
+// * provide methods to get Marketplace data on any inventory item
+// * signal marketplace updates to inventory
+class LLMarketplaceData;
+
+// A Marketplace item is known by its tuple
+class LLMarketplaceTuple
+{
+public:
+ friend class LLMarketplaceData;
+
+ LLMarketplaceTuple();
+ LLMarketplaceTuple(const LLUUID& folder_id);
+ LLMarketplaceTuple(const LLUUID& folder_id, std::string listing_id, const LLUUID& version_id, bool is_listed = false);
+
+private:
+ // Representation of a marketplace item in the Marketplace DB (well, what we know of it...)
+ LLUUID mFolderListingId;
+ std::string mListingId;
+ LLUUID mActiveVersionFolderId;
+ bool mIsActive;
+};
+// Note: the folder UUID is used as a key to this map. It could therefore be taken off the object themselves
+typedef std::map<LLUUID, LLMarketplaceTuple> marketplace_items_list_t;
+
+// There's one and only one possible set of Marketplace data per agent and per session
+class LLMarketplaceData
+ : public LLSingleton<LLMarketplaceData>
+{
+public:
+ LLMarketplaceData();
+
+ bool isEmpty() { return (mMarketplaceItems.size() == 0); }
+
+ // Access Marketplace Data : each method returns a default value if the folder_id can't be found
+ bool getActivationState(const LLUUID& folder_id);
+ std::string getListingID(const LLUUID& folder_id);
+ LLUUID getVersionFolderID(const LLUUID& folder_id);
+
+ bool isListed(const LLUUID& folder_id); // returns true if folder_id is in the items map
+
+ // Modify Marketplace Data : each method returns true if the function succeeds, false if error
+ bool setListingID(const LLUUID& folder_id, std::string listing_id);
+ bool setVersionFolderID(const LLUUID& folder_id, const LLUUID& version_id);
+ bool setActivation(const LLUUID& folder_id, bool activate);
+
+ // Merov : DD Development : methods to populate the items list with something usefull using
+ // inventory IDs and some pseudo random code so we can play with the UI...
+ void addTestItem(const LLUUID& folder_id);
+ void addTestItem(const LLUUID& folder_id, const LLUUID& version_id);
+
+private:
+ marketplace_items_list_t mMarketplaceItems;
+};
+
#endif // LL_LLMARKETPLACEFUNCTIONS_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index a8eeddb798..853d98693b 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -243,6 +243,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("tex_fetch_debugger", "floater_texture_fetch_debugger.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTextureFetchDebugger>);
}
LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>);
+ LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceListings>);
LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>);
LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>);
LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>);
diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp
index 991f6b40e6..ee8f85782f 100644
--- a/indra/newview/llviewerfoldertype.cpp
+++ b/indra/newview/llviewerfoldertype.cpp
@@ -140,6 +140,8 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()
addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible));
addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "Inv_SysOpen", "Inv_SysClosed", FALSE, true));
+
+ addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new ViewerFolderEntry("Marketplace listings", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible));
addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "Inv_FolderOpen", "Inv_FolderClosed", FALSE, false, "default"));
diff --git a/indra/newview/skins/default/xui/en/floater_marketplace_listings.xml b/indra/newview/skins/default/xui/en/floater_marketplace_listings.xml
new file mode 100755
index 0000000000..80d6187e1e
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_marketplace_listings.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<floater
+ title="MARKETPLACE LISTINGS"
+ name="floater_marketplace_listings"
+ help_topic="floater_marketplace_listings"
+ positioning="cascading"
+ width="333"
+ height="445"
+ min_width="200"
+ min_height="300"
+ can_close="true"
+ can_resize="true"
+ save_rect="true"
+ save_visibility="false"
+ reuse_instance="true">
+ <string name="MarketplaceListingsInitializing">Initializing...</string>
+ <panel
+ follows="all"
+ layout="topleft"
+ left="0"
+ top="0"
+ label=""
+ height="440"
+ width="333">
+ <panel
+ follows="all"
+ left="10"
+ height="420"
+ width="313"
+ top="0"
+ bg_opaque_color="InventoryBackgroundColor">
+ <panel
+ name="marketplace_listings_inventory_placeholder_panel"
+ follows="all"
+ layout="topleft"
+ top="0"
+ left="0"
+ width="313"
+ height="420"
+ bg_opaque_color="InventoryBackgroundColor">
+ <text
+ name="marketplace_listings_inventory_placeholder_title"
+ type="string"
+ follows="top|left|right"
+ layout="topleft"
+ top="10"
+ left="0"
+ width="313"
+ height="25"
+ wrap="true"
+ halign="center"
+ font="SansSerifBold">
+ Loading...
+ </text>
+ <text
+ name="marketplace_listings_inventory_placeholder_text"
+ type="string"
+ follows="top|left|right"
+ layout="topleft"
+ top="35"
+ left="0"
+ width="313"
+ height="130"
+ wrap="true"
+ halign="left" />
+ </panel>
+ </panel>
+ <panel
+ follows="bottom|left|right"
+ layout="topleft"
+ left="10"
+ width="313"
+ height="20">
+ <text
+ name="marketplace_status"
+ type="string"
+ follows="bottom|left|right"
+ layout="topleft"
+ top="0"
+ left="5"
+ width="150"
+ height="20"
+ wrap="true"
+ halign="left"
+ valign="center"
+ font="SansSerif"/>
+ </panel>
+ <layout_stack name="initialization_progress_indicator" orientation="vertical" left="0" height="440" top="0" width="333" follows="all" visible="false">
+ <layout_panel />
+ <layout_panel height="24" auto_resize="false">
+ <layout_stack orientation="horizontal" left="0" height="24" top="0" width="333" follows="all">
+ <layout_panel width="0" />
+ <layout_panel width="24" auto_resize="false">
+ <loading_indicator
+ height="24"
+ layout="topleft"
+ left="0"
+ top="0"
+ width="24" />
+ </layout_panel>
+ <layout_panel width="0" />
+ </layout_stack>
+ </layout_panel>
+ <layout_panel />
+ </layout_stack>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_marketplace_view.xml b/indra/newview/skins/default/xui/en/menu_marketplace_view.xml
new file mode 100755
index 0000000000..9ed93e2f11
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_marketplace_view.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ name="menu_marketplace_sort"
+ left="0" bottom="0" visible="false"
+ mouse_opaque="false">
+ <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 name="show_all" label="Show All">
+ <menu_item_check.on_click
+ function="Marketplace.ViewSort.Action"
+ parameter="show_all" />
+ <menu_item_check.on_check
+ function="Marketplace.ViewSort.CheckItem"
+ parameter="show_all" />
+ </menu_item_check>
+ <menu_item_check name="show_associated_listings" label="Show Associated Listings Only">
+ <menu_item_check.on_click
+ function="Marketplace.ViewSort.Action"
+ parameter="show_associated_listings" />
+ <menu_item_check.on_check
+ function="Marketplace.ViewSort.CheckItem"
+ parameter="show_associated_listings" />
+ </menu_item_check>
+ <menu_item_check name="show_active" label="Show Active Listings and Folders Only">
+ <menu_item_check.on_click
+ function="Marketplace.ViewSort.Action"
+ parameter="show_active" />
+ <menu_item_check.on_check
+ function="Marketplace.ViewSort.CheckItem"
+ parameter="show_active" />
+ </menu_item_check>
+ <menu_item_check name="show_inactive_listings" label="Show Inactive Listings Only">
+ <menu_item_check.on_click
+ function="Marketplace.ViewSort.Action"
+ parameter="show_inactive_listings" />
+ <menu_item_check.on_check
+ function="Marketplace.ViewSort.CheckItem"
+ parameter="show_inactive_listings" />
+ </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 7e8d2aaf9a..2c432c2c8c 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -181,6 +181,13 @@
function="Floater.ToggleOrBringToFront"
parameter="outbox" />
</menu_item_call>
+ <menu_item_call
+ label="Marketplace listings..."
+ name="MarketplaceListings">
+ <menu_item_call.on_click
+ function="Floater.ToggleOrBringToFront"
+ parameter="marketplace_listings" />
+ </menu_item_call>
<menu_item_call
label="Account dashboard..."
name="Manage My Account">
diff --git a/indra/newview/skins/default/xui/en/panel_marketplace_listings.xml b/indra/newview/skins/default/xui/en/panel_marketplace_listings.xml
new file mode 100755
index 0000000000..54fc3a0c0f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_marketplace_listings.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ label="Marketplace"
+ name="main marketplace panel"
+ follows="all"
+ layout="topleft"
+ width="308"
+ height="375">
+ <panel
+ label="tool_panel"
+ name="nearby_buttons_panel"
+ follows="left|top|right"
+ layout="topleft"
+ height="30"
+ width="308"
+ top="0"
+ left="0">
+ <menu_button
+ name="sort_btn"
+ tool_tip="View/sort options"
+ layout="topleft"
+ follows="top|left"
+ width="31"
+ height="25"
+ left="2"
+ menu_filename="menu_marketplace_view.xml"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_sort"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ menu_position="bottomleft"/>
+ </panel>
+ <panel
+ follows="all"
+ layout="topleft"
+ default_tab_group="1"
+ width="308"
+ height="340">
+ <tab_container
+ name="marketplace filter tabs"
+ follows="all"
+ layout="topleft"
+ top="0"
+ left="0"
+ top_pad="0"
+ width="308"
+ height="340"
+ halign="center"
+ tab_height="30"
+ tab_group="1"
+ tab_position="top"
+ tab_min_width="50">
+ <inventory_panel
+ label="ALL"
+ name="All Items"
+ help_topic="marketplace_tab"
+ layout="topleft"
+ follows="all"
+ width="308"
+ height="310"
+ top="16"
+ left="0"
+ start_folder.name="Marketplace listings"
+ show_empty_message="false"
+ show_load_status="false"
+ start_folder.type="merchant"
+ tool_tip="Drag and drop items here to sell them"
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ sort_order_setting="InventorySortOrder"
+ show_item_link_overlays="true">
+ </inventory_panel>
+ <inventory_panel
+ label="ACTIVE"
+ name="Active Items"
+ help_topic="marketplace_tab"
+ layout="topleft"
+ follows="all"
+ width="308"
+ height="310"
+ left_delta="0"
+ start_folder.name="Marketplace listings"
+ show_empty_message="false"
+ show_load_status="false"
+ start_folder.type="merchant"
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ show_item_link_overlays="true">
+ </inventory_panel>
+ <inventory_panel
+ label="INACTIVE"
+ name="Inactive Items"
+ help_topic="marketplace_tab"
+ layout="topleft"
+ follows="all"
+ width="308"
+ height="310"
+ left_delta="0"
+ start_folder.name="Marketplace listings"
+ show_empty_message="false"
+ show_load_status="false"
+ start_folder.type="merchant"
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ show_item_link_overlays="true">
+ </inventory_panel>
+ <inventory_panel
+ label="UNASSOCIATED"
+ name="Unassociated Items"
+ help_topic="marketplace_tab"
+ layout="topleft"
+ follows="all"
+ width="308"
+ height="310"
+ left_delta="0"
+ start_folder.name="Marketplace listings"
+ show_empty_message="false"
+ show_load_status="false"
+ start_folder.type="merchant"
+ bg_opaque_color="DkGray2"
+ bg_alpha_color="DkGray2"
+ background_visible="true"
+ border="false"
+ bevel_style="none"
+ show_item_link_overlays="true">
+ </inventory_panel>
+ </tab_container>
+ </panel>
+</panel> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 3252ed2b62..80b520622a 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2255,6 +2255,11 @@ We are accessing your account on the [[MARKETPLACE_CREATE_STORE_URL] Marketplace
<string name="InventoryOutboxError">
The [[MARKETPLACE_CREATE_STORE_URL] Marketplace store] is returning errors.
</string>
+ <string name="InventoryMarketplaceListingsNoItemsTitle">Your Marketplace Listings folder is empty.</string>
+ <string name="InventoryMarketplaceListingsNoItemsTooltip"></string>
+ <string name="InventoryMarketplaceListingsNoItems">
+ Drag folders to this area to list them for sale on the [[MARKETPLACE_DASHBOARD_URL] Marketplace].
+ </string>
<string name="Marketplace Error None">No errors</string>
<string name="Marketplace Error Not Merchant">Error: Before sending items to the Marketplace you will need to set yourself up as a merchant (free of charge).</string>
@@ -2266,6 +2271,9 @@ The [[MARKETPLACE_CREATE_STORE_URL] Marketplace store] is returning errors.
<string name="Marketplace Error Unsellable Item">Error: This item can not be sold on the marketplace.</string>
<string name="Marketplace Error Internal Import">Error: There was a problem with this item. Try again later.</string>
+ <string name="MarketplaceNoID">no Mkt ID</string>
+ <string name="MarketplaceActive">live</string>
+
<string name="Open landmarks">Open landmarks</string>
<!-- use value="" because they have preceding spaces -->