summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2023-11-15 22:15:03 +0200
committerakleshchev <117672381+akleshchev@users.noreply.github.com>2023-11-16 18:30:46 +0200
commitfda96e36806dab544709ac87156949c3accc5cf8 (patch)
treef20d0df15a2409553b6ca740f8891292b81a4a1d
parent7ff358efc46a07c1ed3bc845c693d67c5eb95b69 (diff)
SL-20575 When opening menu cache results and spread load over frames
-rw-r--r--indra/newview/llinventorybridge.cpp228
-rw-r--r--indra/newview/llinventorybridge.h40
-rw-r--r--indra/newview/llinventoryfunctions.cpp25
3 files changed, 267 insertions, 26 deletions
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 5b2a1366bd..acdbeead9d 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -773,9 +773,6 @@ void hide_context_entries(LLMenuGL& menu,
bool found = false;
- std::string myinput;
- std::vector<std::string> mylist{ "a", "b", "c" };
-
menuentry_vec_t::const_iterator itor2 = std::find(entries_to_show.begin(), entries_to_show.end(), name);
if (itor2 != entries_to_show.end())
{
@@ -872,7 +869,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
items.push_back(std::string("Cut"));
- if (!isItemMovable() || !isItemRemovable())
+ if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
}
@@ -921,7 +918,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
if(!single_folder_root)
{
items.push_back(std::string("Cut"));
- if (!isItemMovable() || !isItemRemovable())
+ if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
}
@@ -1063,7 +1060,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
items.push_back(std::string("Delete"));
- if (!isItemRemovable(false) || isPanelActive("Favorite Items"))
+ if (isPanelActive("Favorite Items") || !canMenuDelete())
{
disabled_items.push_back(std::string("Delete"));
}
@@ -1219,6 +1216,16 @@ void LLInvFVBridge::addLinkReplaceMenuOption(menuentry_vec_t& items, menuentry_v
}
}
+bool LLInvFVBridge::canMenuDelete()
+{
+ return isItemRemovable(false);
+}
+
+bool LLInvFVBridge::canMenuCut()
+{
+ return isItemRemovable(true);
+}
+
// *TODO: remove this
BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
{
@@ -4478,7 +4485,7 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
return;
}
- if (!isItemRemovable(false))
+ if (!canMenuDelete())
{
disabled_items.push_back(std::string("Delete"));
}
@@ -4848,6 +4855,192 @@ void LLFolderBridge::modifyOutfit(BOOL append)
}
}
+//static
+void LLFolderBridge::onCanDeleteIdle(void* user_data)
+{
+ LLFolderBridge* self = (LLFolderBridge*)user_data;
+
+ // we really need proper onidle mechanics that returns available time
+ const F32 EXPIRY_SECONDS = 0.008f;
+ LLTimer timer;
+ timer.setTimerExpirySec(EXPIRY_SECONDS);
+
+ LLInventoryModel* model = self->getInventoryModel();
+ if (model)
+ {
+ switch (self->mCanDeleteFolderState)
+ {
+ case CDS_INIT_FOLDER_CHECK:
+ // Can still be expensive, split it further?
+ model->collectDescendents(
+ self->mUUID,
+ self->mFoldersToCheck,
+ self->mItemsToCheck,
+ LLInventoryModel::EXCLUDE_TRASH);
+ self->mCanDeleteFolderState = CDS_PROCESSING_ITEMS;
+ break;
+
+ case CDS_PROCESSING_ITEMS:
+ while (!timer.hasExpired() && !self->mItemsToCheck.empty())
+ {
+ LLViewerInventoryItem* item = self->mItemsToCheck.back().get();
+ if (item)
+ {
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
+ {
+ if (get_is_item_worn(item))
+ {
+ // At the moment we disable 'cut' if category has worn items (do we need to?)
+ // but allow 'delete' to happen since it will prompt user to detach
+ self->mCanCut = false;
+ }
+ }
+
+ if (!item->getIsLinkType() && get_is_item_worn(item))
+ {
+ self->mCanCut = false;
+ }
+ }
+ self->mItemsToCheck.pop_back();
+ }
+ self->mCanDeleteFolderState = CDS_PROCESSING_FOLDERS;
+ break;
+ case CDS_PROCESSING_FOLDERS:
+ {
+ const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
+ LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr;
+
+ while (!timer.hasExpired() && !self->mFoldersToCheck.empty())
+ {
+ LLViewerInventoryCategory* cat = self->mFoldersToCheck.back().get();
+ if (cat)
+ {
+ const LLFolderType::EType folder_type = cat->getPreferredType();
+ if (LLFolderType::lookupIsProtectedType(folder_type))
+ {
+ self->mCanCut = false;
+ self->mCanDelete = false;
+ self->completeDeleteProcessing();
+ break;
+ }
+
+ // Can't delete the outfit that is currently being worn.
+ if (folder_type == LLFolderType::FT_OUTFIT)
+ {
+ if (cat == outfit_linked_category)
+ {
+ self->mCanCut = false;
+ self->mCanDelete = false;
+ self->completeDeleteProcessing();
+ break;
+ }
+ }
+ }
+ self->mFoldersToCheck.pop_back();
+ }
+ }
+ self->mCanDeleteFolderState = CDS_DONE;
+ break;
+ case CDS_DONE:
+ self->completeDeleteProcessing();
+ break;
+ }
+ }
+}
+
+bool LLFolderBridge::canMenuDelete()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (!model) return false;
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ if (!category)
+ {
+ return false;
+ }
+
+ S32 version = category->getVersion();
+ if (mLastCheckedVersion == version)
+ {
+ return mCanDelete;
+ }
+
+ initCanDeleteProcessing(model, version);
+ return false;
+}
+
+bool LLFolderBridge::canMenuCut()
+{
+ LLInventoryModel* model = getInventoryModel();
+ if (!model) return false;
+ LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
+ if (!category)
+ {
+ return false;
+ }
+
+ S32 version = category->getVersion();
+ if (mLastCheckedVersion == version)
+ {
+ return mCanCut;
+ }
+
+ initCanDeleteProcessing(model, version);
+ return false;
+}
+
+void LLFolderBridge::initCanDeleteProcessing(LLInventoryModel* model, S32 version)
+{
+ if (mCanDeleteFolderState == CDS_DONE
+ || mInProgressVersion != version)
+ {
+ if (get_is_category_removable(model, mUUID))
+ {
+ // init recursive check of content
+ mInProgressVersion = version;
+ mCanCut = true;
+ mCanDelete = true;
+ mCanDeleteFolderState = CDS_INIT_FOLDER_CHECK;
+ mFoldersToCheck.clear();
+ mItemsToCheck.clear();
+ gIdleCallbacks.addFunction(onCanDeleteIdle, this);
+ }
+ else
+ {
+ // no check needed
+ mCanDelete = false;
+ mCanCut = false;
+ mLastCheckedVersion = version;
+ mCanDeleteFolderState = CDS_DONE;
+ mFoldersToCheck.clear();
+ mItemsToCheck.clear();
+ }
+ }
+}
+
+void LLFolderBridge::completeDeleteProcessing()
+{
+ LLInventoryModel* model = getInventoryModel();
+ LLViewerInventoryCategory* category = model ? (LLViewerInventoryCategory*)model->getCategory(mUUID) : nullptr;
+ if (model && category && category->getVersion() == mInProgressVersion)
+ {
+ mLastCheckedVersion = mInProgressVersion;
+ mCanDeleteFolderState = CDS_DONE;
+ gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
+ }
+ else
+ {
+ mCanDelete = false;
+ mCanCut = false;
+ mLastCheckedVersion = LLViewerInventoryCategory::VERSION_UNKNOWN;
+ mCanDeleteFolderState = CDS_DONE;
+ }
+
+ if (mRoot)
+ {
+ mRoot->updateMenu();
+ }
+}
+
// +=================================================+
// | LLMarketplaceFolderBridge |
@@ -5009,6 +5202,27 @@ void drop_to_favorites_cb(const LLUUID& id, LLPointer<LLInventoryCallback> cb1,
cb2->fire(id);
}
+LLFolderBridge::LLFolderBridge(LLInventoryPanel* inventory,
+ LLFolderView* root,
+ const LLUUID& uuid)
+ : LLInvFVBridge(inventory, root, uuid)
+ , mCallingCards(FALSE)
+ , mWearables(FALSE)
+ , mIsLoading(false)
+ , mShowDescendantsCount(false)
+ , mCanDeleteFolderState(CDS_DONE)
+ , mLastCheckedVersion(S32_MIN)
+ , mInProgressVersion(S32_MIN)
+ , mCanDelete(false)
+ , mCanCut(false)
+{
+}
+
+LLFolderBridge::~LLFolderBridge()
+{
+ gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
+}
+
void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb)
{
// use callback to rearrange favorite landmarks after adding
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 0d87e2b97c..c493067fc4 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -162,6 +162,9 @@ protected:
virtual void addLinkReplaceMenuOption(menuentry_vec_t& items,
menuentry_vec_t& disabled_items);
+ virtual bool canMenuDelete();
+ virtual bool canMenuCut();
+
protected:
LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid);
@@ -272,14 +275,10 @@ class LLFolderBridge : public LLInvFVBridge
public:
LLFolderBridge(LLInventoryPanel* inventory,
LLFolderView* root,
- const LLUUID& uuid)
- : LLInvFVBridge(inventory, root, uuid),
- mCallingCards(FALSE),
- mWearables(FALSE),
- mIsLoading(false),
- mShowDescendantsCount(false)
- {}
-
+ const LLUUID& uuid);
+
+ ~LLFolderBridge();
+
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
@@ -392,6 +391,31 @@ protected:
LLTimer mTimeSinceRequestStart;
std::string mMessage;
LLRootHandle<LLFolderBridge> mHandle;
+
+private:
+ // checking if folder is cutable or deletable is expensive,
+ // cache values and split check over frames
+ static void onCanDeleteIdle(void* user_data);
+ void initCanDeleteProcessing(LLInventoryModel* model, S32 version);
+ void completeDeleteProcessing();
+ bool canMenuDelete();
+ bool canMenuCut();
+
+ enum ECanDeleteState
+ {
+ CDS_INIT_FOLDER_CHECK,
+ CDS_PROCESSING_ITEMS,
+ CDS_PROCESSING_FOLDERS,
+ CDS_DONE,
+ };
+
+ ECanDeleteState mCanDeleteFolderState;
+ LLInventoryModel::cat_array_t mFoldersToCheck;
+ LLInventoryModel::item_array_t mItemsToCheck;
+ S32 mLastCheckedVersion;
+ S32 mInProgressVersion;
+ bool mCanDelete;
+ bool mCanCut;
};
class LLTextureBridge : public LLItemBridge
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index a260b62c69..97568fede1 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -840,23 +840,26 @@ bool get_is_category_and_children_removable(LLInventoryModel* model, const LLUUI
item_array,
LLInventoryModel::EXCLUDE_TRASH);
- for (LLInventoryModel::item_array_t::value_type& item : item_array)
+ if (check_worn)
{
- // Disable delete from COF folder; have users explicitly choose "detach/take off",
- // unless the item is not worn but in the COF (i.e. is bugged).
- if (item)
+ for (LLInventoryModel::item_array_t::value_type& item : item_array)
{
- if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
+ // Disable delete/cut from COF folder; have users explicitly choose "detach/take off",
+ // unless the item is not worn but in the COF (i.e. is bugged).
+ if (item)
{
- if (get_is_item_worn(item))
+ if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
{
- return false;
+ if (get_is_item_worn(item))
+ {
+ return false;
+ }
}
- }
- if (check_worn && !item->getIsLinkType() && get_is_item_worn(item))
- {
- return false;
+ if (!item->getIsLinkType() && get_is_item_worn(item))
+ {
+ return false;
+ }
}
}
}