EXT-7158 FIXED Implemented filter in "My Outfits" tab.

- Added accordion tab title highlighting setter and title getter.
- Added filtered tabs title highlighting.
- Tabs which don't pass filter are hidden.
- Added applying filter on list refresh event to avoid refreshing list on every filter change.
- Moved part of LLTextUtil to llui/lluitextutil to reuse code in llaccordionctrltab.
- Fixed passing list size to mRefreshCompleteSignal.
- Added list refresh callback to LLInventoryItemsList for checking tab visibility  without re-applying filter sub-string.

Committed to proceed with dependent tasks.
If there are any comments/suggestions related to text utils this part of code may be changed without requiring much effort.

Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/363/

--HG--
branch : product-engine
meow-7.2.2
Sergei Litovchuk 2010-05-13 19:31:50 +03:00
parent 90940d0b06
commit a968046282
11 changed files with 214 additions and 57 deletions

View File

@ -101,6 +101,7 @@ set(llui_SOURCE_FILES
lluictrlfactory.cpp
lluiimage.cpp
lluistring.cpp
lluitextutil.cpp
llundo.cpp
llurlaction.cpp
llurlentry.cpp
@ -197,6 +198,7 @@ set(llui_HEADER_FILES
llui.h
lluiimage.h
lluistring.h
lluitextutil.h
llundo.h
llurlaction.h
llurlentry.h

View File

@ -32,12 +32,13 @@
#include "linden_common.h"
#include "lluictrl.h"
#include "llscrollbar.h"
#include "llaccordionctrltab.h"
#include "lllocalcliprect.h"
#include "lllocalcliprect.h"
#include "llscrollbar.h"
#include "lltextbox.h"
#include "lluictrl.h"
#include "lluitextutil.h"
static const std::string DD_BUTTON_NAME = "dd_button";
static const std::string DD_TEXTBOX_NAME = "dd_textbox";
@ -72,7 +73,8 @@ public:
virtual BOOL postBuild();
void setTitle(const std::string& title);
std::string getTitle();
void setTitle(const std::string& title, const std::string& hl);
virtual void onMouseEnter(S32 x, S32 y, MASK mask);
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
@ -146,10 +148,28 @@ BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild()
return TRUE;
}
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title)
std::string LLAccordionCtrlTab::LLAccordionCtrlTabHeader::getTitle()
{
if(mHeaderTextbox)
mHeaderTextbox->setText(title);
{
return mHeaderTextbox->getText();
}
else
{
return LLStringUtil::null;
}
}
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title, const std::string& hl)
{
if(mHeaderTextbox)
{
LLTextUtil::textboxSetHighlightedVal(
mHeaderTextbox,
LLStyle::Params(),
title,
hl);
}
}
void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
@ -436,12 +456,25 @@ void LLAccordionCtrlTab::setAccordionView(LLView* panel)
addChild(panel,0);
}
void LLAccordionCtrlTab::setTitle(const std::string& title)
std::string LLAccordionCtrlTab::getTitle()
{
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
if (header)
{
header->setTitle(title);
return header->getTitle();
}
else
{
return LLStringUtil::null;
}
}
void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl)
{
LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
if (header)
{
header->setTitle(title, hl);
}
}
@ -903,5 +936,3 @@ BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
}
return LLUICtrl::handleToolTip(x, y, mask);
}

View File

@ -113,8 +113,10 @@ public:
void setAccordionView(LLView* panel);
LLView* getAccordionView() { return mContainerPanel; };
// Set text in LLAccordionCtrlTabHeader
void setTitle(const std::string& title);
std::string getTitle();
// Set text and highlight substring in LLAccordionCtrlTabHeader
void setTitle(const std::string& title, const std::string& hl = LLStringUtil::null);
boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb);
boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb);

View File

@ -316,9 +316,7 @@ void LLAvatarList::refresh()
}
// Send refresh_complete signal.
std::vector<LLSD> cur_values;
getValues(cur_values);
mRefreshCompleteSignal(this, LLSD((S32)cur_values.size()));
mRefreshCompleteSignal(this, LLSD((S32)size(false)));
}
// Commit if we've added/removed items.

View File

@ -36,12 +36,13 @@
#include "llavataractions.h"
#include "llavatarlistitem.h"
#include "llfloaterreg.h"
#include "llagent.h"
#include "lloutputmonitorctrl.h"
#include "llavatariconctrl.h"
#include "lltextutil.h"
#include "llbutton.h"
#include "llfloaterreg.h"
#include "lluitextutil.h"
#include "llagent.h"
#include "llavatariconctrl.h"
#include "lloutputmonitorctrl.h"
bool LLAvatarListItem::sStaticInitialized = false;
S32 LLAvatarListItem::sLeftPadding = 0;

View File

@ -40,12 +40,12 @@
#include "llmenugl.h"
#include "lltextbox.h"
#include "lltrans.h"
#include "lluitextutil.h"
// newview
#include "llagent.h"
#include "llgroupactions.h"
#include "llfloaterreg.h"
#include "lltextutil.h"
#include "llviewercontrol.h" // for gSavedSettings
#include "llviewermenu.h" // for gMenuHolder
#include "llvoiceclient.h"

View File

@ -40,11 +40,13 @@
// llcommon
#include "llcommonutils.h"
// llui
#include "lliconctrl.h"
#include "lluitextutil.h"
#include "llcallbacklist.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "lltextutil.h"
#include "lltrans.h"
////////////////////////////////////////////////////////////////////////////////
@ -320,6 +322,7 @@ LLInventoryItemsList::Params::Params()
LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p)
: LLFlatListViewEx(p)
, mNeedsRefresh(false)
, mPrevVisibility(false)
{
// TODO: mCommitOnSelectionChange is set to "false" in LLFlatListView
// but reset to true in all derived classes. This settings might need to
@ -327,6 +330,8 @@ LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p
setCommitOnSelectionChange(true);
setNoFilteredItemsMsg(LLTrans::getString("InventoryNoMatchingItems"));
gIdleCallbacks.addFunction(idle, this);
}
// virtual
@ -344,12 +349,31 @@ void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item
mNeedsRefresh = true;
}
void LLInventoryItemsList::draw()
boost::signals2::connection LLInventoryItemsList::setRefreshCompleteCallback(const commit_signal_t::slot_type& cb)
{
LLFlatListViewEx::draw();
if(mNeedsRefresh)
return mRefreshCompleteSignal.connect(cb);
}
void LLInventoryItemsList::doIdle()
{
bool cur_visibility = getVisible();
if(cur_visibility != mPrevVisibility || mNeedsRefresh)
{
refresh();
mRefreshCompleteSignal(this, LLSD());
mPrevVisibility = getVisible();
}
}
//static
void LLInventoryItemsList::idle(void* user_data)
{
LLInventoryItemsList* self = static_cast<LLInventoryItemsList*>(user_data);
if ( self )
{ // Do the real idle
self->doIdle();
}
}

View File

@ -212,14 +212,23 @@ public:
void refreshList(const LLDynamicArray<LLPointer<LLViewerInventoryItem> > item_array);
boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb);
/**
* Let list know items need to be refreshed in next draw()
* Let list know items need to be refreshed in next doIdle()
*/
void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; }
bool getNeedsRefresh(){ return mNeedsRefresh; }
/*virtual*/ void draw();
/**
* Idle routine used to refresh the list regardless of the current list
* visibility, unlike draw() which is called only for the visible list.
* This is needed for example to filter items of the list hidden by closed
* accordion tab.
*/
void doIdle(); // Real idle routine
static void idle(void* user_data); // static glue to doIdle()
protected:
friend class LLUICtrlFactory;
@ -229,7 +238,7 @@ protected:
/**
* Refreshes list items, adds new items and removes deleted items.
* Called from draw() until all new items are added, ,
* Called from doIdle() until all new items are added,
* maximum 50 items can be added during single call.
*/
void refresh();
@ -249,6 +258,10 @@ private:
uuid_vec_t mIDs; // IDs of items that were added in refreshList().
// Will be used in refresh() to determine added and removed ids
bool mNeedsRefresh;
bool mPrevVisibility;
commit_signal_t mRefreshCompleteSignal;
};
#endif //LL_LLINVENTORYITEMSLIST_H

View File

@ -169,6 +169,9 @@ void LLOutfitsList::refreshList(const LLUUID& category_id)
// Setting list commit callback to monitor currently selected wearable item.
list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1));
// Setting list refresh callback to apply filter on list change.
list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onWearableItemsListRefresh, this, _1));
// Fetch the new outfit contents.
cat->fetch();
@ -244,35 +247,9 @@ void LLOutfitsList::performAction(std::string action)
void LLOutfitsList::setFilterSubString(const std::string& string)
{
applyFilter(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"));
}
}
}
}
//////////////////////////////////////////////////////////////////////////
@ -350,4 +327,102 @@ void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUI
mSelectedOutfitUUID = category_id;
}
void LLOutfitsList::onWearableItemsListRefresh(LLUICtrl* ctrl)
{
if (!ctrl || mFilterSubString.empty())
return;
for (outfits_map_t::iterator
iter = mOutfitsMap.begin(),
iter_end = mOutfitsMap.end();
iter != iter_end; ++iter)
{
LLAccordionCtrlTab* tab = iter->second;
if (tab) continue;
LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(tab->getAccordionView());
if (list != ctrl) continue;
std::string title = tab->getTitle();
LLStringUtil::toUpper(title);
std::string cur_filter = mFilterSubString;
LLStringUtil::toUpper(cur_filter);
if (std::string::npos == title.find(cur_filter))
{
// hide tab if its title doesn't pass filter
// and it has no visible items
tab->setVisible(list->size() != 0);
}
else
{
tab->setTitle(tab->getTitle(), cur_filter);
}
}
}
void LLOutfitsList::applyFilter(const std::string& new_filter_substring)
{
for (outfits_map_t::iterator
iter = mOutfitsMap.begin(),
iter_end = mOutfitsMap.end();
iter != iter_end; ++iter)
{
LLAccordionCtrlTab* tab = iter->second;
if (!tab) continue;
bool more_restrictive = mFilterSubString.size() < new_filter_substring.size() && !new_filter_substring.substr(0, mFilterSubString.size()).compare(mFilterSubString);
// 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);
}
if(mFilterSubString.empty() && !new_filter_substring.empty())
{
//store accordion tab state when filter is not empty
tab->notifyChildren(LLSD().with("action","store_state"));
}
if (!new_filter_substring.empty())
{
tab->setDisplayChildren(true);
std::string title = tab->getTitle();
LLStringUtil::toUpper(title);
std::string cur_filter = new_filter_substring;
LLStringUtil::toUpper(cur_filter);
if (std::string::npos == title.find(cur_filter))
{
// hide tab if its title doesn't pass filter
// and it has no visible items
tab->setVisible(list->size() != 0);
}
else
{
tab->setTitle(tab->getTitle(), cur_filter);
}
}
else
{
// 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"));
}
}
}
// EOF

View File

@ -94,6 +94,17 @@ private:
*/
void changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
/**
* Called upon list refresh event to update tab visibility depending on
* the results of applying filter to the title and list items of the tab.
*/
void onWearableItemsListRefresh(LLUICtrl* ctrl);
/**
* Highlights filtered items and hides tabs which haven't passed filter.
*/
void applyFilter(const std::string& new_filter_substring);
LLInventoryCategoriesObserver* mCategoriesObserver;
LLAccordionCtrl* mAccordion;

View File

@ -38,7 +38,7 @@
#include "llsidetray.h"
#include "llworldmap.h"
#include "llteleporthistorystorage.h"
#include "lltextutil.h"
#include "lluitextutil.h"
#include "llaccordionctrl.h"
#include "llaccordionctrltab.h"