summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Litovchuk <slitovchuk@productengine.com>2010-05-13 19:31:50 +0300
committerSergei Litovchuk <slitovchuk@productengine.com>2010-05-13 19:31:50 +0300
commita9680462828d99cb482cdb235f14d6bd3c87bc9c (patch)
tree67d6a4f5cb9ed3b7ac38b6e2f1e4137901f8d51e
parent90940d0b065d18b1dfaa178ee294b4d47ff96e2a (diff)
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
-rw-r--r--indra/llui/CMakeLists.txt2
-rw-r--r--indra/llui/llaccordionctrltab.cpp51
-rw-r--r--indra/llui/llaccordionctrltab.h6
-rw-r--r--indra/newview/llavatarlist.cpp4
-rw-r--r--indra/newview/llavatarlistitem.cpp7
-rw-r--r--indra/newview/llgrouplist.cpp2
-rw-r--r--indra/newview/llinventoryitemslist.cpp32
-rw-r--r--indra/newview/llinventoryitemslist.h19
-rw-r--r--indra/newview/lloutfitslist.cpp131
-rw-r--r--indra/newview/lloutfitslist.h11
-rw-r--r--indra/newview/llpanelteleporthistory.cpp2
11 files changed, 212 insertions, 55 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 3ecab90756..88a1652671 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -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
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 596da782ce..0db2dca615 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -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)
+ {
+ 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);
+ header->setTitle(title, hl);
}
}
@@ -903,5 +936,3 @@ BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask)
}
return LLUICtrl::handleToolTip(x, y, mask);
}
-
-
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index de254ed3eb..f5b7fd0af6 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -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);
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index dfb213716c..47ec5270c3 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -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.
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 2a51eeacfc..656274cb7a 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -36,12 +36,13 @@
#include "llavataractions.h"
#include "llavatarlistitem.h"
+#include "llbutton.h"
#include "llfloaterreg.h"
+#include "lluitextutil.h"
+
#include "llagent.h"
-#include "lloutputmonitorctrl.h"
#include "llavatariconctrl.h"
-#include "lltextutil.h"
-#include "llbutton.h"
+#include "lloutputmonitorctrl.h"
bool LLAvatarListItem::sStaticInitialized = false;
S32 LLAvatarListItem::sLeftPadding = 0;
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 5efd99b939..3224ac6d9b 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -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"
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp
index f48e7b3966..2d1d401cd4 100644
--- a/indra/newview/llinventoryitemslist.cpp
+++ b/indra/newview/llinventoryitemslist.cpp
@@ -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();
}
}
diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h
index 6e74330df2..60cccc0f4f 100644
--- a/indra/newview/llinventoryitemslist.h
+++ b/indra/newview/llinventoryitemslist.h
@@ -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
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 18bd610dd9..12d5203429 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -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)
{
- mFilterSubString = string;
+ applyFilter(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"));
- }
- }
- }
+ mFilterSubString = string;
}
//////////////////////////////////////////////////////////////////////////
@@ -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
diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h
index d86cf5a703..bcb393b12a 100644
--- a/indra/newview/lloutfitslist.h
+++ b/indra/newview/lloutfitslist.h
@@ -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;
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index e8b6c6bfe5..4dd03e04a9 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -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"