From 4395d8e9f1302e8efcda4b35da3b0e3ea6c36928 Mon Sep 17 00:00:00 2001
From: Mike Antipov <mantipov@productengine.com>
Date: Wed, 21 Apr 2010 10:17:09 +0300
Subject: [PATCH] WIP: critical bug EXT-4837 ([NUX] When filter results in null
 state, provide a message suggesting the user try global search.)

Partial implementation of help text in case of empty list when filtered for Nearby and Recent lists of People panel:
 * Extracted support implementation of several messages for empty list depend of filtering from LLGroupList to LLFlatListEx
 * change inheritence of LLGroupList and LLAvatarList from LLFlatListView to LLFlatListViewEx
 * updated panel people to init Nearby & Recent lists with appropriate messages.

--HG--
branch : product-engine
---
 indra/llui/llflatlistview.cpp                 | 38 ++++++++++++-
 indra/llui/llflatlistview.h                   | 54 ++++++++++++++++++-
 indra/newview/llavatarlist.cpp                | 12 +++--
 indra/newview/llavatarlist.h                  |  4 +-
 indra/newview/llgrouplist.cpp                 | 21 +-------
 indra/newview/llgrouplist.h                   | 22 +-------
 indra/newview/llpanelpeople.cpp               | 10 ++--
 .../skins/default/xui/en/panel_people.xml     | 10 +++-
 8 files changed, 116 insertions(+), 55 deletions(-)

diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index 82f054c4b7..990bf5cd22 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -1,10 +1,10 @@
 /** 
  * @file llflatlistview.cpp
- * @brief LLFlatListView base class
+ * @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
  *
  * $LicenseInfo:firstyear=2009&license=viewergpl$
  * 
- * Copyright (c) 2009, Linden Research, Inc.
+ * Copyright (c) 2009-2010, Linden Research, Inc.
  * 
  * Second Life Viewer Source Code
  * The source code in this file ("Source Code") is provided by Linden Lab
@@ -1122,4 +1122,38 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
 	}
 }
 
+
+/************************************************************************/
+/*             LLFlatListViewEx implementation                          */
+/************************************************************************/
+LLFlatListViewEx::Params::Params()
+: no_items_msg("no_items_msg")
+, no_filtered_items_msg("no_filtered_items_msg")
+{
+
+}
+
+LLFlatListViewEx::LLFlatListViewEx(const Params& p)
+:	LLFlatListView(p)
+, mNoFilteredItemsMsg(p.no_filtered_items_msg)
+, mNoItemsMsg(p.no_items_msg)
+{
+
+}
+
+void LLFlatListViewEx::updateNoItemsMessage(bool items_filtered)
+{
+	if (items_filtered)
+	{
+		// items were filtered
+		setNoItemsCommentText(mNoFilteredItemsMsg);
+	}
+	else
+	{
+		// list does not contain any items at all
+		setNoItemsCommentText(mNoItemsMsg);
+	}
+
+}
+
 //EOF
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index e3c07e811f..f7d094f7e7 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -1,10 +1,10 @@
 /** 
  * @file llflatlistview.h
- * @brief LLFlatListView base class
+ * @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
  *
  * $LicenseInfo:firstyear=2009&license=viewergpl$
  * 
- * Copyright (c) 2009, Linden Research, Inc.
+ * Copyright (c) 2009-2010, Linden Research, Inc.
  * 
  * Second Life Viewer Source Code
  * The source code in this file ("Source Code") is provided by Linden Lab
@@ -430,4 +430,54 @@ private:
 	commit_signal_t	mOnReturnSignal;
 };
 
+/**
+ * Extends LLFlatListView functionality to show different messages when there are no items in the
+ * list depend on whether they are filtered or not.
+ *
+ * Class provides one message per case of empty list.
+ * It also provides protected updateNoItemsMessage() method to be called each time when derived list
+ * is changed to update base mNoItemsCommentTextbox value.
+ *
+ * It is implemented to avoid duplication of this functionality in concrete implementations of the
+ * lists. It is intended to be used as a base class for lists which should support two different
+ * messages for empty state. Can be improved to support more than two messages via state-to-message map.
+ */
+class LLFlatListViewEx : public LLFlatListView
+{
+public:
+	struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
+	{
+		/**
+		 * Contains a message for empty list when it does not contain any items at all.
+		 */
+		Optional<std::string>	no_items_msg;
+
+		/**
+		 * Contains a message for empty list when its items are removed by filtering.
+		 */
+		Optional<std::string>	no_filtered_items_msg;
+		Params();
+	};
+
+	// *WORKAROUND: two methods to overload appropriate Params due to localization issue:
+	// no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931
+	void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
+	void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
+
+protected:
+	LLFlatListViewEx(const Params& p);
+
+	/**
+	 * Applies a message for empty list depend on passed argument.
+	 *
+	 * @param items_filtered - if true message for filtered items will be set, otherwise for
+	 * completely empty list.
+	 */
+	void updateNoItemsMessage(bool items_filtered);
+
+private:
+	std::string mNoFilteredItemsMsg;
+	std::string mNoItemsMsg;
+};
+
 #endif
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index c7a5691d70..8ba47b5198 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -113,7 +113,7 @@ LLAvatarList::Params::Params()
 }
 
 LLAvatarList::LLAvatarList(const Params& p)
