MAINT-4950 Appearance panel performance improvements.
parent
b941de80db
commit
b7b98918eb
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -93,4 +93,9 @@ void LLFilteredWearableListManager::populateList()
|
|||
mWearableList->refreshList(item_array);
|
||||
}
|
||||
|
||||
void LLFilteredWearableListManager::holdProgress()
|
||||
{
|
||||
mWearableList->setForceRefresh(false);
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
|||
|
|
@ -56,6 +56,11 @@ public:
|
|||
*/
|
||||
void populateList();
|
||||
|
||||
/**
|
||||
* Drop operation
|
||||
*/
|
||||
void holdProgress();
|
||||
|
||||
private:
|
||||
LLInventoryItemsList* mWearableList;
|
||||
LLInventoryCollectFunctor* mCollector;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue