summaryrefslogtreecommitdiff
path: root/indra/newview/lloutfitslist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/lloutfitslist.cpp')
-rw-r--r--indra/newview/lloutfitslist.cpp228
1 files changed, 132 insertions, 96 deletions
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 5c7792b0df..352d59a9c2 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);
}
}
@@ -314,14 +312,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)
{
if (mSelectedOutfitUUID.isNull()) return false;
@@ -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<LLWearableItemsList*>(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<LLWearableItemsList*>(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<LLWearableItemsList*>(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);
@@ -820,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.
@@ -835,14 +805,23 @@ void LLOutfitListBase::onOpen(const LLSD& info)
// arrive.
category->fetch();
refreshList(outfits);
- highlightBaseOutfit();
mIsInitialized = true;
}
}
+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();
+ mRefreshListState.CategoryUUID.setNull();
+
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
@@ -855,51 +834,109 @@ 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<LLUUID, std::string> names;
+ for (const LLPointer<LLViewerInventoryCategory>& cat : cat_array)
+ {
+ names.emplace(std::make_pair(cat->getUUID(), cat->getName()));
+ }
- // Create added and removed items vectors.
- computeDifference(cat_array, vadded, vremoved);
+ // 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;
+
+ 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.
- 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<LLUUID>::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))
- {
- return;
- }
- 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();
+ highlightBaseOutfit();
+
+ gIdleCallbacks.deleteFunction(onIdle, this);
+ mRefreshListState.CategoryUUID.setNull();
+
+ LL_INFOS() << "done" << LL_ENDL;
}
void LLOutfitListBase::computeDifference(
@@ -936,7 +973,6 @@ void LLOutfitListBase::highlightBaseOutfit()
mHighlightedOutfitUUID = base_id;
onHighlightBaseOutfit(base_id, prev_id);
}
-
}
void LLOutfitListBase::removeSelected()