From fadc09ba3901aad4f69dfc851e554b127919cb4e Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 9 Oct 2023 23:39:45 +0200 Subject: SL-20288 Lags in Appearance floater --- indra/newview/lloutfitslist.cpp | 89 ++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 14 deletions(-) (limited to 'indra/newview/lloutfitslist.cpp') diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 5c7792b0df..8042b87a44 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -835,7 +835,6 @@ void LLOutfitListBase::onOpen(const LLSD& info) // arrive. category->fetch(); refreshList(outfits); - highlightBaseOutfit(); mIsInitialized = true; } @@ -843,6 +842,9 @@ void LLOutfitListBase::onOpen(const LLSD& info) void LLOutfitListBase::refreshList(const LLUUID& category_id) { + bool wasNull = mRefreshListState.CategoryUUID.isNull(); + mRefreshListState.CategoryUUID.setNull(); + LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; @@ -855,27 +857,81 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) LLInventoryModel::EXCLUDE_TRASH, is_category); - uuid_vec_t vadded; - uuid_vec_t vremoved; + // Memorize item names for each UUID + std::map names; + for (const LLPointer& cat : cat_array) + { + names.emplace(std::make_pair(cat->getUUID(), cat->getName())); + } + + // Fill added and removed items vectors. + mRefreshListState.Added.clear(); + mRefreshListState.Removed.clear(); + computeDifference(cat_array, mRefreshListState.Added, mRefreshListState.Removed); + // Sort added items vector by item name. + std::sort(mRefreshListState.Added.begin(), mRefreshListState.Added.end(), + [names](const LLUUID& a, const LLUUID& b) + { + return LLStringUtil::compareDict(names.at(a), names.at(b)) < 0; + }); + // Initialize iterators for added and removed items vectors. + mRefreshListState.AddedIterator = mRefreshListState.Added.begin(); + mRefreshListState.RemovedIterator = mRefreshListState.Removed.begin(); + + LL_INFOS() << "added: " << mRefreshListState.Added.size() << + ", removed: " << mRefreshListState.Removed.size() << + ", changed: " << gInventory.getChangedIDs().size() << + LL_ENDL; + + mRefreshListState.CategoryUUID = category_id; + if (wasNull) + { + gIdleCallbacks.addFunction(onIdle, this); + } +} + +// static +void LLOutfitListBase::onIdle(void* userdata) +{ + LLOutfitListBase* self = (LLOutfitListBase*)userdata; + + self->onIdleRefreshList(); +} + +void LLOutfitListBase::onIdleRefreshList() +{ + if (mRefreshListState.CategoryUUID.isNull()) + return; - // Create added and removed items vectors. - computeDifference(cat_array, vadded, vremoved); + const F64 MAX_TIME = 0.05f; + F64 curent_time = LLTimer::getTotalSeconds(); + const F64 end_time = curent_time + MAX_TIME; // Handle added tabs. - for (uuid_vec_t::const_iterator iter = vadded.begin(); - iter != vadded.end(); - ++iter) + while (mRefreshListState.AddedIterator < mRefreshListState.Added.end()) { - const LLUUID cat_id = (*iter); + const LLUUID cat_id = (*mRefreshListState.AddedIterator++); updateAddedCategory(cat_id); + + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; } + mRefreshListState.Added.clear(); + mRefreshListState.AddedIterator = mRefreshListState.Added.end(); // Handle removed tabs. - for (uuid_vec_t::const_iterator iter = vremoved.begin(); iter != vremoved.end(); ++iter) + while (mRefreshListState.RemovedIterator < mRefreshListState.Removed.end()) { - const LLUUID cat_id = (*iter); + const LLUUID cat_id = (*mRefreshListState.RemovedIterator++); updateRemovedCategory(cat_id); + + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; } + mRefreshListState.Removed.clear(); + mRefreshListState.RemovedIterator = mRefreshListState.Removed.end(); // Get changed items from inventory model and update outfit tabs // which might have been renamed. @@ -888,9 +944,9 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) if (!cat) { LLInventoryObject* obj = gInventory.getObject(*items_iter); - if(!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) + if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) { - return; + break; } cat = (LLViewerInventoryCategory*)obj; } @@ -900,6 +956,12 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) } sortOutfits(); + highlightBaseOutfit(); + + gIdleCallbacks.deleteFunction(onIdle, this); + mRefreshListState.CategoryUUID.setNull(); + + LL_INFOS() << "done" << LL_ENDL; } void LLOutfitListBase::computeDifference( @@ -936,7 +998,6 @@ void LLOutfitListBase::highlightBaseOutfit() mHighlightedOutfitUUID = base_id; onHighlightBaseOutfit(base_id, prev_id); } - } void LLOutfitListBase::removeSelected() -- cgit v1.3 From 42e062888f6276c1e2dc043514a270a8dcf580db Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 10 Oct 2023 23:21:08 +0200 Subject: SL-20432 Filtering My Outfits with big number of items freezes UI --- indra/llui/llaccordionctrltab.h | 10 +-- indra/llui/llflatlistview.cpp | 47 ++++++++----- indra/llui/llflatlistview.h | 11 +-- indra/newview/llinventoryitemslist.cpp | 2 +- indra/newview/llinventoryitemslist.h | 8 +-- indra/newview/lloutfitgallery.cpp | 41 +++++------ indra/newview/lloutfitgallery.h | 4 +- indra/newview/lloutfitslist.cpp | 110 +++++++++++------------------- indra/newview/lloutfitslist.h | 9 +-- indra/newview/llpanelappearancetab.cpp | 27 +++++++- indra/newview/llpanelappearancetab.h | 13 +++- indra/newview/llpaneloutfitedit.cpp | 5 +- indra/newview/llpaneloutfitsinventory.cpp | 30 +++----- indra/newview/llpaneloutfitsinventory.h | 1 - indra/newview/llpanelwearing.cpp | 9 ++- indra/newview/llpanelwearing.h | 2 +- 16 files changed, 158 insertions(+), 171 deletions(-) (limited to 'indra/newview/lloutfitslist.cpp') diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 896a34cac4..496c34c38b 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -126,12 +126,12 @@ public: void setSelected(bool is_selected); - bool getCollapsible() {return mCollapsible;}; + bool getCollapsible() { return mCollapsible; }; - void setCollapsible(bool collapsible) {mCollapsible = collapsible;}; + void setCollapsible(bool collapsible) { mCollapsible = collapsible; }; void changeOpenClose(bool is_open); - void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;}; + void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; }; bool canOpenClose() const { return mCanOpenClose; }; virtual BOOL postBuild(); @@ -142,8 +142,8 @@ public: void draw(); - void storeOpenCloseState (); - void restoreOpenCloseState (); + void storeOpenCloseState(); + void restoreOpenCloseState(); protected: LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&); diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 460bd0945b..e4f2dd11a4 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1361,26 +1361,28 @@ void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show) mForceShowingUnmatchedItems = show; } -void LLFlatListViewEx::setFilterSubString(const std::string& filter_str) +void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent) { if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) { mFilterSubString = filter_str; updateNoItemsMessage(mFilterSubString); - filterItems(); + filterItems(false, notify_parent); } } -void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) +bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) { - if (!item) return; + if (!item) + return false; + + BOOL visible = TRUE; // 0 signifies that filter is matched, // i.e. we don't hide items that don't support 'match_filter' action, separators etc. if (0 == item->notify(action)) { mHasMatchedItems = true; - item->setVisible(true); } else { @@ -1388,12 +1390,20 @@ void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) if (!mForceShowingUnmatchedItems) { selectItem(item, false); + visible = FALSE; } - item->setVisible(mForceShowingUnmatchedItems); } + + if (item->getVisible() != visible) + { + item->setVisible(visible); + return true; + } + + return false; } -void LLFlatListViewEx::filterItems() +void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent) { typedef std::vector item_panel_list_t; @@ -1403,19 +1413,24 @@ void LLFlatListViewEx::filterItems() LLSD action; action.with("match_filter", cur_filter); - item_panel_list_t items; - getItems(items); - mHasMatchedItems = false; - item_panel_list_t::iterator iter = items.begin(), iter_end = items.end(); - while (iter < iter_end) + bool visibility_changed = false; + pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end(); + while (iter != iter_end) { - LLPanel* pItem = *(iter++); - updateItemVisibility(pItem, action); + LLPanel* pItem = (*(iter++))->first; + visibility_changed |= updateItemVisibility(pItem, action); } - sort(); - notifyParentItemsRectChanged(); + if (re_sort) + { + sort(); + } + + if (visibility_changed && notify_parent) + { + notifyParentItemsRectChanged(); + } } bool LLFlatListViewEx::hasMatchedItems() diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index d47c1cf333..adb0e3e553 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -300,6 +300,7 @@ public: virtual S32 notify(const LLSD& info) ; virtual ~LLFlatListView(); + protected: /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ @@ -375,7 +376,9 @@ protected: LLRect getLastSelectedItemRect(); - void ensureSelectedVisible(); + void ensureSelectedVisible(); + + const pairs_list_t& getItemPairs() { return mItemPairs; } private: @@ -482,14 +485,14 @@ public: /** * Sets up new filter string and filters the list. */ - void setFilterSubString(const std::string& filter_str); + void setFilterSubString(const std::string& filter_str, bool notify_parent); std::string getFilterSubString() { return mFilterSubString; } /** * Filters the list, rearranges and notifies parent about shape changes. * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. */ - void filterItems(); + void filterItems(bool re_sort, bool notify_parent); /** * Returns true if last call of filterItems() found at least one matching item @@ -513,7 +516,7 @@ protected: * @param item - item we are changing * @param item - action - parameters to determin visibility from */ - void updateItemVisibility(LLPanel* item, const LLSD &action); + bool updateItemVisibility(LLPanel* item, const LLSD &action); private: std::string mNoFilteredItemsMsg; diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp index 23129f7d44..cac859387c 100644 --- a/indra/newview/llinventoryitemslist.cpp +++ b/indra/newview/llinventoryitemslist.cpp @@ -240,7 +240,7 @@ void LLInventoryItemsList::refresh() case REFRESH_LIST_SORT: { // Filter, sort, rearrange and notify parent about shape changes - filterItems(); + filterItems(true, true); if (mAddedItems.size() == 0) { diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h index ce41105f98..5b83298bb9 100644 --- a/indra/newview/llinventoryitemslist.h +++ b/indra/newview/llinventoryitemslist.h @@ -51,20 +51,20 @@ public: /** * Let list know items need to be refreshed in next doIdle() */ - void setNeedsRefresh(bool needs_refresh){ mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; } + void setNeedsRefresh(bool needs_refresh) { mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; } - U32 getNeedsRefresh(){ return mRefreshState; } + U32 getNeedsRefresh() { return mRefreshState; } /** * Sets the flag indicating that the list needs to be refreshed even if it is * not currently visible. */ - void setForceRefresh(bool force_refresh){ mForceRefresh = force_refresh; } + void setForceRefresh(bool force_refresh) { mForceRefresh = force_refresh; } /** * If refreshes when invisible. */ - bool getForceRefresh(){ return mForceRefresh; } + bool getForceRefresh() { return mForceRefresh; } virtual bool selectItemByValue(const LLSD& value, bool select = true); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index de988555c5..e621c32911 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -433,8 +433,7 @@ bool compareGalleryItem(LLOutfitGalleryItem* item1, LLOutfitGalleryItem* item2) } void LLOutfitGallery::reArrangeRows(S32 row_diff) -{ - +{ std::vector buf_items = mItems; for (std::vector::const_reverse_iterator it = buf_items.rbegin(); it != buf_items.rend(); ++it) { @@ -446,16 +445,24 @@ void LLOutfitGallery::reArrangeRows(S32 row_diff) } mHiddenItems.clear(); - mItemsInRow+= row_diff; + mItemsInRow += row_diff; updateGalleryWidth(); std::sort(buf_items.begin(), buf_items.end(), compareGalleryItem); - + + std::string cur_filter = getFilterSubString(); + LLStringUtil::toUpper(cur_filter); + for (std::vector::const_iterator it = buf_items.begin(); it != buf_items.end(); ++it) { - (*it)->setHidden(false); - applyFilter(*it,sFilterSubString); + std::string outfit_name = (*it)->getItemName(); + LLStringUtil::toUpper(outfit_name); + + bool hidden = (std::string::npos == outfit_name.find(cur_filter)); + (*it)->setHidden(hidden); + addToGallery(*it); } + updateMessageVisibility(); } @@ -725,9 +732,9 @@ LLOutfitGallery::~LLOutfitGallery() } } -void LLOutfitGallery::setFilterSubString(const std::string& string) +// virtual +void LLOutfitGallery::onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) { - sFilterSubString = string; reArrangeRows(); } @@ -743,20 +750,6 @@ void LLOutfitGallery::onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id) } } -void LLOutfitGallery::applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring) -{ - if (!item) return; - - std::string outfit_name = item->getItemName(); - LLStringUtil::toUpper(outfit_name); - - std::string cur_filter = filter_substring; - LLStringUtil::toUpper(cur_filter); - - bool hidden = (std::string::npos == outfit_name.find(cur_filter)); - item->setHidden(hidden); -} - void LLOutfitGallery::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) { } @@ -904,11 +897,11 @@ bool LLOutfitGallery::hasDefaultImage(const LLUUID& outfit_cat_id) void LLOutfitGallery::updateMessageVisibility() { - if(mItems.empty()) + if (mItems.empty()) { mMessageTextBox->setVisible(TRUE); mScrollPanel->setVisible(FALSE); - std::string message = sFilterSubString.empty()? getString("no_outfits_msg") : getString("no_matched_outfits_msg"); + std::string message = getString(getFilterSubString().empty() ? "no_outfits_msg" : "no_matched_outfits_msg"); mMessageTextBox->setValue(message); } else diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 9915752962..f2366e6494 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -90,7 +90,7 @@ public: void wearSelectedOutfit(); - /*virtual*/ void setFilterSubString(const std::string& string); + /*virtual*/ void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string); /*virtual*/ void getCurrentCategories(uuid_vec_t& vcur); /*virtual*/ void updateAddedCategory(LLUUID cat_id); @@ -117,8 +117,6 @@ protected: /*virtual*/ void onExpandAllFolders() {} /*virtual*/ LLOutfitListGearMenuBase* createGearMenu(); - void applyFilter(LLOutfitGalleryItem* item, const std::string& filter_substring); - private: LLUUID getPhotoAssetId(const LLUUID& outfit_id); LLUUID getDefaultPhoto(); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 8042b87a44..27d73fc4ae 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -188,7 +188,7 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) list->setCommitCallback(boost::bind(&LLOutfitsList::onListSelectionChange, this, _1)); // Setting list refresh callback to apply filter on list change. - list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1)); + list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onRefreshComplete, this, _1)); list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3)); @@ -199,19 +199,17 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) // Further list updates will be triggered by the category observer. list->updateList(cat_id); - // If filter is currently applied we store the initial tab state and - // open it to show matched items if any. - if (!sFilterSubString.empty()) + // If filter is currently applied we store the initial tab state. + if (!getFilterSubString().empty()) { tab->notifyChildren(LLSD().with("action", "store_state")); - tab->setDisplayChildren(true); // Setting mForceRefresh flag will make the list refresh its contents // even if it is not currently visible. This is required to apply the // filter to the newly added list. list->setForceRefresh(true); - list->setFilterSubString(sFilterSubString); + list->setFilterSubString(getFilterSubString(), false); } } @@ -313,14 +311,6 @@ void LLOutfitsList::onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) } } -// virtual -void LLOutfitsList::setFilterSubString(const std::string& string) -{ - applyFilter(string); - - sFilterSubString = string; -} - // virtual bool LLOutfitListBase::isActionEnabled(const LLSD& userdata) { @@ -494,9 +484,9 @@ void LLOutfitsList::restoreOutfitSelection(LLAccordionCtrlTab* tab, const LLUUID } } -void LLOutfitsList::onFilteredWearableItemsListRefresh(LLUICtrl* ctrl) +void LLOutfitsList::onRefreshComplete(LLUICtrl* ctrl) { - if (!ctrl || sFilterSubString.empty()) + if (!ctrl || getFilterSubString().empty()) return; for (outfits_map_t::iterator @@ -510,57 +500,50 @@ void LLOutfitsList::onFilteredWearableItemsListRefresh(LLUICtrl* ctrl) LLWearableItemsList* list = dynamic_cast(tab->getAccordionView()); if (list != ctrl) continue; - applyFilterToTab(iter->first, tab, sFilterSubString); + applyFilterToTab(iter->first, tab, getFilterSubString()); } } -void LLOutfitsList::applyFilter(const std::string& new_filter_substring) +// virtual +void LLOutfitsList::onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) { - mAccordion->setFilterSubString(new_filter_substring); + mAccordion->setFilterSubString(new_string); - for (outfits_map_t::iterator - iter = mOutfitsMap.begin(), - iter_end = mOutfitsMap.end(); - iter != iter_end; ++iter) + outfits_map_t::iterator iter = mOutfitsMap.begin(), iter_end = mOutfitsMap.end(); + while (iter != iter_end) { - LLAccordionCtrlTab* tab = iter->second; + const LLUUID& category_id = iter->first; + LLAccordionCtrlTab* tab = iter++->second; if (!tab) continue; - bool more_restrictive = sFilterSubString.size() < new_filter_substring.size() && !new_filter_substring.substr(0, sFilterSubString.size()).compare(sFilterSubString); - - // Restore tab visibility in case of less restrictive filter - // to compare it with updated string if it was previously hidden. - if (!more_restrictive) - { - tab->setVisible(TRUE); - } - LLWearableItemsList* list = dynamic_cast(tab->getAccordionView()); if (list) { - list->setFilterSubString(new_filter_substring); + list->setFilterSubString(new_string, tab->getDisplayChildren()); } - if(sFilterSubString.empty() && !new_filter_substring.empty()) + if (old_string.empty()) { - //store accordion tab state when filter is not empty - tab->notifyChildren(LLSD().with("action","store_state")); + // Store accordion tab state when filter is not empty + tab->notifyChildren(LLSD().with("action", "store_state")); } - if (!new_filter_substring.empty()) + if (!new_string.empty()) { - applyFilterToTab(iter->first, tab, new_filter_substring); + applyFilterToTab(category_id, tab, new_string); } else { - // restore tab title when filter is empty + tab->setVisible(TRUE); + + // Restore tab title when filter is empty tab->setTitle(tab->getTitle()); - //restore accordion state after all those accodrion tab manipulations - tab->notifyChildren(LLSD().with("action","restore_state")); + // Restore accordion state after all those accodrion tab manipulations + tab->notifyChildren(LLSD().with("action", "restore_state")); // Try restoring the tab selection. - restoreOutfitSelection(tab, iter->first); + restoreOutfitSelection(tab, category_id); } } @@ -586,11 +569,11 @@ void LLOutfitsList::applyFilterToTab( if (std::string::npos == title.find(cur_filter)) { - // hide tab if its title doesn't pass filter - // and it has no visible items + // Hide tab if its title doesn't pass filter + // and it has no matched items tab->setVisible(list->hasMatchedItems()); - // remove title highlighting because it might + // Remove title highlighting because it might // have been previously highlighted by less restrictive filter tab->setTitle(tab->getTitle()); @@ -602,18 +585,6 @@ void LLOutfitsList::applyFilterToTab( // Try restoring the tab selection. restoreOutfitSelection(tab, category_id); } - - if (tab->getVisible()) - { - // Open tab if it has passed the filter. - tab->setDisplayChildren(true); - } - else - { - // Set force refresh flag to refresh not visible list - // when some changes occur in it. - list->setForceRefresh(true); - } } bool LLOutfitsList::canWearSelected() @@ -698,11 +669,10 @@ void LLOutfitsList::onCOFChanged() // These links UUIDs are not the same UUIDs that we have in each wearable items list. // So we collect base items' UUIDs to find them or links that point to them in wearable // items lists and update their worn state there. - for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); - iter != item_array.end(); - ++iter) + LLInventoryModel::item_array_t::const_iterator array_iter = item_array.begin(), array_end = item_array.end(); + while (array_iter < array_end) { - vnew.push_back((*iter)->getLinkedUUID()); + vnew.push_back((*(array_iter++))->getLinkedUUID()); } // We need to update only items that were added or removed from COF. @@ -711,20 +681,20 @@ void LLOutfitsList::onCOFChanged() // Store the ids of items currently linked from COF. mCOFLinkedItems = vnew; - for (outfits_map_t::iterator iter = mOutfitsMap.begin(); - iter != mOutfitsMap.end(); - ++iter) + // Append removed ids to added ids because we should update all of them. + vadded.reserve(vadded.size() + vremoved.size()); + vadded.insert(vadded.end(), vremoved.begin(), vremoved.end()); + vremoved.clear(); + + outfits_map_t::iterator map_iter = mOutfitsMap.begin(), map_end = mOutfitsMap.end(); + while (map_iter != map_end) { - LLAccordionCtrlTab* tab = iter->second; + LLAccordionCtrlTab* tab = (map_iter++)->second; if (!tab) continue; LLWearableItemsList* list = dynamic_cast(tab->getAccordionView()); if (!list) continue; - // Append removed ids to added ids because we should update all of them. - vadded.reserve(vadded.size() + vremoved.size()); - vadded.insert(vadded.end(), vremoved.begin(), vremoved.end()); - // Every list updates the labels of changed items or // the links that point to these items. list->updateChangedItems(vadded); diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 7d212420a2..43c3ba75b5 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -237,7 +237,7 @@ public: //void performAction(std::string action); - /*virtual*/ void setFilterSubString(const std::string& string); + /*virtual*/ void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string); /*virtual*/ void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const; @@ -307,12 +307,7 @@ private: * Called upon list refresh event to update tab visibility depending on * the results of applying filter to the title and list items of the tab. */ - void onFilteredWearableItemsListRefresh(LLUICtrl* ctrl); - - /** - * Highlights filtered items and hides tabs which haven't passed filter. - */ - void applyFilter(const std::string& new_filter_substring); + void onRefreshComplete(LLUICtrl* ctrl); /** * Applies filter to the given tab diff --git a/indra/newview/llpanelappearancetab.cpp b/indra/newview/llpanelappearancetab.cpp index 8fa8867c69..16bd8a1380 100644 --- a/indra/newview/llpanelappearancetab.cpp +++ b/indra/newview/llpanelappearancetab.cpp @@ -28,12 +28,35 @@ #include "llpanelappearancetab.h" - #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llviewerinventory.h" -//virtual +std::string LLPanelAppearanceTab::sRecentFilterSubString; + +void LLPanelAppearanceTab::setFilterSubString(const std::string& new_string) +{ + if (new_string != mFilterSubString) + { + std::string old_string = mFilterSubString; + mFilterSubString = new_string; + onFilterSubStringChanged(mFilterSubString, old_string); + } + + sRecentFilterSubString = new_string; +} + +void LLPanelAppearanceTab::checkFilterSubString() +{ + if (sRecentFilterSubString != mFilterSubString) + { + std::string old_string = mFilterSubString; + mFilterSubString = sRecentFilterSubString; + onFilterSubStringChanged(mFilterSubString, old_string); + } +} + +// virtual bool LLPanelAppearanceTab::canTakeOffSelected() { uuid_vec_t selected_uuids; diff --git a/indra/newview/llpanelappearancetab.h b/indra/newview/llpanelappearancetab.h index 2ed6b00497..e81394dd3c 100644 --- a/indra/newview/llpanelappearancetab.h +++ b/indra/newview/llpanelappearancetab.h @@ -35,13 +35,17 @@ public: LLPanelAppearanceTab() : LLPanel() {} virtual ~LLPanelAppearanceTab() {} - virtual void setFilterSubString(const std::string& string) = 0; + void setFilterSubString(const std::string& new_string); + + void checkFilterSubString(); + + virtual void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) = 0; virtual bool isActionEnabled(const LLSD& userdata) = 0; virtual void getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const {} - static const std::string& getFilterSubString() { return sFilterSubString; } + const std::string& getFilterSubString() { return mFilterSubString; } protected: @@ -50,7 +54,10 @@ protected: */ bool canTakeOffSelected(); - static std::string sFilterSubString; +private: + std::string mFilterSubString; + + static std::string sRecentFilterSubString; }; #endif //LL_LLPANELAPPEARANCETAB_H diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 4a755a6e93..c7ae4eb0d9 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -733,7 +733,7 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string) if (mSearchString == "") { mInventoryItemsPanel->setFilterSubString(LLStringUtil::null); - mWearableItemsList->setFilterSubString(LLStringUtil::null); + mWearableItemsList->setFilterSubString(LLStringUtil::null, true); // re-open folders that were initially open mSavedFolderState->setApply(TRUE); mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); @@ -763,8 +763,7 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string) // set new filter string mInventoryItemsPanel->setFilterSubString(mSearchString); - mWearableItemsList->setFilterSubString(mSearchString); - + mWearableItemsList->setFilterSubString(mSearchString, true); } void LLPanelOutfitEdit::onPlusBtnClicked(void) diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index d8c34d5c40..af06de379d 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -28,19 +28,19 @@ #include "llpaneloutfitsinventory.h" -#include "llnotificationsutil.h" -#include "lltabcontainer.h" - +#include "llagentwearables.h" +#include "llappearancemgr.h" #include "llfloatersidepanelcontainer.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "lloutfitobserver.h" +#include "llnotificationsutil.h" #include "lloutfitgallery.h" +#include "lloutfitobserver.h" #include "lloutfitslist.h" +#include "llpanelappearancetab.h" #include "llpanelwearing.h" #include "llsidepanelappearance.h" +#include "lltabcontainer.h" #include "llviewercontrol.h" #include "llviewerfoldertype.h" @@ -159,25 +159,12 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string) { if (!mActivePanel) return; - mFilterSubString = string; - - if (string == "") - { - mActivePanel->setFilterSubString(LLStringUtil::null); - } - if (!LLInventoryModelBackgroundFetch::instance().inventoryFetchStarted()) { llassert(false); // this should have been done on startup LLInventoryModelBackgroundFetch::instance().start(); } - if (mActivePanel->getFilterSubString().empty() && string.empty()) - { - // current filter and new filter empty, do nothing - return; - } - // set new filter string mActivePanel->setFilterSubString(string); } @@ -302,6 +289,7 @@ bool LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata) { return mActivePanel && mActivePanel->isActionEnabled(userdata); } + // List Commands // ////////////////////////////////////////////////////////////////////////////////// @@ -330,7 +318,7 @@ void LLPanelOutfitsInventory::onTabChange() mActivePanel = dynamic_cast(mAppearanceTabs->getCurrentPanel()); if (!mActivePanel) return; - mActivePanel->setFilterSubString(mFilterSubString); + mActivePanel->checkFilterSubString(); mActivePanel->onOpen(LLSD()); updateVerbs(); @@ -357,8 +345,6 @@ bool LLPanelOutfitsInventory::isOutfitsGalleryPanelActive() const return mActivePanel->getName() == OUTFIT_GALLERY_TAB_NAME; } - - void LLPanelOutfitsInventory::setWearablesLoading(bool val) { updateVerbs(); diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 50d7074d4b..91873a427a 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -66,7 +66,6 @@ protected: private: LLTabContainer* mAppearanceTabs; - std::string mFilterSubString; ////////////////////////////////////////////////////////////////////////////////// // tab panels // diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 5242c4fef9..bfdb0fbc88 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -209,8 +209,6 @@ protected: ////////////////////////////////////////////////////////////////////////// -std::string LLPanelAppearanceTab::sFilterSubString = LLStringUtil::null; - static LLPanelInjector t_panel_wearing("panel_wearing"); LLPanelWearing::LLPanelWearing() @@ -328,10 +326,11 @@ void LLPanelWearing::startUpdateTimer() } // virtual -void LLPanelWearing::setFilterSubString(const std::string& string) +void LLPanelWearing::onFilterSubStringChanged(const std::string& new_string, const std::string& old_string) { - sFilterSubString = string; - mCOFItemsList->setFilterSubString(sFilterSubString); + mCOFItemsList->setFilterSubString(new_string, true); + + mAccordionCtrl->arrange(); } // virtual diff --git a/indra/newview/llpanelwearing.h b/indra/newview/llpanelwearing.h index 18e543eec6..2f3f14956a 100644 --- a/indra/newview/llpanelwearing.h +++ b/indra/newview/llpanelwearing.h @@ -61,7 +61,7 @@ public: /*virtual*/ void onOpen(const LLSD& info); - /*virtual*/ void setFilterSubString(const std::string& string); + /*virtual*/ void onFilterSubStringChanged(const std::string& new_string, const std::string& old_string); /*virtual*/ bool isActionEnabled(const LLSD& userdata); -- cgit v1.3 From 56c88b83435facd5023b8781a59ade12dc865e15 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 13 Mar 2024 22:15:56 +0200 Subject: SL-20288 Fix renaming getChangedIDs is only accurate in scope of observer's callback, don't use it onIdle. getObject call made no sense, item was warrantied to be LLViewerInventoryItem and would only be AT_CATEGORY if it is a link, making the following cast to a category dangerous --- indra/newview/lloutfitslist.cpp | 33 +++++++++++++++++++-------------- indra/newview/lloutfitslist.h | 2 ++ 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'indra/newview/lloutfitslist.cpp') diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 27d73fc4ae..352d59a9c2 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -790,7 +790,7 @@ void LLOutfitListBase::onOpen(const LLSD& info) // Start observing changes in "My Outfits" category. mCategoriesObserver->addCategory(outfits, - boost::bind(&LLOutfitListBase::refreshList, this, outfits)); + boost::bind(&LLOutfitListBase::observerCallback, this, outfits)); //const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); // Start observing changes in Current Outfit category. @@ -810,6 +810,13 @@ void LLOutfitListBase::onOpen(const LLSD& info) } } +void LLOutfitListBase::observerCallback(const LLUUID& category_id) +{ + const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs(); + mChangedItems.insert(changed_items.begin(), changed_items.end()); + refreshList(category_id); +} + void LLOutfitListBase::refreshList(const LLUUID& category_id) { bool wasNull = mRefreshListState.CategoryUUID.isNull(); @@ -905,24 +912,22 @@ void LLOutfitListBase::onIdleRefreshList() // Get changed items from inventory model and update outfit tabs // which might have been renamed. - const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs(); - for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin(); - items_iter != changed_items.end(); - ++items_iter) + while (!mChangedItems.empty()) { + std::set::const_iterator items_iter = mChangedItems.begin(); LLViewerInventoryCategory *cat = gInventory.getCategory(*items_iter); - if (!cat) + mChangedItems.erase(items_iter); + + // Links aren't supposed to be allowed here, check only cats + if (cat) { - LLInventoryObject* obj = gInventory.getObject(*items_iter); - if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY)) - { - break; - } - cat = (LLViewerInventoryCategory*)obj; + std::string name = cat->getName(); + updateChangedCategoryName(cat, name); } - std::string name = cat->getName(); - updateChangedCategoryName(cat, name); + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; } sortOutfits(); diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 43c3ba75b5..980b9c3970 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -109,6 +109,7 @@ public: virtual bool getHasExpandableFolders() = 0; protected: + void observerCallback(const LLUUID& category_id); virtual LLOutfitListGearMenuBase* createGearMenu() = 0; virtual void onHighlightBaseOutfit(LLUUID base_id, LLUUID prev_id) = 0; virtual void onSetSelectedOutfitByUUID(const LLUUID& outfit_uuid) = 0; @@ -127,6 +128,7 @@ protected: uuid_vec_t::const_iterator AddedIterator; uuid_vec_t::const_iterator RemovedIterator; } mRefreshListState; + std::set mChangedItems; bool mIsInitialized; LLInventoryCategoriesObserver* mCategoriesObserver; -- cgit v1.3