Fix up EAM to work (Part 2)

Did you know you could type into a list to search it by prefix?!
The Lindens didn't!!
Let's make this search bar an ACTUAL FILTER!
To do this, we add support for filtering to all scroll lists,
so that's cool. Also filtered items will be selected.

Also optimized item selection loop to perform better when selecting in
massive lists (like group members)

Changed the text on the Copy Button to reflect that it copies everything,
not just the applied filter... if you wanted that, you could just
ctrl-a, ctrl-c... I mean, reallly
This commit is contained in:
Lirusaito
2019-07-22 08:39:06 -04:00
parent 31c5b00fed
commit 3654ff5f5c
6 changed files with 120 additions and 62 deletions

View File

@@ -54,6 +54,8 @@
#include "llsdparam.h" #include "llsdparam.h"
#include "llmenugl.h" #include "llmenugl.h"
#include <boost/algorithm/string/predicate.hpp>
static LLRegisterWidget<LLScrollListCtrl> r("scroll_list"); static LLRegisterWidget<LLScrollListCtrl> r("scroll_list");
@@ -504,6 +506,8 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r
BOOL not_too_big = getItemCount() < mMaxItemCount; BOOL not_too_big = getItemCount() < mMaxItemCount;
if (not_too_big) if (not_too_big)
{ {
if (!mFilter.empty()) filterItem(item);
switch( pos ) switch( pos )
{ {
case ADD_TOP: case ADD_TOP:
@@ -586,10 +590,11 @@ S32 LLScrollListCtrl::calcMaxContentWidth()
{ {
// update max content width for this column, by looking at all items // update max content width for this column, by looking at all items
column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel.getWString()) + mColumnPadding + HEADING_TEXT_PADDING : 0; column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel.getWString()) + mColumnPadding + HEADING_TEXT_PADDING : 0;
item_list::iterator iter; for (auto& item : mItemList)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex); if (item->getFiltered()) continue;
LLScrollListCell* cellp = item->getColumn(column->mIndex);
if (!cellp) continue; if (!cellp) continue;
column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth);
@@ -642,10 +647,8 @@ const S32 SCROLL_LIST_ROW_PAD = 2;
void LLScrollListCtrl::updateLineHeight() void LLScrollListCtrl::updateLineHeight()
{ {
mLineHeight = 0; mLineHeight = 0;
item_list::iterator iter; for (auto& itemp : mItemList)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem *itemp = *iter;
S32 num_cols = itemp->getNumColumns(); S32 num_cols = itemp->getNumColumns();
S32 i = 0; S32 i = 0;
for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i))
@@ -766,6 +769,7 @@ BOOL LLScrollListCtrl::selectFirstItem()
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem *itemp = *iter; LLScrollListItem *itemp = *iter;
if (itemp->getFiltered()) continue;
if( first_item && itemp->getEnabled() ) if( first_item && itemp->getEnabled() )
{ {
if (!itemp->getSelected()) if (!itemp->getSelected())
@@ -825,9 +829,11 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
continue ; continue ;
} }
if( index >= first_index && index <= last_index ) if (itemp->getFiltered())
{ {
if( itemp->getEnabled() ) if (index >= first_index && index <= last_index)
{
if (itemp->getEnabled())
{ {
selectItem(itemp, FALSE); selectItem(itemp, FALSE);
success = TRUE; success = TRUE;
@@ -838,6 +844,7 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index )
deselectItem(itemp); deselectItem(itemp);
} }
index++; index++;
}
iter++ ; iter++ ;
} }
@@ -973,6 +980,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids )
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem* item = *iter; LLScrollListItem* item = *iter;
if (item->getFiltered()) continue;
uuid_vec_t::iterator iditr; uuid_vec_t::iterator iditr;
for(iditr = ids.begin(); iditr != ids.end(); ++iditr) for(iditr = ids.begin(); iditr != ids.end(); ++iditr)
{ {
@@ -998,15 +1007,14 @@ S32 LLScrollListCtrl::getItemIndex( LLScrollListItem* target_item ) const
updateSort(); updateSort();
S32 index = 0; S32 index = 0;
item_list::const_iterator iter; for (LLScrollListItem* itemp : mItemList)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem *itemp = *iter; if (itemp->getFiltered()) continue;
if (target_item == itemp) if (target_item == itemp)
{ {
return index; return index;
} }
index++; ++index;
} }
return -1; return -1;
} }
@@ -1016,15 +1024,14 @@ S32 LLScrollListCtrl::getItemIndex( const LLUUID& target_id ) const
updateSort(); updateSort();
S32 index = 0; S32 index = 0;
item_list::const_iterator iter; for (LLScrollListItem* itemp : mItemList)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem *itemp = *iter; if (itemp->getFiltered()) continue;
if (target_id == itemp->getUUID()) if (target_id == itemp->getUUID())
{ {
return index; return index;
} }
index++; ++index;
} }
return -1; return -1;
} }
@@ -1046,6 +1053,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem* cur_item = *iter; LLScrollListItem* cur_item = *iter;
if (cur_item->getFiltered()) continue;
if (cur_item->getSelected()) if (cur_item->getSelected())
{ {
@@ -1090,6 +1098,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection)
for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++) for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++)
{ {
LLScrollListItem* cur_item = *iter; LLScrollListItem* cur_item = *iter;
if (cur_item->getFiltered()) continue;
if (cur_item->getSelected()) if (cur_item->getSelected())
{ {
@@ -1194,6 +1203,8 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, BOO
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem* item = *iter; LLScrollListItem* item = *iter;
if (item->getFiltered()) continue;
std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names
if (!case_sensitive) if (!case_sensitive)
{ {
@@ -1229,6 +1240,8 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem* item = *iter; LLScrollListItem* item = *iter;
if (item->getFiltered()) continue;
// Only select enabled items with matching names // Only select enabled items with matching names
LLScrollListCell* cellp = item->getColumn(getSearchColumn()); LLScrollListCell* cellp = item->getColumn(getSearchColumn());
BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE;
@@ -1252,6 +1265,9 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen
{ {
LLScrollListItem* item = *iter; LLScrollListItem* item = *iter;
// Don't select filtered items
if (item->getFiltered()) continue;
// Only select enabled items with matching names // Only select enabled items with matching names
LLScrollListCell* cellp = item->getColumn(getSearchColumn()); LLScrollListCell* cellp = item->getColumn(getSearchColumn());
if (!cellp) if (!cellp)
@@ -1336,6 +1352,8 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected)
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem* item = *iter; LLScrollListItem* item = *iter;
if (item->getFiltered()) continue;
if (item->getEnabled() && (item->getValue().asString() == value.asString())) if (item->getEnabled() && (item->getValue().asString() == value.asString()))
{ {
if (selected) if (selected)
@@ -1365,7 +1383,7 @@ BOOL LLScrollListCtrl::isSelected(const LLSD& value) const
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem* item = *iter; LLScrollListItem* item = *iter;
if (item->getValue().asString() == value.asString()) if (!item->getFiltered() && item->getValue().asString() == value.asString())
{ {
return item->getSelected(); return item->getSelected();
} }
@@ -1443,9 +1461,10 @@ void LLScrollListCtrl::drawItems()
{ {
bool should_continue = false; // False until all passes are done for all row cells. bool should_continue = false; // False until all passes are done for all row cells.
S32 cur_y = y; S32 cur_y = y;
for (S32 line = first_line; line <= last_line; line++) for (S32 index = first_line, line = first_line; index <= last_line; ++index)
{ {
LLScrollListItem* item = mItemList[line]; LLScrollListItem* item = mItemList[index];
if (item->getFiltered()) continue; // Skip filtered
item_rect.setOriginAndSize( item_rect.setOriginAndSize(
x, x,
@@ -1498,6 +1517,7 @@ void LLScrollListCtrl::drawItems()
should_continue |= item->draw(pass, item_rect, fg_color, bg_color, highlight_color, mColumnPadding); should_continue |= item->draw(pass, item_rect, fg_color, bg_color, highlight_color, mColumnPadding);
} }
++line;
} }
done = !should_continue; done = !should_continue;
} }
@@ -1647,9 +1667,10 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
// meaning that we never stop selecting until hitting max or // meaning that we never stop selecting until hitting max or
// the end of the list. // the end of the list.
LLScrollListItem* lastSelected = mLastSelected; LLScrollListItem* lastSelected = mLastSelected;
auto selected_count = getAllSelected().size();
for (itor = mItemList.begin(); itor != mItemList.end(); ++itor) for (itor = mItemList.begin(); itor != mItemList.end(); ++itor)
{ {
if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable) if(mMaxSelectable > 0 && selected_count >= mMaxSelectable)
{ {
if(mOnMaximumSelectCallback) if(mOnMaximumSelectCallback)
{ {
@@ -1658,6 +1679,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
break; break;
} }
LLScrollListItem *item = *itor; LLScrollListItem *item = *itor;
if (item->getFiltered()) continue;
if (item == hit_item || item == lastSelected) if (item == hit_item || item == lastSelected)
{ {
selectItem(item, FALSE); selectItem(item, FALSE);
@@ -1672,6 +1694,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask)
{ {
selectItem(item, FALSE); selectItem(item, FALSE);
} }
++selected_count;
} }
} }
} }
@@ -1884,10 +1907,9 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
S32 num_page_lines = getLinesPerPage(); S32 num_page_lines = getLinesPerPage();
S32 line = 0; S32 line = 0;
item_list::iterator iter; for(LLScrollListItem* item : mItemList)
for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem* item = *iter; if (item->getFiltered()) continue;
if( mScrollLines <= line && line < mScrollLines + num_page_lines ) if( mScrollLines <= line && line < mScrollLines + num_page_lines )
{ {
if( item->getEnabled() && item_rect.pointInRect( x, y ) ) if( item->getEnabled() && item_rect.pointInRect( x, y ) )
@@ -1898,7 +1920,7 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y )
item_rect.translate(0, -mLineHeight); item_rect.translate(0, -mLineHeight);
} }
line++; ++line;
} }
return hit_item; return hit_item;
@@ -1956,6 +1978,39 @@ S32 LLScrollListCtrl::getRowOffsetFromIndex(S32 index)
return row_bottom; return row_bottom;
} }
void LLScrollListCtrl::filterItem(LLScrollListItem* item)
{
for (const auto& column : item->mColumns)
{
// Only filter text, search tooltip because it'll usually be the text anyway.
if (column->isText() && boost::icontains(column->getToolTip(), mFilter))
{
item->setFiltered(false);
return;
}
}
item->setFiltered(true);
}
void LLScrollListCtrl::setFilter(const std::string& filter)
{
if (filter == mFilter) return;
bool no_filter = filter.empty();
// If our filter string has been expanded, we can skip already filtered items
bool expanded = !no_filter && !mFilter.empty() && boost::icontains(filter, mFilter);
mFilter = filter;
for (auto& item : mItemList)
{
if (no_filter) item->setFiltered(false);
else if (!expanded || !item->getFiltered())
{
filterItem(item);
}
}
}
BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask)
{ {
@@ -2185,7 +2240,8 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
while(iter != start_iter) while(iter != start_iter)
{ {
LLScrollListItem* item = *iter; LLScrollListItem* item = *iter;
if (!item->getFiltered())
{
LLScrollListCell* cellp = item->getColumn(getSearchColumn()); LLScrollListCell* cellp = item->getColumn(getSearchColumn());
if (cellp) if (cellp)
{ {
@@ -2207,6 +2263,7 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char)
break; break;
} }
} }
}
++iter; ++iter;
if (iter == mItemList.end()) if (iter == mItemList.end())
@@ -2816,7 +2873,7 @@ void LLScrollListCtrl::selectAll()
for (iter = mItemList.begin(); iter != mItemList.end(); iter++) for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
{ {
LLScrollListItem *itemp = *iter; LLScrollListItem *itemp = *iter;
if( itemp->getEnabled() ) if (itemp->getEnabled() && !itemp->getFiltered())
{ {
selectItem(itemp, FALSE); selectItem(itemp, FALSE);
} }

View File

@@ -249,6 +249,9 @@ public:
void clearSearchString() { mSearchString.clear(); } void clearSearchString() { mSearchString.clear(); }
void filterItem(LLScrollListItem* item);
void setFilter(const std::string& filter);
// support right-click context menus for avatar/group lists // support right-click context menus for avatar/group lists
void setContextMenu(LLMenuGL* menu) { mPopupMenu = menu; } void setContextMenu(LLMenuGL* menu) { mPopupMenu = menu; }
void setContextMenu(S32 index) { mPopupMenu = sMenus[index]; } void setContextMenu(S32 index) { mPopupMenu = sMenus[index]; }
@@ -469,6 +472,8 @@ private:
LLWString mSearchString; LLWString mSearchString;
LLFrameTimer mSearchTimer; LLFrameTimer mSearchTimer;
std::string mFilter;
S32 mSearchColumn; S32 mSearchColumn;
S32 mNumDynamicWidthColumns; S32 mNumDynamicWidthColumns;
S32 mTotalStaticColumnWidth; S32 mTotalStaticColumnWidth;

View File

@@ -38,6 +38,7 @@
LLScrollListItem::LLScrollListItem( const Params& p ) LLScrollListItem::LLScrollListItem( const Params& p )
: mSelected(FALSE), : mSelected(FALSE),
mEnabled(p.enabled), mEnabled(p.enabled),
mFiltered(false),
mUserdata(p.userdata), mUserdata(p.userdata),
mItemValue(p.value), mItemValue(p.value),
mColumns() mColumns()

View File

@@ -71,6 +71,9 @@ public:
void setEnabled( BOOL b ) { mEnabled = b; } void setEnabled( BOOL b ) { mEnabled = b; }
BOOL getEnabled() const { return mEnabled; } BOOL getEnabled() const { return mEnabled; }
void setFiltered(bool b) { if (mFiltered = b) mSelected = false; }
bool getFiltered() const { return mFiltered; }
void setUserdata( void* userdata ) { mUserdata = userdata; } void setUserdata( void* userdata ) { mUserdata = userdata; }
void* getUserdata() const { return mUserdata; } void* getUserdata() const { return mUserdata; }
@@ -100,6 +103,7 @@ protected:
private: private:
BOOL mSelected; BOOL mSelected;
BOOL mEnabled; BOOL mEnabled;
bool mFiltered;
void* mUserdata; void* mUserdata;
LLSD mItemValue; LLSD mItemValue;
std::vector<LLScrollListCell *> mColumns; std::vector<LLScrollListCell *> mColumns;

View File

@@ -4250,16 +4250,7 @@ void LLPanelEstateAccess::onBannedSearchEdit(const std::string& search_string)
void LLPanelEstateAccess::searchAgent(LLNameListCtrl* listCtrl, const std::string& search_string) void LLPanelEstateAccess::searchAgent(LLNameListCtrl* listCtrl, const std::string& search_string)
{ {
if (!listCtrl) return; if (!listCtrl) return;
listCtrl->setFilter(search_string);
if (!search_string.empty())
{
listCtrl->setSearchColumn(0); // name column
listCtrl->selectItemByPrefix(search_string, FALSE);
}
else
{
listCtrl->deselectAllItems(TRUE);
}
} }
void LLPanelEstateAccess::copyListToClipboard(std::string list_name) void LLPanelEstateAccess::copyListToClipboard(std::string list_name)

View File

@@ -216,7 +216,7 @@
follows="left|top" follows="left|top"
bottom_delta="0" bottom_delta="0"
height="23" height="23"
label="Copy" label="Copy All"
layout="topleft" layout="topleft"
left_delta="123" left_delta="123"
name="copy_allowed_list_btn" name="copy_allowed_list_btn"
@@ -328,7 +328,7 @@
follows="left|top" follows="left|top"
bottom_delta="0" bottom_delta="0"
height="23" height="23"
label="Copy" label="Copy All"
layout="topleft" layout="topleft"
left_delta="123" left_delta="123"
name="copy_allowed_group_list_btn" name="copy_allowed_group_list_btn"
@@ -454,7 +454,7 @@
follows="left|top" follows="left|top"
bottom_delta="0" bottom_delta="0"
height="23" height="23"
label="Copy" label="Copy All"
layout="topleft" layout="topleft"
left_delta="123" left_delta="123"
name="copy_banned_list_btn" name="copy_banned_list_btn"