-:	LLFlatListView(p)
+:	LLFlatListViewEx(p)
 , mIgnoreOnlineStatus(p.ignore_online_status)
 , mShowLastInteractionTime(p.show_last_interaction_time)
 , mContextMenu(NULL)
@@ -154,7 +154,7 @@ void LLAvatarList::draw()
 	// *NOTE dzaporozhan
 	// Call refresh() after draw() to avoid flickering of avatar list items.
 
-	LLFlatListView::draw();
+	LLFlatListViewEx::draw();
 
 	if (mDirty)
 		refresh();
@@ -171,7 +171,7 @@ void LLAvatarList::clear()
 {
 	getIDs().clear();
 	setDirty(true);
-	LLFlatListView::clear();
+	LLFlatListViewEx::clear();
 }
 
 void LLAvatarList::setNameFilter(const std::string& filter)
@@ -179,6 +179,10 @@ void LLAvatarList::setNameFilter(const std::string& filter)
 	if (mNameFilter != filter)
 	{
 		mNameFilter = filter;
+
+		// update message for empty state here instead of refresh() to avoid blinking when switch
+		// between tabs.
+		updateNoItemsMessage(!mNameFilter.empty());
 		setDirty();
 	}
 }
@@ -360,7 +364,7 @@ S32 LLAvatarList::notifyParent(const LLSD& info)
 		sort();
 		return 1;
 	}
-	return LLFlatListView::notifyParent(info);
+	return LLFlatListViewEx::notifyParent(info);
 }
 
 void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos)
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index 528f796b8b..ff090f3a34 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -49,11 +49,11 @@ class LLTimer;
  * @see setDirty()
  * @see setNameFilter()
  */
