From eb4b0d630fbcb26529e366e1d0b37dd48c2ed5fc Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Thu, 6 Feb 2014 14:53:13 -0500 Subject: [PATCH] [MAINT-2287] The rest of the updates so far to outbox. --- indra/newview/llfloateroutbox.cpp | 82 +++++++++++++++++------- indra/newview/llfloateroutbox.h | 1 + indra/newview/llinventorymodel.cpp | 60 +++++++++++++++++ indra/newview/llinventorymodel.h | 5 ++ indra/newview/llinventoryobserver.cpp | 17 ++++- indra/newview/llmarketplacefunctions.cpp | 21 ++++-- indra/newview/llmarketplacefunctions.h | 1 + 7 files changed, 156 insertions(+), 31 deletions(-) diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp index 64baf95ff..f98f9f006 100644 --- a/indra/newview/llfloateroutbox.cpp +++ b/indra/newview/llfloateroutbox.cpp @@ -164,6 +164,17 @@ BOOL LLFloaterOutbox::postBuild() return TRUE; } +void LLFloaterOutbox::cleanOutbox() +{ + // 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 + mOutboxId.setNull(); + mOutboxItemCount = 0; +} + void LLFloaterOutbox::onClose(bool app_quitting) { /* @@ -226,14 +237,26 @@ void LLFloaterOutbox::setupOutbox() } // We are a merchant. Get the outbox, create it if needs be. - mOutboxId = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, true, false); - if (mOutboxId.isNull()) + LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, true); + if (outbox_id.isNull()) { - // We should never get there unles inventory fails badly + // We should never get there unless inventory fails badly llerrs << "Inventory problem: failure to create the outbox for a merchant!" << llendl; return; } + // Consolidate Merchant Outbox + // 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_OUTBOX); + + if (outbox_id == mOutboxId) + { + + llwarns << "Inventory warning: Merchant outbox already set" << llendl; + return; + } + mOutboxId = outbox_id; + // No longer need to observe new category creation if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) { @@ -243,13 +266,15 @@ void LLFloaterOutbox::setupOutbox() } llassert(!mCategoryAddedObserver); - // Create observer for outbox modifications - if (mCategoriesObserver == NULL) + // Create observer for outbox modifications : clear the old one and create a new one + if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver)) { - mCategoriesObserver = new LLInventoryCategoriesObserver(); - gInventory.addObserver(mCategoriesObserver); - mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this)); + gInventory.removeObserver(mCategoriesObserver); + delete mCategoriesObserver; } + mCategoriesObserver = new LLInventoryCategoriesObserver(); + gInventory.addObserver(mCategoriesObserver); + mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this)); llassert(mCategoriesObserver); // Set up the outbox inventory view @@ -273,13 +298,15 @@ void LLFloaterOutbox::initializeMarketPlace() // // Initialize the marketplace import API // - LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance(); - importer.setInitializationErrorCallback(boost::bind(&LLFloaterOutbox::initializationReportError, this, _1, _2)); - importer.setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1)); - importer.setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2)); - importer.initialize(); + if (!importer.isInitialized()) + { + importer.setInitializationErrorCallback(boost::bind(&LLFloaterOutbox::initializationReportError, this, _1, _2)); + importer.setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1)); + importer.setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2)); + importer.initialize(); + } } void LLFloaterOutbox::setStatusString(const std::string& statusString) @@ -306,6 +333,11 @@ void LLFloaterOutbox::updateFolderCount() mOutboxItemCount = item_count; } + else + { + // If there's no outbox, the number of items in it should be set to 0 for consistency + mOutboxItemCount = 0; + } if (!mImportBusy) { @@ -375,6 +407,11 @@ void LLFloaterOutbox::updateView() if (mOutboxId.notNull()) { + // Does the outbox needs recreation? + if ((mOutboxInventoryPanel.get() == NULL) || !gInventory.getCategory(mOutboxId)) + { + setupOutbox(); + } // "Outbox is empty!" message strings outbox_text = LLTrans::getString("InventoryOutboxNoItems"); subs_link = "[MARKETPLACE_DASHBOARD_URL]"; @@ -441,7 +478,8 @@ BOOL LLFloaterOutbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, { if ((mOutboxInventoryPanel.get() == NULL) || //(mWindowShade && mWindowShade->isShown()) || - LLMarketplaceInventoryImporter::getInstance()->isImportInProgress()) + LLMarketplaceInventoryImporter::getInstance()->isImportInProgress() || + mOutboxId.isNull()) { return FALSE; } @@ -511,16 +549,16 @@ void LLFloaterOutbox::onImportButtonClicked() void LLFloaterOutbox::onOutboxChanged() { - llassert(!mOutboxId.isNull()); - - if (mOutboxInventoryPanel) + LLViewerInventoryCategory* category = gInventory.getCategory(mOutboxId); + if (mOutboxId.notNull() && category) { - mOutboxInventoryPanel->requestSort(); + fetchOutboxContents(); + updateView(); + } + else + { + cleanOutbox(); } - - fetchOutboxContents(); - - updateView(); } void LLFloaterOutbox::importReportResults(U32 status, const LLSD& content) diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h index c48ddb561..61a11c50d 100644 --- a/indra/newview/llfloateroutbox.h +++ b/indra/newview/llfloateroutbox.h @@ -72,6 +72,7 @@ public: protected: void setupOutbox(); + void cleanOutbox(); void fetchOutboxContents(); void importReportResults(U32 status, const LLSD& content); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index ddfb151a6..4d4e7ce8f 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -405,6 +405,66 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id) mItemLock[cat_id] = false; } +void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::EType type) +{ + // Make a list of folders that are not "main_id" and are of "type" + std::vector folder_ids; + for (cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + { + LLViewerInventoryCategory* cat = cit->second; + if ((cat->getPreferredType() == type) && (cat->getUUID() != main_id)) + { + folder_ids.push_back(cat->getUUID()); + } + } + + // Iterate through those folders + for (std::vector::iterator folder_ids_it = folder_ids.begin(); folder_ids_it != folder_ids.end(); ++folder_ids_it) + { + LLUUID folder_id = (*folder_ids_it); + + // Get the content of this folder + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(folder_id, cats, items); + + // Move all items to the main folder + // Note : we get the list of UUIDs and iterate on them instead of iterating directly on item_array_t + // elements. This is because moving elements modify the maps and, consequently, invalidate iterators on them. + // This "gather and iterate" method is verbose but resilient. + std::vector list_uuids; + for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (std::vector::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + LLViewerInventoryItem* item = getItem(*it); + changeItemParent(item, main_id, TRUE); + } + + // Move all folders to the main folder + list_uuids.clear(); + for (cat_array_t::const_iterator it = cats->begin(); it != cats->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (std::vector::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + LLViewerInventoryCategory* cat = getCategory(*it); + changeCategoryParent(cat, main_id, TRUE); + } + + // Purge the emptied folder + // Note: we'd like to use purgeObject() but it doesn't cleanly eliminate the folder + // which leads to issues further down the road when the folder is found again + //purgeObject(folder_id); + // We remove the folder and empty the trash instead which seems to work + removeCategory(folder_id); + gInventory.emptyFolderType("", LLFolderType::FT_TRASH); + } +} + // findCategoryUUIDForType() returns the uuid of the category that // specifies 'type' as what it defaults to containing. The category is // not necessarily only for that type. *NOTE: This will create a new diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a73a1fee6..09a85ba5d 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -275,6 +275,11 @@ public: LLViewerInventoryItem* getLinkedItem(const LLUUID& object_id) const; LLUUID findCategoryByName(std::string name); + + // Copy content of all folders of type "type" into folder "id" and delete/purge the empty folders + // Note : This method has been designed for FT_OUTBOX (aka Merchant Outbox) but can be used for other categories + void consolidateForType(const LLUUID& id, LLFolderType::EType type); + private: mutable LLPointer mLastItem; // cache recent lookups diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 9db175ec2..1cd71cf89 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -690,15 +690,24 @@ void LLInventoryCategoriesObserver::changed(U32 mask) if (!mCategoryMap.size()) return; + std::vector deleted_categories_ids; + for (category_map_t::iterator iter = mCategoryMap.begin(); iter != mCategoryMap.end(); ++iter) { const LLUUID& cat_id = (*iter).first; + LLCategoryData& cat_data = (*iter).second; LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); if (!category) + { + llwarns << "Category : Category id = " << cat_id << " disappeared" << llendl; + cat_data.mCallback(); + // Keep track of those deleted categories so we can remove them + deleted_categories_ids.push_back(cat_id); continue; + } const S32 version = category->getVersion(); const S32 expected_num_descendents = category->getDescendentCount(); @@ -726,8 +735,6 @@ void LLInventoryCategoriesObserver::changed(U32 mask) const S32 current_num_known_descendents = cats->count() + items->count(); - LLCategoryData& cat_data = (*iter).second; - bool cat_changed = false; // If category version or descendents count has changed @@ -757,6 +764,12 @@ void LLInventoryCategoriesObserver::changed(U32 mask) if (cat_changed) cat_data.mCallback(); } + + // Remove deleed categories from the list + for (std::vector::iterator deleted_id = deleted_categories_ids.begin(); deleted_id != deleted_categories_ids.end(); ++deleted_id) + { + removeCategory(*deleted_id); + } } bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 74a8ddbcf..60d2e52c2 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -231,9 +231,11 @@ namespace LLMarketplaceImport llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl; } - // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS + // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions + // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) && - (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS)) + (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) && + (status != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) { if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { @@ -241,9 +243,9 @@ namespace LLMarketplaceImport } sMarketplaceCookie.clear(); } - else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS)) + else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)) { - llinfos << " SLM GET : Got IMPORT_DONE_WITH_ERRORS, marketplace cookie not cleared." << llendl; + llinfos << " SLM GET : Got error status = " << status << ", but marketplace cookie not cleared." << llendl; } sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING); @@ -306,13 +308,15 @@ namespace LLMarketplaceImport std::string url = getInventoryImportURL(); + AIHTTPHeaders headers = LLViewerMedia::getHeaders(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM GET: " << url << llendl; + llinfos << " SLM GET: establishMarketplaceSessionCookie, LLHTTPClient::get, url = " << url << llendl; + llinfos << " SLM GET: headers " << llendl; + llinfos << headers << llendl; } slmGetTimer.start(); - AIHTTPHeaders headers = LLViewerMedia::getHeaders(); LLHTTPClient::get(url, new LLImportGetResponder(), headers); return true; @@ -453,7 +457,10 @@ boost::signals2::connection LLMarketplaceInventoryImporter::setStatusReportCallb void LLMarketplaceInventoryImporter::initialize() { - llassert(!mInitialized); + if (mInitialized) + { + return; + } if (!LLMarketplaceImport::hasSessionCookie()) { diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h index 4e9e6ee81..6203af84f 100644 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -92,6 +92,7 @@ public: void initialize(); bool triggerImport(); bool isImportInProgress() const { return mImportInProgress; } + bool isInitialized() const { return mInitialized; } U32 getMarketPlaceStatus() const { return mMarketPlaceStatus; } protected: