diff --git a/indra/newview/fsfloaterlinkreplace.cpp b/indra/newview/fsfloaterlinkreplace.cpp index e11c07a8d5..42ba02daf2 100644 --- a/indra/newview/fsfloaterlinkreplace.cpp +++ b/indra/newview/fsfloaterlinkreplace.cpp @@ -31,21 +31,27 @@ #include "fsdroptarget.h" #include "llagent.h" #include "llappearancemgr.h" -#include "llinventoryfunctions.h" #include "lllineeditor.h" #include "lltextbox.h" -#include "llviewerinventory.h" + +const F32 BATCH_PAUSE_TIME = 1.f; +const U32 MAX_BATCH_SIZE = 25; FSFloaterLinkReplace::FSFloaterLinkReplace(const LLSD& key) : LLFloater(key), + LLEventTimer(BATCH_PAUSE_TIME), mRemainingItems(0), mSourceUUID(LLUUID::null), - mTargetUUID(LLUUID::null) + mTargetUUID(LLUUID::null), + mInstance(NULL) { + mEventTimer.stop(); + mInstance = this; } FSFloaterLinkReplace::~FSFloaterLinkReplace() { + mInstance = NULL; } BOOL FSFloaterLinkReplace::postBuild() @@ -53,7 +59,8 @@ BOOL FSFloaterLinkReplace::postBuild() mStartBtn = getChild("btn_start"); mStartBtn->setCommitCallback(boost::bind(&FSFloaterLinkReplace::onStartClicked, this)); - getChild("btn_refresh")->setCommitCallback(boost::bind(&FSFloaterLinkReplace::checkEnableStart, this)); + mRefreshBtn = getChild("btn_refresh"); + mRefreshBtn->setCommitCallback(boost::bind(&FSFloaterLinkReplace::checkEnableStart, this)); mSourceEditor = getChild("source_uuid_editor"); mTargetEditor = getChild("target_uuid_editor"); @@ -133,55 +140,25 @@ void FSFloaterLinkReplace::onStartClicked() return; } - LLInventoryModel::item_array_t items = gInventory.collectLinkedItems(mSourceUUID); - LL_INFOS() << "Found " << items.size() << " inventory links that need to be replaced." << LL_ENDL; + mRemainingInventoryItems = gInventory.collectLinkedItems(mSourceUUID); + LL_INFOS() << "Found " << mRemainingInventoryItems.size() << " inventory links that need to be replaced." << LL_ENDL; - if (items.size() > 0) + if (mRemainingInventoryItems.size() > 0) { LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); if (target_item) { - mRemainingItems = (U32)items.size(); + mRemainingItems = (U32)mRemainingInventoryItems.size(); LLStringUtil::format_map_t args; args["NUM"] = llformat("%d", mRemainingItems); mStatusText->setText(getString("ItemsRemaining", args)); - const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - LLPointer source_item = *it; + mStartBtn->setEnabled(FALSE); + mRefreshBtn->setEnabled(FALSE); - if (source_item->getParentUUID() != cof_folder_id) - { - bool is_outfit_folder = gInventory.isObjectDescendentOf(source_item->getParentUUID(), outfit_folder_id); - // If either the new or old item in the COF is a wearable, we need to update wearable ordering after the link has been replaced - bool needs_wearable_ordering_update = is_outfit_folder && source_item->getType() == LLAssetType::AT_CLOTHING || target_item->getType() == LLAssetType::AT_CLOTHING; - // Other items in the COF need a description update (description of the actual link item must be empty) - bool needs_description_update = is_outfit_folder && target_item->getType() != LLAssetType::AT_CLOTHING; - - LL_DEBUGS() << "is_outfit_folder = " << (is_outfit_folder ? "true" : "false") << LL_NEWLINE - << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE - << "needs_description_update = " << (needs_description_update ? "true" : "false") << LL_ENDL; - - LLInventoryObject::const_object_list_t obj_array; - obj_array.push_back(LLConstPointer(target_item)); - link_inventory_array(source_item->getParentUUID(), - obj_array, - new LLBoostFuncInventoryCallback(boost::bind(&FSFloaterLinkReplace::linkCreatedCallback, - this, - source_item->getUUID(), - target_item->getUUID(), - needs_wearable_ordering_update, - needs_description_update, - (is_outfit_folder ? source_item->getParentUUID() : LLUUID::null) ))); - } - else - { - decreaseOpenItemCount(); - } - } + mEventTimer.start(); + tick(); } else { @@ -189,6 +166,7 @@ void FSFloaterLinkReplace::onStartClicked() LL_WARNS() << "Link replace target not found." << LL_ENDL; } } + } void FSFloaterLinkReplace::linkCreatedCallback(const LLUUID& old_item_id, @@ -256,7 +234,10 @@ void FSFloaterLinkReplace::linkCreatedCallback(const LLUUID& old_item_id, remove_inventory_object(old_item_id, NULL); } - decreaseOpenItemCount(); + if (mInstance) + { + decreaseOpenItemCount(); + } } void FSFloaterLinkReplace::decreaseOpenItemCount() @@ -266,6 +247,9 @@ void FSFloaterLinkReplace::decreaseOpenItemCount() if (mRemainingItems == 0) { mStatusText->setText(getString("ReplaceFinished")); + mStartBtn->setEnabled(TRUE); + mRefreshBtn->setEnabled(TRUE); + mEventTimer.stop(); LL_INFOS() << "Inventory link replace finished." << LL_ENDL; } else @@ -277,3 +261,66 @@ void FSFloaterLinkReplace::decreaseOpenItemCount() } } +BOOL FSFloaterLinkReplace::tick() +{ + LL_DEBUGS() << "Calling tick - remaining items = " << mRemainingInventoryItems.size() << LL_ENDL; + + LLInventoryModel::item_array_t current_batch; + + for (U32 i = 0; i < MAX_BATCH_SIZE; ++i) + { + if (!mRemainingInventoryItems.size()) + { + mEventTimer.stop(); + break; + } + + current_batch.push_back(mRemainingInventoryItems.back()); + mRemainingInventoryItems.pop_back(); + } + processBatch(current_batch); + + return FALSE; +} + +void FSFloaterLinkReplace::processBatch(LLInventoryModel::item_array_t items) +{ + const LLViewerInventoryItem* target_item = gInventory.getItem(mTargetUUID); + const LLUUID cof_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const LLUUID outfit_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) + { + LLPointer source_item = *it; + + if (source_item->getParentUUID() != cof_folder_id) + { + bool is_outfit_folder = gInventory.isObjectDescendentOf(source_item->getParentUUID(), outfit_folder_id); + // If either the new or old item in the COF is a wearable, we need to update wearable ordering after the link has been replaced + bool needs_wearable_ordering_update = is_outfit_folder && source_item->getType() == LLAssetType::AT_CLOTHING || target_item->getType() == LLAssetType::AT_CLOTHING; + // Other items in the COF need a description update (description of the actual link item must be empty) + bool needs_description_update = is_outfit_folder && target_item->getType() != LLAssetType::AT_CLOTHING; + + LL_DEBUGS() << "is_outfit_folder = " << (is_outfit_folder ? "true" : "false") << LL_NEWLINE + << "needs_wearable_ordering_update = " << (needs_wearable_ordering_update ? "true" : "false") << LL_NEWLINE + << "needs_description_update = " << (needs_description_update ? "true" : "false") << LL_ENDL; + + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(LLConstPointer(target_item)); + link_inventory_array(source_item->getParentUUID(), + obj_array, + new LLBoostFuncInventoryCallback(boost::bind(&FSFloaterLinkReplace::linkCreatedCallback, + this, + source_item->getUUID(), + target_item->getUUID(), + needs_wearable_ordering_update, + needs_description_update, + (is_outfit_folder ? source_item->getParentUUID() : LLUUID::null) ))); + } + else + { + decreaseOpenItemCount(); + } + } +} + diff --git a/indra/newview/fsfloaterlinkreplace.h b/indra/newview/fsfloaterlinkreplace.h index cd457a83ba..55451409df 100644 --- a/indra/newview/fsfloaterlinkreplace.h +++ b/indra/newview/fsfloaterlinkreplace.h @@ -28,12 +28,15 @@ #define FS_FLOATERLINKREPLACE_H #include "llfloater.h" +#include "lleventtimer.h" +#include "llinventoryfunctions.h" +#include "llviewerinventory.h" class FSInventoryLinkReplaceDropTarget; class LLButton; class LLTextBox; -class FSFloaterLinkReplace : public LLFloater +class FSFloaterLinkReplace : public LLFloater, LLEventTimer { LOG_CLASS(FSFloaterLinkReplace); @@ -44,11 +47,14 @@ public: BOOL postBuild(); virtual void onOpen(const LLSD& key); + virtual BOOL tick(); + private: void checkEnableStart(); void onStartClicked(); void decreaseOpenItemCount(); void updateFoundLinks(); + void processBatch(LLInventoryModel::item_array_t items); void linkCreatedCallback(const LLUUID& old_item_id, const LLUUID& target_item_id, @@ -62,11 +68,16 @@ private: FSInventoryLinkReplaceDropTarget* mSourceEditor; FSInventoryLinkReplaceDropTarget* mTargetEditor; LLButton* mStartBtn; + LLButton* mRefreshBtn; LLTextBox* mStatusText; LLUUID mSourceUUID; LLUUID mTargetUUID; U32 mRemainingItems; + + LLInventoryModel::item_array_t mRemainingInventoryItems; + + FSFloaterLinkReplace* mInstance; }; #endif // FS_FLOATERLINKREPLACE_H