-class LLAvatarList : public LLFlatListView
+class LLAvatarList : public LLFlatListViewEx
 {
 	LOG_CLASS(LLAvatarList);
 public:
-	struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> 
+	struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
 	{
 		Optional<bool>	ignore_online_status, // show all items as online
 						show_last_interaction_time, // show most recent interaction time. *HACK: move this to a derived class
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 8a056f836f..f21b6e1085 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -71,18 +71,10 @@ public:
 
 static const LLGroupComparator GROUP_COMPARATOR;
 
-LLGroupList::Params::Params()
-: no_groups_msg("no_groups_msg")
-, no_filtered_groups_msg("no_filtered_groups_msg")
-{
-	
-}
 
 LLGroupList::LLGroupList(const Params& p)
-:	LLFlatListView(p)
+:	LLFlatListViewEx(p)
 	, mDirty(true) // to force initial update
-	, mNoFilteredGroupsMsg(p.no_filtered_groups_msg)
-	, mNoGroupsMsg(p.no_groups_msg)
 {
 	// Listen for agent group changes.
 	gAgent.addListener(this, "new group");
@@ -160,16 +152,7 @@ void LLGroupList::refresh()
 	bool				have_filter		= !mNameFilter.empty();
 
 	// set no items message depend on filter state & total count of groups
-	if (have_filter)
-	{
-		// groups were filtered
-		setNoItemsCommentText(mNoFilteredGroupsMsg);
-	}
-	else if (0 == count)
-	{
-		// user is not a member of any group
-		setNoItemsCommentText(mNoGroupsMsg);
-	}
+	updateNoItemsMessage(have_filter);
 
 	clear();
 
diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h
index 0e9da25c58..16f3fc05a3 100644
--- a/indra/newview/llgrouplist.h
+++ b/indra/newview/llgrouplist.h
@@ -47,23 +47,10 @@
  * 
  * @see setNameFilter()
  */
-class LLGroupList: public LLFlatListView, public LLOldEvents::LLSimpleListener
+class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener
 {
 	LOG_CLASS(LLGroupList);
 public:
-	struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> 
-	{
-		/**
-		 * Contains a message for empty list when user is not a member of any group
-		 */
-		Optional<std::string>	no_groups_msg;
-
-		/**
-		 * Contains a message for empty list when all groups don't match passed filter
-		 */
-		Optional<std::string>	no_filtered_groups_msg;
-		Params();
-	};
 
 	LLGroupList(const Params& p);
 	virtual ~LLGroupList();
@@ -75,11 +62,6 @@ public:
 	void toggleIcons();
 	bool getIconsVisible() const { return mShowIcons; }
 
-	// *WORKAROUND: two methods to overload appropriate Params due to localization issue:
-	// no_groups_msg & no_filtered_groups_msg attributes are not defined as translatable in VLT. See EXT-5931
-	void setNoGroupsMsg(const std::string& msg) { mNoGroupsMsg = msg; }
-	void setNoFilteredGroupsMsg(const std::string& msg) { mNoFilteredGroupsMsg = msg; }
-	
 private:
 	void setDirty(bool val = true)		{ mDirty = val; }
 	void refresh();
@@ -94,8 +76,6 @@ private:
 	bool mShowIcons;
 	bool mDirty;
 	std::string mNameFilter;
-	std::string mNoFilteredGroupsMsg;
-	std::string mNoGroupsMsg;
 };
 
 class LLButton;
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 5802d53cd1..daa2a04f65 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -512,15 +512,19 @@ BOOL LLPanelPeople::postBuild()
 
 	mNearbyList = getChild<LLPanel>(NEARBY_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
 	mNearbyList->setNoItemsCommentText(getString("no_one_near"));
+	mNearbyList->setNoItemsMsg(getString("no_one_near"));
+	mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
 	mNearbyList->setShowIcons("NearbyListShowIcons");
 
 	mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
-	mRecentList->setNoItemsCommentText(getString("no_people"));
+	mRecentList->setNoItemsCommentText(getString("no_recent_people"));
+	mRecentList->setNoItemsMsg(getString("no_recent_people"));
+	mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people"));
 	mRecentList->setShowIcons("RecentListShowIcons");
 
 	mGroupList = getChild<LLGroupList>("group_list");
-	mGroupList->setNoGroupsMsg(getString("no_groups_msg"));
-	mGroupList->setNoFilteredGroupsMsg(getString("no_filtered_groups_msg"));
+	mGroupList->setNoItemsMsg(getString("no_groups_msg"));
+	mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg"));
 
 	mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
 	mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 8a4a28e188..61784fede4 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -12,11 +12,17 @@
  top="0"
  width="333">
     <string
-     name="no_people"
+     name="no_recent_people"
      value="No recent people. Looking for people to hang out with? Try [secondlife:///app/search/people Search] or the [secondlife:///app/worldmap World Map]." />
+    <string
+     name="no_filtered_recent_people"
+     value="Didn't find what you're looking for? Try [secondlife:///app/search/people Search]." />
     <string
      name="no_one_near"
      value="No one nearby. Looking for people to hang out with? Try [secondlife:///app/search/people Search] or the [secondlife:///app/worldmap World Map]." />
+    <string
+     name="no_one_filtered_near"
+     value="Didn't find what you're looking for? Try [secondlife:///app/search/people Search]." />
     <string
      name="no_friends_online"
      value="No friends online" />
@@ -30,7 +36,7 @@
      name="groups_filter_label"
      value="Filter Groups" />
      <!--
-     *WORKAROUND: for group_list.no_groups_msg & group_list.no_filtered_groups_msg attributes.
+     *WORKAROUND: for group_list.no_items_msg & group_list.no_filtered_items_msg attributes.
      They are not defined as translatable in VLT. See EXT-5931
      -->
     <string
-- 
GitLab