Implemented normal EXT-7002 (Inventory flat list needs optimization.):

- changed the LLInventoryItemsList::addNewItem() to add item to the list without immediately rearranging
 - implemented LLFlatListViewEx::setFilterSubString(), sets up new filter string and filters the list.
 - implemented LLFlatListViewEx::filterItems(), filters the list, rearranges and notifies parent about shape changes. The list items are filtered using the notify() functionality, without need in adding/removing them on each filter call. It sends 'match_filter' request to items and interprets the returned zero as sign of matched filter string, i.e. we don't hide items that don't support 'match_filter' action(separators etc).
 - filtring of LLOutfitsList.
 Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/342/

--HG--
branch : product-engine
meow-7.2.2
Eugene Mutavchi 2010-04-30 18:27:24 +03:00
parent 779bf4bb59
commit d6edc4cd12
5 changed files with 240 additions and 49 deletions

View File

@ -297,6 +297,27 @@ void LLFlatListView::setNoItemsCommentText(const std::string& comment_text)
mNoItemsCommentTextbox->setValue(comment_text);
}
U32 LLFlatListView::size(const bool only_visible_items) const
{
if (only_visible_items)
{
U32 size = 0;
for (pairs_const_iterator_t
iter = mItemPairs.begin(),
iter_end = mItemPairs.end();
iter != iter_end; ++iter)
{
if ((*iter)->first->getVisible())
++size;
}
return size;
}
else
{
return mItemPairs.size();
}
}
void LLFlatListView::clear()
{
// do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex.
@ -426,7 +447,7 @@ void LLFlatListView::rearrangeItems()
{
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
setNoItemsCommentVisible(mItemPairs.empty());
setNoItemsCommentVisible(0==size());
if (mItemPairs.empty()) return;
@ -745,19 +766,43 @@ LLRect LLFlatListView::getLastSelectedItemRect()
void LLFlatListView::selectFirstItem ()
{
// No items - no actions!
if (mItemPairs.empty()) return;
if (0 == size()) return;
selectItemPair(mItemPairs.front(), true);
ensureSelectedVisible();
// Select first visible item
for (pairs_iterator_t
iter = mItemPairs.begin(),
iter_end = mItemPairs.end();
iter != iter_end; ++iter)
{
// skip invisible items
if ( (*iter)->first->getVisible() )
{
selectItemPair(*iter, true);
ensureSelectedVisible();
break;
}
}
}
void LLFlatListView::selectLastItem ()
{
// No items - no actions!
if (mItemPairs.empty()) return;
if (0 == size()) return;
selectItemPair(mItemPairs.back(), true);
ensureSelectedVisible();
// Select last visible item
for (pairs_list_t::reverse_iterator
r_iter = mItemPairs.rbegin(),
r_iter_end = mItemPairs.rend();
r_iter != r_iter_end; ++r_iter)
{
// skip invisible items
if ( (*r_iter)->first->getVisible() )
{
selectItemPair(*r_iter, true);
ensureSelectedVisible();
break;
}
}
}
void LLFlatListView::ensureSelectedVisible()
@ -775,14 +820,14 @@ void LLFlatListView::ensureSelectedVisible()
bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection)
{
// No items - no actions!
if ( !mItemPairs.size() )
if ( 0 == size() )
return false;
item_pair_t* to_sel_pair = NULL;
item_pair_t* cur_sel_pair = NULL;
if ( mSelectedItemPairs.size() )
{
item_pair_t* to_sel_pair = NULL;
item_pair_t* cur_sel_pair = NULL;
// Take the last selected pair
cur_sel_pair = mSelectedItemPairs.back();
// Bases on given direction choose next item to select
@ -816,42 +861,42 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti
}
}
}
if ( to_sel_pair )
{
bool select = true;
if ( reset_selection )
{
// Reset current selection if we were asked about it
resetSelection();
}
else
{
// If item already selected and no reset request than we should deselect last selected item.
select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair));
}
// Select/Deselect next item
selectItemPair(select ? to_sel_pair : cur_sel_pair, select);
return true;
}
}
else
{
// If there weren't selected items then choose the first one bases on given direction
cur_sel_pair = (is_up_direction) ? mItemPairs.back() : mItemPairs.front();
// Force selection to first item
to_sel_pair = cur_sel_pair;
}
if ( to_sel_pair )
{
bool select = true;
if ( reset_selection )
{
// Reset current selection if we were asked about it
resetSelection();
}
if (is_up_direction)
selectLastItem();
else
{
// If item already selected and no reset request than we should deselect last selected item.
select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair));
}
// Select/Deselect next item
selectItemPair(select ? to_sel_pair : cur_sel_pair, select);
selectFirstItem();
return true;
}
return false;
}
BOOL LLFlatListView::canSelectAll() const
{
return !mItemPairs.empty() && mAllowSelection && mMultipleSelection;
return 0 != size() && mAllowSelection && mMultipleSelection;
}
void LLFlatListView::selectAll()
@ -1167,4 +1212,51 @@ void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string)
}
void LLFlatListViewEx::setFilterSubString(const std::string& filter_str)
{
if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString))
{
mFilterSubString = filter_str;
updateNoItemsMessage(mFilterSubString);
filterItems();
}
}
void LLFlatListViewEx::filterItems()
{
typedef std::vector <LLPanel*> item_panel_list_t;
std::string cur_filter = mFilterSubString;
LLStringUtil::toUpper(cur_filter);
LLSD action;
action.with("match_filter", cur_filter);
item_panel_list_t items;
getItems(items);
for (item_panel_list_t::iterator
iter = items.begin(),
iter_end = items.end();
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))
{
pItem->setVisible(true);
}
else
{
// TODO: implement (re)storing of current selection.
selectItem(pItem, false);
pItem->setVisible(false);
}
}
rearrangeItems();
notifyParentItemsRectChanged();
}
//EOF

View File

@ -264,9 +264,8 @@ public:
/** Get number of selected items in the list */
U32 numSelected() const {return mSelectedItemPairs.size(); }
/** Get number of items in the list */
U32 size() const { return mItemPairs.size(); }
/** Get number of (visible) items in the list */
U32 size(const bool only_visible_items = true) const;
/** Removes all items from the list */
virtual void clear();
@ -464,6 +463,17 @@ public:
void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
/**
* Sets up new filter string and filters the list.
*/
void setFilterSubString(const std::string& filter_str);
/**
* 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();
protected:
LLFlatListViewEx(const Params& p);
@ -478,6 +488,7 @@ protected:
private:
std::string mNoFilteredItemsMsg;
std::string mNoItemsMsg;
std::string mFilterSubString;
};
#endif

View File

@ -45,6 +45,7 @@
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "lltextutil.h"
#include "lltrans.h"
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@ -63,6 +64,16 @@ LLPanelInventoryListItemBase* LLPanelInventoryListItemBase::create(LLViewerInven
return list_item;
}
void LLPanelInventoryListItemBase::draw()
{
if (getNeedsRefresh())
{
updateItem();
setNeedsRefresh(false);
}
LLPanel::draw();
}
void LLPanelInventoryListItemBase::updateItem()
{
setIconImage(mIconImage);
@ -121,7 +132,7 @@ BOOL LLPanelInventoryListItemBase::postBuild()
mIconImage = get_item_icon(mItem->getType(), mItem->getInventoryType(), mItem->getFlags(), FALSE);
updateItem();
setNeedsRefresh(true);
setWidgetsVisible(false);
reshapeWidgets();
@ -148,6 +159,34 @@ void LLPanelInventoryListItemBase::onMouseLeave(S32 x, S32 y, MASK mask)
LLPanel::onMouseLeave(x, y, mask);
}
S32 LLPanelInventoryListItemBase::notify(const LLSD& info)
{
S32 rv = 0;
if(info.has("match_filter"))
{
mHighlightedText = info["match_filter"].asString();
std::string test(mItem->getName());
LLStringUtil::toUpper(test);
if(mHighlightedText.empty() || std::string::npos != test.find(mHighlightedText))
{
rv = 0; // substring is found
}
else
{
rv = -1;
}
setNeedsRefresh(true);
}
else
{
rv = LLPanel::notify(info);
}
return rv;
}
LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem* item)
: LLPanel()
, mItem(item)
@ -156,6 +195,7 @@ LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem
, mWidgetSpacing(WIDGET_SPACING)
, mLeftWidgetsWidth(0)
, mRightWidgetsWidth(0)
, mNeedsRefresh(false)
{
}
@ -278,13 +318,15 @@ LLInventoryItemsList::Params::Params()
{}
LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p)
: LLFlatListView(p)
: LLFlatListViewEx(p)
, mNeedsRefresh(false)
{
// TODO: mCommitOnSelectionChange is set to "false" in LLFlatListView
// but reset to true in all derived classes. This settings might need to
// be added to LLFlatListView::Params() and/or set to "true" by default.
setCommitOnSelectionChange(true);
setNoFilteredItemsMsg(LLTrans::getString("InventoryNoMatchingItems"));
}
// virtual
@ -304,7 +346,7 @@ void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item
void LLInventoryItemsList::draw()
{
LLFlatListView::draw();
LLFlatListViewEx::draw();
if(mNeedsRefresh)
{
refresh();
@ -332,7 +374,8 @@ void LLInventoryItemsList::refresh()
break;
}
LLViewerInventoryItem* item = gInventory.getItem(*it);
addNewItem(item);
// Do not rearrange items on each adding, let's do that on filter call
addNewItem(item, false);
++nadded;
}
@ -342,6 +385,9 @@ void LLInventoryItemsList::refresh()
removeItemByUUID(*it);
}
// Filter, rearrange and notify parent about shape changes
filterItems();
bool needs_refresh = add_limit_exceeded;
setNeedsRefresh(needs_refresh);
}
@ -363,7 +409,7 @@ void LLInventoryItemsList::computeDifference(
LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
}
void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item)
void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange /*= true*/)
{
if (!item)
{
@ -375,7 +421,7 @@ void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item)
if (!list_item)
return;
bool is_item_added = addItem(list_item, item->getUUID());
bool is_item_added = addItem(list_item, item->getUUID(), ADD_BOTTOM, rearrange);
if (!is_item_added)
{
llwarns << "Couldn't add flat list item." << llendl;

View File

@ -64,13 +64,16 @@ class LLViewerInventoryItem;
class LLPanelInventoryListItemBase : public LLPanel
{
public:
static LLPanelInventoryListItemBase* create(LLViewerInventoryItem* item);
virtual void draw();
/**
* Called after inventory item was updated, update panel widgets to reflect inventory changes.
* Let item know it need to be refreshed in next draw()
*/
virtual void updateItem();
void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; }
bool getNeedsRefresh(){ return mNeedsRefresh; }
/**
* Add widget to left side
@ -107,6 +110,11 @@ public:
*/
/*virtual*/ void setValue(const LLSD& value);
/**
* Handles filter request
*/
/*virtual*/ S32 notify(const LLSD& info);
/* Highlights item */
/*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask);
/* Removes item highlight */
@ -125,6 +133,11 @@ protected:
*/
virtual void init();
/**
* Called after inventory item was updated, update panel widgets to reflect inventory changes.
*/
virtual void updateItem();
/** setter for mIconCtrl */
void setIconCtrl(LLIconCtrl* icon) { mIconCtrl = icon; }
/** setter for MTitleCtrl */
@ -178,14 +191,15 @@ private:
S32 mLeftWidgetsWidth;
S32 mRightWidgetsWidth;
bool mNeedsRefresh;
};
//////////////////////////////////////////////////////////////////////////
class LLInventoryItemsList : public LLFlatListView
class LLInventoryItemsList : public LLFlatListViewEx
{
public:
struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
{
Params();
};
@ -225,7 +239,7 @@ protected:
/**
* Add an item to the list
*/
virtual void addNewItem(LLViewerInventoryItem* item);
virtual void addNewItem(LLViewerInventoryItem* item, bool rearrange = true);
private:
uuid_vec_t mIDs; // IDs of items that were added in refreshList().

View File

@ -245,6 +245,34 @@ void LLOutfitsList::performAction(std::string action)
void LLOutfitsList::setFilterSubString(const std::string& string)
{
mFilterSubString = string;
for (outfits_map_t::iterator
iter = mOutfitsMap.begin(),
iter_end = mOutfitsMap.end();
iter != iter_end; ++iter)
{
LLAccordionCtrlTab* tab = iter->second;
if (tab)
{
LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*> (tab->getAccordionView());
if (list)
{
list->setFilterSubString(mFilterSubString);
}
if(!mFilterSubString.empty())
{
//store accordion tab state when filter is not empty
tab->notifyChildren(LLSD().with("action","store_state"));
tab->setDisplayChildren(true);
}
else
{
//restore accordion state after all those accodrion tab manipulations
tab->notifyChildren(LLSD().with("action","restore_state"));
}
}
}
}
//////////////////////////////////////////////////////////////////////////