MAINT-4950 Appearance panel performance improvements.

master
andreykproductengine 2016-09-26 21:29:20 +03:00
parent b941de80db
commit b7b98918eb
9 changed files with 281 additions and 103 deletions

View File

@ -105,6 +105,81 @@ bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*
return true;
}
bool LLFlatListView::addItemPairs(pairs_list_t panel_list, bool rearrange /*= true*/)
{
if (!mItemComparator)
{
LL_WARNS_ONCE() << "No comparator specified for inserting FlatListView items." << LL_ENDL;
return false;
}
if (panel_list.size() == 0)
{
return false;
}
// presort list so that it will be easier to sort elements into mItemPairs
panel_list.sort(ComparatorAdaptor(*mItemComparator));
pairs_const_iterator_t new_pair_it = panel_list.begin();
item_pair_t* new_pair = *new_pair_it;
pairs_iterator_t pair_it = mItemPairs.begin();
item_pair_t* item_pair = *pair_it;
// sort panel_list into mItemPars
while (new_pair_it != panel_list.end() && pair_it != mItemPairs.end())
{
if (!new_pair->first || new_pair->first->getParent() == mItemsPanel)
{
// iterator already used or we are reusing existing panel
new_pair_it++;
new_pair = *new_pair_it;
}
else if (mItemComparator->compare(new_pair->first, item_pair->first))
{
LLPanel* panel = new_pair->first;
mItemPairs.insert(pair_it, new_pair);
mItemsPanel->addChild(panel);
//_4 is for MASK
panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4));
panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4));
// Children don't accept the focus
panel->setTabStop(false);
}
else
{
pair_it++;
item_pair = *pair_it;
}
}
// Add what is left of panel_list into the end of mItemPairs.
for (; new_pair_it != panel_list.end(); ++new_pair_it)
{
item_pair_t* item_pair = *new_pair_it;
LLPanel *panel = item_pair->first;
if (panel && panel->getParent() != mItemsPanel)
{
mItemPairs.push_back(item_pair);
mItemsPanel->addChild(panel);
//_4 is for MASK
panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4));
panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4));
// Children don't accept the focus
panel->setTabStop(false);
}
}
if (rearrange)
{
rearrangeItems();
notifyParentItemsRectChanged();
}
return true;
}
bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value /*= LLUUID::null*/)
{
@ -1289,6 +1364,28 @@ void LLFlatListViewEx::setFilterSubString(const std::string& filter_str)
}
}
void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
{
if (!item) return;
// 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
{
// TODO: implement (re)storing of current selection.
if (!mForceShowingUnmatchedItems)
{
selectItem(item, false);
}
item->setVisible(mForceShowingUnmatchedItems);
}
}
void LLFlatListViewEx::filterItems()
{
typedef std::vector <LLPanel*> item_panel_list_t;
@ -1309,22 +1406,7 @@ void LLFlatListViewEx::filterItems()
iter != iter_end; ++iter)
{
LLPanel* pItem = (*iter);
// 0 signifies that filter is matched,
// i.e. we don't hide items that don't support 'match_filter' action, separators etc.
if (0 == pItem->notify(action))
{
mHasMatchedItems = true;
pItem->setVisible(true);
}
else
{
// TODO: implement (re)storing of current selection.
if(!mForceShowingUnmatchedItems)
{
selectItem(pItem, false);
}
pItem->setVisible(mForceShowingUnmatchedItems);
}
updateItemVisibility(pItem, action);
}
sort();

View File

@ -351,6 +351,8 @@ protected:
virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange);
bool addItemPairs(pairs_list_t panel_list, bool rearrange = true);
/**
* Notify parent about changed size of internal controls with "size_changes" action
*
@ -480,6 +482,7 @@ public:
* Sets up new filter string and filters the list.
*/
void setFilterSubString(const std::string& filter_str);
std::string getFilterSubString() { return mFilterSubString; }
/**
* Filters the list, rearranges and notifies parent about shape changes.
@ -503,6 +506,14 @@ protected:
*/
void updateNoItemsMessage(const std::string& filter_string);
/**
* Applies visibility acording to action and LLFlatListView settings.
*
* @param item - item we are changing
* @param item - action - parameters to determin visibility from
*/
void updateItemVisibility(LLPanel* item, const LLSD &action);
private:
std::string mNoFilteredItemsMsg;
std::string mNoItemsMsg;

View File

@ -93,4 +93,9 @@ void LLFilteredWearableListManager::populateList()
mWearableList->refreshList(item_array);
}
void LLFilteredWearableListManager::holdProgress()
{
mWearableList->setForceRefresh(false);
}
// EOF

View File

@ -56,6 +56,11 @@ public:
*/
void populateList();
/**
* Drop operation
*/
void holdProgress();
private:
LLInventoryItemsList* mWearableList;
LLInventoryCollectFunctor* mCollector;

View File

@ -45,7 +45,7 @@ LLInventoryItemsList::Params::Params()
LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p)
: LLFlatListViewEx(p)
, mNeedsRefresh(false)
, mRefreshState(REFRESH_COMPLETE)
, mForceRefresh(false)
{
// TODO: mCommitOnSelectionChange is set to "false" in LLFlatListView
@ -66,13 +66,13 @@ LLInventoryItemsList::~LLInventoryItemsList()
void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array)
{
getIDs().clear();
getIDs().clear();
LLInventoryModel::item_array_t::const_iterator it = item_array.begin();
for( ; item_array.end() != it; ++it)
{
getIDs().push_back((*it)->getUUID());
}
mNeedsRefresh = true;
mRefreshState = REFRESH_ALL;
}
boost::signals2::connection LLInventoryItemsList::setRefreshCompleteCallback(const commit_signal_t::slot_type& cb)
@ -113,9 +113,9 @@ void LLInventoryItemsList::updateSelection()
void LLInventoryItemsList::doIdle()
{
if (!mNeedsRefresh) return;
if (mRefreshState == REFRESH_COMPLETE) return;
if (isInVisibleChain() || mForceRefresh)
if (isInVisibleChain() || mForceRefresh )
{
refresh();
@ -137,54 +137,130 @@ LLTrace::BlockTimerStatHandle FTM_INVENTORY_ITEMS_REFRESH("Inventory List Refres
void LLInventoryItemsList::refresh()
{
LL_RECORD_BLOCK_TIME(FTM_INVENTORY_ITEMS_REFRESH);
static const unsigned ADD_LIMIT = 20;
LL_RECORD_BLOCK_TIME(FTM_INVENTORY_ITEMS_REFRESH);
uuid_vec_t added_items;
uuid_vec_t removed_items;
switch (mRefreshState)
{
case REFRESH_ALL:
{
mAddedItems.clear();
mRemovedItems.clear();
computeDifference(getIDs(), mAddedItems, mRemovedItems);
if (mRemovedItems.size() > 0)
{
mRefreshState = REFRESH_LIST_ERASE;
}
else if (mAddedItems.size() > 0)
{
mRefreshState = REFRESH_LIST_APPEND;
}
else
{
mRefreshState = REFRESH_LIST_SORT;
}
computeDifference(getIDs(), added_items, removed_items);
rearrangeItems();
notifyParentItemsRectChanged();
break;
}
case REFRESH_LIST_ERASE:
{
uuid_vec_t::const_iterator it = mRemovedItems.begin();
for (; mRemovedItems.end() != it; ++it)
{
// don't filter items right away
removeItemByUUID(*it, false);
}
mRemovedItems.clear();
mRefreshState = REFRESH_LIST_SORT; // fix visibility and arrange
break;
}
case REFRESH_LIST_APPEND:
{
static const unsigned ADD_LIMIT = 25; // Note: affects perfomance
bool add_limit_exceeded = false;
unsigned int nadded = 0;
unsigned int nadded = 0;
uuid_vec_t::const_iterator it = added_items.begin();
for( ; added_items.end() != it; ++it)
{
if(nadded >= ADD_LIMIT)
{
add_limit_exceeded = true;
break;
}
LLViewerInventoryItem* item = gInventory.getItem(*it);
// Do not rearrange items on each adding, let's do that on filter call
llassert(item);
if (item)
{
addNewItem(item, false);
++nadded;
}
}
// form a list to add
uuid_vec_t::iterator it = mAddedItems.begin();
pairs_list_t panel_list;
while(mAddedItems.size() > 0 && nadded < ADD_LIMIT)
{
LLViewerInventoryItem* item = gInventory.getItem(*it);
llassert(item);
if (item)
{
LLPanel *list_item = createNewItem(item);
if (list_item)
{
item_pair_t* new_pair = new item_pair_t(list_item, item->getUUID());
panel_list.push_back(new_pair);
++nadded;
}
}
it = removed_items.begin();
for( ; removed_items.end() != it; ++it)
{
// don't filter items right away
removeItemByUUID(*it, false);
}
it = mAddedItems.erase(it);
}
// Filter, rearrange and notify parent about shape changes
filterItems();
// add the list
// Note: usually item pairs are sorted with std::sort, but we are calling
// this function on idle and pairs' list can take a lot of time to sort
// through, so we are sorting items into list while adding them
addItemPairs(panel_list, false);
bool needs_refresh = add_limit_exceeded;
setNeedsRefresh(needs_refresh);
setForceRefresh(needs_refresh);
// update visibility of items in the list
std::string cur_filter = getFilterSubString();
LLStringUtil::toUpper(cur_filter);
LLSD action;
action.with("match_filter", cur_filter);
// After list building completed, select items that had been requested to select before list was build
if(!needs_refresh)
{
updateSelection();
}
pairs_const_iterator_t pair_it = panel_list.begin();
for (; pair_it != panel_list.end(); ++pair_it)
{
item_pair_t* item_pair = *pair_it;
if (item_pair->first->getParent() != NULL)
{
updateItemVisibility(item_pair->first, action);
}
}
rearrangeItems();
notifyParentItemsRectChanged();
if (mAddedItems.size() > 0)
{
mRefreshState = REFRESH_LIST_APPEND;
}
else
{
// Note: while we do sort and check visibility at REFRESH_LIST_APPEND, update
// could have changed something about existing items so redo checks for all items.
mRefreshState = REFRESH_LIST_SORT;
}
break;
}
case REFRESH_LIST_SORT:
{
// Filter, sort, rearrange and notify parent about shape changes
filterItems();
if (mAddedItems.size() == 0)
{
// After list building completed, select items that had been requested to select before list was build
updateSelection();
mRefreshState = REFRESH_COMPLETE;
}
else
{
mRefreshState = REFRESH_LIST_APPEND;
}
break;
}
default:
break;
}
setForceRefresh(mRefreshState != REFRESH_COMPLETE);
}
void LLInventoryItemsList::computeDifference(
@ -204,24 +280,15 @@ void LLInventoryItemsList::computeDifference(
LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
}
void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange /*= true*/)
LLPanel* LLInventoryItemsList::createNewItem(LLViewerInventoryItem* item)
{
if (!item)
{
LL_WARNS() << "No inventory item. Couldn't create flat list item." << LL_ENDL;
llassert(item != NULL);
}
LLPanelInventoryListItemBase *list_item = LLPanelInventoryListItemBase::create(item);
if (!list_item)
return;
bool is_item_added = addItem(list_item, item->getUUID(), ADD_BOTTOM, rearrange);
if (!is_item_added)
{
LL_WARNS() << "Couldn't add flat list item." << LL_ENDL;
llassert(is_item_added);
}
if (!item)
{
LL_WARNS() << "No inventory item. Couldn't create flat list item." << LL_ENDL;
llassert(item != NULL);
return NULL;
}
return LLPanelInventoryListItemBase::create(item);
}
// EOF

View File

@ -51,9 +51,9 @@ public:
/**
* Let list know items need to be refreshed in next doIdle()
*/
void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; }
void setNeedsRefresh(bool needs_refresh){ mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; }
bool getNeedsRefresh(){ return mNeedsRefresh; }
U32 getNeedsRefresh(){ return mRefreshState; }
/**
* Sets the flag indicating that the list needs to be refreshed even if it is
@ -71,7 +71,7 @@ public:
* This is needed for example to filter items of the list hidden by closed
* accordion tab.
*/
void doIdle(); // Real idle routine
virtual void doIdle(); // Real idle routine
static void idle(void* user_data); // static glue to doIdle()
protected:
@ -94,17 +94,29 @@ protected:
void computeDifference(const uuid_vec_t& vnew, uuid_vec_t& vadded, uuid_vec_t& vremoved);
/**
* Add an item to the list
*/
virtual void addNewItem(LLViewerInventoryItem* item, bool rearrange = true);
* Create panel(item) from inventory item
*/
virtual LLPanel* createNewItem(LLViewerInventoryItem* item);
protected:
enum ERefreshStates
{
REFRESH_COMPLETE = 0,
REFRESH_LIST_SORT,
REFRESH_LIST_APPEND,
REFRESH_LIST_ERASE,
REFRESH_ALL
};
ERefreshStates mRefreshState;
private:
uuid_vec_t mIDs; // IDs of items that were added in refreshList().
// Will be used in refresh() to determine added and removed ids
uuid_vec_t mSelectTheseIDs; // IDs that will be selected if list is not loaded till now
bool mNeedsRefresh;
uuid_vec_t mAddedItems;
uuid_vec_t mRemovedItems;
bool mForceRefresh;

View File

@ -779,6 +779,10 @@ void LLPanelOutfitEdit::onVisibilityChanged(const LLSD &in_visible_chain)
{
update();
}
else
{
mWearableListManager->holdProgress(); //list population restarts with visibility
}
}
void LLPanelOutfitEdit::onAddWearableClicked(void)

View File

@ -653,24 +653,16 @@ LLWearableItemsList::~LLWearableItemsList()
{}
// virtual
void LLWearableItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange /*= true*/)
LLPanel* LLWearableItemsList::createNewItem(LLViewerInventoryItem* item)
{
if (!item)
{
LL_WARNS() << "No inventory item. Couldn't create flat list item." << LL_ENDL;
llassert(item != NULL);
}
if (!item)
{
LL_WARNS() << "No inventory item. Couldn't create flat list item." << LL_ENDL;
llassert(item != NULL);
return NULL;
}
LLPanelWearableOutfitItem *list_item = LLPanelWearableOutfitItem::create(item, mWornIndicationEnabled);
if (!list_item)
return;
bool is_item_added = addItem(list_item, item->getUUID(), ADD_BOTTOM, rearrange);
if (!is_item_added)
{
LL_WARNS() << "Couldn't add flat list item." << LL_ENDL;
llassert(is_item_added);
}
return LLPanelWearableOutfitItem::create(item, mWornIndicationEnabled);
}
void LLWearableItemsList::updateList(const LLUUID& category_id)

View File

@ -453,7 +453,7 @@ public:
virtual ~LLWearableItemsList();
/*virtual*/ void addNewItem(LLViewerInventoryItem* item, bool rearrange = true);
/*virtual*/ LLPanel* createNewItem(LLViewerInventoryItem* item);
void updateList(const LLUUID& category_id);