summaryrefslogtreecommitdiff
path: root/indra/newview/llpanelpeople.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llpanelpeople.cpp')
-rw-r--r--indra/newview/llpanelpeople.cpp515
1 files changed, 449 insertions, 66 deletions
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 61d66873ea..288edeb031 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -35,6 +35,8 @@
// libs
#include "llfloaterreg.h"
#include "llmenugl.h"
+#include "llnotificationsutil.h"
+#include "lleventtimer.h"
#include "llfiltereditor.h"
#include "lltabcontainer.h"
#include "lluictrlfactory.h"
@@ -42,6 +44,7 @@
#include "llpanelpeople.h"
// newview
+#include "llaccordionctrl.h"
#include "llaccordionctrltab.h"
#include "llagent.h"
#include "llavataractions.h"
@@ -53,12 +56,16 @@
#include "llfriendcard.h"
#include "llgroupactions.h"
#include "llgrouplist.h"
+#include "llinventoryobserver.h"
#include "llpanelpeoplemenus.h"
+#include "llsidetray.h"
+#include "llsidetraypanelcontainer.h"
#include "llrecentpeople.h"
#include "llviewercontrol.h" // for gSavedSettings
#include "llviewermenu.h" // for gMenuHolder
#include "llvoiceclient.h"
#include "llworld.h"
+#include "llspeakers.h"
#define FRIEND_LIST_UPDATE_TIMEOUT 0.5
#define NEARBY_LIST_UPDATE_INTERVAL 1
@@ -68,6 +75,8 @@ static const std::string FRIENDS_TAB_NAME = "friends_panel";
static const std::string GROUP_TAB_NAME = "groups_panel";
static const std::string RECENT_TAB_NAME = "recent_panel";
+static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
+
/** Comparator for comparing avatar items by last interaction date */
class LLAvatarItemRecentComparator : public LLAvatarItemComparator
{
@@ -118,8 +127,84 @@ protected:
}
};
+/** Compares avatar items by distance between you and them */
+class LLAvatarItemDistanceComparator : public LLAvatarItemComparator
+{
+public:
+ typedef std::map < LLUUID, LLVector3d > id_to_pos_map_t;
+ LLAvatarItemDistanceComparator() {};
+
+ void updateAvatarsPositions(std::vector<LLVector3d>& positions, uuid_vec_t& uuids)
+ {
+ std::vector<LLVector3d>::const_iterator
+ pos_it = positions.begin(),
+ pos_end = positions.end();
+
+ uuid_vec_t::const_iterator
+ id_it = uuids.begin(),
+ id_end = uuids.end();
+
+ LLAvatarItemDistanceComparator::id_to_pos_map_t pos_map;
+
+ mAvatarsPositions.clear();
+
+ for (;pos_it != pos_end && id_it != id_end; ++pos_it, ++id_it )
+ {
+ mAvatarsPositions[*id_it] = *pos_it;
+ }
+ };
+
+protected:
+ virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const
+ {
+ const LLVector3d& me_pos = gAgent.getPositionGlobal();
+ const LLVector3d& item1_pos = mAvatarsPositions.find(item1->getAvatarId())->second;
+ const LLVector3d& item2_pos = mAvatarsPositions.find(item2->getAvatarId())->second;
+ F32 dist1 = dist_vec(item1_pos, me_pos);
+ F32 dist2 = dist_vec(item2_pos, me_pos);
+ return dist1 < dist2;
+ }
+private:
+ id_to_pos_map_t mAvatarsPositions;
+};
+
+/** Comparator for comparing nearby avatar items by last spoken time */
+class LLAvatarItemRecentSpeakerComparator : public LLAvatarItemNameComparator
+{
+public:
+ LLAvatarItemRecentSpeakerComparator() {};
+ virtual ~LLAvatarItemRecentSpeakerComparator() {};
+
+protected:
+ virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const
+ {
+ LLPointer<LLSpeaker> lhs = LLActiveSpeakerMgr::instance().findSpeaker(item1->getAvatarId());
+ LLPointer<LLSpeaker> rhs = LLActiveSpeakerMgr::instance().findSpeaker(item2->getAvatarId());
+ if ( lhs.notNull() && rhs.notNull() )
+ {
+ // Compare by last speaking time
+ if( lhs->mLastSpokeTime != rhs->mLastSpokeTime )
+ return ( lhs->mLastSpokeTime > rhs->mLastSpokeTime );
+ }
+ else if ( lhs.notNull() )
+ {
+ // True if only item1 speaker info available
+ return true;
+ }
+ else if ( rhs.notNull() )
+ {
+ // False if only item2 speaker info available
+ return false;
+ }
+ // By default compare by name.
+ return LLAvatarItemNameComparator::doCompare(item1, item2);
+ }
+};
+
static const LLAvatarItemRecentComparator RECENT_COMPARATOR;
static const LLAvatarItemStatusComparator STATUS_COMPARATOR;
+static LLAvatarItemDistanceComparator DISTANCE_COMPARATOR;
+static const LLAvatarItemRecentSpeakerComparator RECENT_SPEAKER_COMPARATOR;
static LLRegisterPanelClassWrapper<LLPanelPeople> t_people("panel_people");
@@ -197,7 +282,8 @@ public:
~LLFriendListUpdater()
{
- delete mInvObserver;
+ // will be deleted by ~LLInventoryModel
+ //delete mInvObserver;
LLVoiceClient::getInstance()->removeObserver(this);
LLAvatarTracker::instance().removeObserver(this);
}
@@ -368,6 +454,7 @@ LLPanelPeople::LLPanelPeople()
mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this));
mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this));
mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this));
+ mCommitCallbackRegistrar.add("People.addFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this));
}
LLPanelPeople::~LLPanelPeople()
@@ -376,6 +463,11 @@ LLPanelPeople::~LLPanelPeople()
delete mFriendListUpdater;
delete mRecentListUpdater;
+ if(LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->removeObserver(this);
+ }
+
LLView::deleteViewByHandle(mGroupPlusMenuHandle);
LLView::deleteViewByHandle(mNearbyViewSortMenuHandle);
LLView::deleteViewByHandle(mFriendsViewSortMenuHandle);
@@ -384,7 +476,7 @@ LLPanelPeople::~LLPanelPeople()
}
-void LLPanelPeople::onFriendsAccordionExpandedCollapsed(const LLSD& param, LLAvatarList* avatar_list)
+void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list)
{
if(!avatar_list)
{
@@ -394,6 +486,7 @@ void LLPanelPeople::onFriendsAccordionExpandedCollapsed(const LLSD& param, LLAva
bool expanded = param.asBoolean();
+ setAccordionCollapsedByUser(ctrl, !expanded);
if(!expanded)
{
avatar_list->resetSelection();
@@ -402,7 +495,7 @@ void LLPanelPeople::onFriendsAccordionExpandedCollapsed(const LLSD& param, LLAva
BOOL LLPanelPeople::postBuild()
{
- mVisibleSignal.connect(boost::bind(&LLPanelPeople::onVisibilityChange, this, _2));
+ setVisibleCallback(boost::bind(&LLPanelPeople::onVisibilityChange, this, _2));
mFilterEditor = getChild<LLFilterEditor>("filter_input");
mFilterEditor->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
@@ -413,59 +506,73 @@ BOOL LLPanelPeople::postBuild()
mOnlineFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_online");
mAllFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_all");
mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online"));
+ mOnlineFriendList->setShowIcons("FriendsListShowIcons");
mAllFriendList->setNoItemsCommentText(getString("no_friends"));
+ mAllFriendList->setShowIcons("FriendsListShowIcons");
mNearbyList = getChild<LLPanel>(NEARBY_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
mNearbyList->setNoItemsCommentText(getString("no_one_near"));
+ mNearbyList->setShowIcons("NearbyListShowIcons");
mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
mRecentList->setNoItemsCommentText(getString("no_people"));
+ mRecentList->setShowIcons("RecentListShowIcons");
mGroupList = getChild<LLGroupList>("group_list");
- mGroupList->setNoItemsCommentText(getString("no_groups"));
+ mGroupList->setNoGroupsMsg(getString("no_groups_msg"));
+ mGroupList->setNoFilteredGroupsMsg(getString("no_filtered_groups_msg"));
mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
+ mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
+ mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false);
setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false);
+ setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false);
LLPanel* groups_panel = getChild<LLPanel>(GROUP_TAB_NAME);
groups_panel->childSetAction("activate_btn", boost::bind(&LLPanelPeople::onActivateButtonClicked, this));
groups_panel->childSetAction("plus_btn", boost::bind(&LLPanelPeople::onGroupPlusButtonClicked, this));
- groups_panel->childSetAction("minus_btn", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this));
LLPanel* friends_panel = getChild<LLPanel>(FRIENDS_TAB_NAME);
friends_panel->childSetAction("add_btn", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this));
friends_panel->childSetAction("del_btn", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this));
- mOnlineFriendList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mOnlineFriendList));
- mAllFriendList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mAllFriendList));
- mNearbyList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mNearbyList));
- mRecentList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mRecentList));
+ mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
+ mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
+ mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
+ mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList));
mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList));
mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList));
mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList));
- mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onGroupInfoButtonClicked, this));
+ // Set openning IM as default on return action for avatar lists
+ mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
+ mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
+ mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
+ mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
+
+ mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this));
mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this));
+ mGroupList->setReturnCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this));
LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>("tab_all");
accordion_tab->setDropDownStateChangedCallback(
- boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _2, mAllFriendList));
+ boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mAllFriendList));
accordion_tab = getChild<LLAccordionCtrlTab>("tab_online");
accordion_tab->setDropDownStateChangedCallback(
- boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _2, mOnlineFriendList));
+ boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mOnlineFriendList));
buttonSetAction("view_profile_btn", boost::bind(&LLPanelPeople::onViewProfileButtonClicked, this));
- buttonSetAction("add_friend_btn", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this));
buttonSetAction("group_info_btn", boost::bind(&LLPanelPeople::onGroupInfoButtonClicked, this));
buttonSetAction("chat_btn", boost::bind(&LLPanelPeople::onChatButtonClicked, this));
buttonSetAction("im_btn", boost::bind(&LLPanelPeople::onImButtonClicked, this));
buttonSetAction("call_btn", boost::bind(&LLPanelPeople::onCallButtonClicked, this));
+ buttonSetAction("group_call_btn", boost::bind(&LLPanelPeople::onGroupCallButtonClicked, this));
buttonSetAction("teleport_btn", boost::bind(&LLPanelPeople::onTeleportButtonClicked, this));
buttonSetAction("share_btn", boost::bind(&LLPanelPeople::onShareButtonClicked, this));
@@ -475,21 +582,24 @@ BOOL LLPanelPeople::postBuild()
getChild<LLPanel>(GROUP_TAB_NAME)->childSetAction("groups_viewsort_btn",boost::bind(&LLPanelPeople::onGroupsViewSortButtonClicked, this));
// Must go after setting commit callback and initializing all pointers to children.
- mTabContainer->selectTabByName(FRIENDS_TAB_NAME);
+ mTabContainer->selectTabByName(NEARBY_TAB_NAME);
// Create menus.
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
registrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2));
+ registrar.add("People.Group.Minus.Action", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this));
registrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2));
registrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2));
registrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2));
registrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2));
+ enable_registrar.add("People.Group.Minus.Enable", boost::bind(&LLPanelPeople::isRealGroup, this));
enable_registrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2));
enable_registrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2));
-
+ enable_registrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2));
+
LLMenuGL* plus_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_group_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
mGroupPlusMenuHandle = plus_menu->getHandle();
@@ -509,12 +619,28 @@ BOOL LLPanelPeople::postBuild()
if(recent_view_sort)
mRecentViewSortMenuHandle = recent_view_sort->getHandle();
+ gVoiceClient->addObserver(this);
+
// call this method in case some list is empty and buttons can be in inconsistent state
updateButtons();
+ mOnlineFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2));
+ mAllFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2));
+
return TRUE;
}
+// virtual
+void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+ if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+ {
+ return;
+ }
+
+ updateButtons();
+}
+
void LLPanelPeople::updateFriendList()
{
if (!mOnlineFriendList || !mAllFriendList)
@@ -554,8 +680,24 @@ void LLPanelPeople::updateFriendList()
online_friendsp.push_back(buddy_id);
}
- mOnlineFriendList->setDirty();
- mAllFriendList->setDirty();
+ // show special help text for just created account to help found friends. EXT-4836
+ static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_msg");
+
+ // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
+ // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
+ bool any_friend_exists = (all_friendsp.size() > 0) || (online_friendsp.size() > 0);
+ no_friends_text->setVisible(!any_friend_exists);
+
+ /*
+ * Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items.
+ * But avatarlist can be updated only if it is visible @see LLAvatarList::draw();
+ * So we need to do force update of lists to avoid inconsistency of data and view of avatarlist.
+ */
+ mOnlineFriendList->setDirty(true, !mOnlineFriendList->filterHasMatches());// do force update if list do NOT have items
+ mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches());
+ //update trash and other buttons according to a selected item
+ updateButtons();
+ showFriendsAccordionsIfNeeded();
}
void LLPanelPeople::updateNearbyList()
@@ -563,8 +705,13 @@ void LLPanelPeople::updateNearbyList()
if (!mNearbyList)
return;
- LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
+ std::vector<LLVector3d> positions;
+
+ LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
mNearbyList->setDirty();
+
+ DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs());
+ LLActiveSpeakerMgr::instance().update(TRUE);
}
void LLPanelPeople::updateRecentList()
@@ -578,14 +725,9 @@ void LLPanelPeople::updateRecentList()
void LLPanelPeople::buttonSetVisible(std::string btn_name, BOOL visible)
{
- // Currently all bottom buttons are wrapped with layout panels.
- // Hiding a button has no effect: the panel still occupies its space.
- // So we have to hide the whole panel (along with its button)
- // to free some space up.
- LLButton* btn = getChild<LLView>("button_bar")->getChild<LLButton>(btn_name);
- LLPanel* btn_parent = dynamic_cast<LLPanel*>(btn->getParent());
- if (btn_parent)
- btn_parent->setVisible(visible);
+ // To make sure we're referencing the right widget (a child of the button bar).
+ LLButton* button = getChild<LLView>("button_bar")->getChild<LLButton>(btn_name);
+ button->setVisible(visible);
}
void LLPanelPeople::buttonSetEnabled(const std::string& btn_name, bool enabled)
@@ -602,26 +744,37 @@ void LLPanelPeople::buttonSetAction(const std::string& btn_name, const commit_si
button->setClickedCallback(cb);
}
+bool LLPanelPeople::isFriendOnline(const LLUUID& id)
+{
+ LLAvatarList::uuid_vector_t ids = mOnlineFriendList->getIDs();
+ return std::find(ids.begin(), ids.end(), id) != ids.end();
+}
+
void LLPanelPeople::updateButtons()
{
std::string cur_tab = getActiveTabName();
bool nearby_tab_active = (cur_tab == NEARBY_TAB_NAME);
bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME);
bool group_tab_active = (cur_tab == GROUP_TAB_NAME);
- bool recent_tab_active = (cur_tab == RECENT_TAB_NAME);
+ //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME);
LLUUID selected_id;
+ uuid_vec_t selected_uuids;
+ getCurrentItemIDs(selected_uuids);
+ bool item_selected = (selected_uuids.size() == 1);
+ bool multiple_selected = (selected_uuids.size() >= 1);
+
buttonSetVisible("group_info_btn", group_tab_active);
buttonSetVisible("chat_btn", group_tab_active);
- buttonSetVisible("add_friend_btn", nearby_tab_active || recent_tab_active);
buttonSetVisible("view_profile_btn", !group_tab_active);
buttonSetVisible("im_btn", !group_tab_active);
+ buttonSetVisible("call_btn", !group_tab_active);
+ buttonSetVisible("group_call_btn", group_tab_active);
buttonSetVisible("teleport_btn", friends_tab_active);
- buttonSetVisible("share_btn", !recent_tab_active && false); // not implemented yet
+ buttonSetVisible("share_btn", nearby_tab_active || friends_tab_active);
if (group_tab_active)
{
- bool item_selected = mGroupList->getSelectedItem() != NULL;
bool cur_group_active = true;
if (item_selected)
@@ -629,10 +782,9 @@ void LLPanelPeople::updateButtons()
selected_id = mGroupList->getSelectedUUID();
cur_group_active = (gAgent.getGroupID() == selected_id);
}
-
+
LLPanel* groups_panel = mTabContainer->getCurrentPanel();
groups_panel->childSetEnabled("activate_btn", item_selected && !cur_group_active); // "none" or a non-active group selected
- groups_panel->childSetEnabled("plus_btn", item_selected);
groups_panel->childSetEnabled("minus_btn", item_selected && selected_id.notNull());
}
else
@@ -640,22 +792,35 @@ void LLPanelPeople::updateButtons()
bool is_friend = true;
// Check whether selected avatar is our friend.
- if ((selected_id = getCurrentItemID()).notNull())
+ if (item_selected)
{
+ selected_id = selected_uuids.front();
is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL;
}
- childSetEnabled("add_friend_btn", !is_friend);
+ LLPanel* cur_panel = mTabContainer->getCurrentPanel();
+ if (cur_panel)
+ {
+ cur_panel->childSetEnabled("add_friend_btn", !is_friend);
+ if (friends_tab_active)
+ {
+ cur_panel->childSetEnabled("del_btn", multiple_selected);
+ }
+ }
}
- bool item_selected = selected_id.notNull();
- buttonSetEnabled("teleport_btn", friends_tab_active && item_selected);
+ bool enable_calls = gVoiceClient->voiceWorking() && gVoiceClient->voiceEnabled();
+
+ buttonSetEnabled("teleport_btn", friends_tab_active && item_selected && isFriendOnline(selected_uuids.front()));
buttonSetEnabled("view_profile_btn", item_selected);
- buttonSetEnabled("im_btn", item_selected);
- buttonSetEnabled("call_btn", item_selected && false); // not implemented yet
- buttonSetEnabled("share_btn", item_selected && false); // not implemented yet
- buttonSetEnabled("group_info_btn", item_selected);
- buttonSetEnabled("chat_btn", item_selected);
+ buttonSetEnabled("im_btn", multiple_selected); // allow starting the friends conference for multiple selection
+ buttonSetEnabled("call_btn", multiple_selected && enable_calls);
+ buttonSetEnabled("share_btn", item_selected); // not implemented yet
+
+ bool none_group_selected = item_selected && selected_id.isNull();
+ buttonSetEnabled("group_info_btn", !none_group_selected);
+ buttonSetEnabled("group_call_btn", !none_group_selected && enable_calls);
+ buttonSetEnabled("chat_btn", !none_group_selected);
}
std::string LLPanelPeople::getActiveTabName() const
@@ -690,7 +855,7 @@ LLUUID LLPanelPeople::getCurrentItemID() const
return LLUUID::null;
}
-void LLPanelPeople::getCurrentItemIDs(std::vector<LLUUID>& selected_uuids) const
+void LLPanelPeople::getCurrentItemIDs(uuid_vec_t& selected_uuids) const
{
std::string cur_tab = getActiveTabName();
@@ -745,6 +910,14 @@ void LLPanelPeople::setSortOrder(LLAvatarList* list, ESortOrder order, bool save
list->setComparator(&RECENT_COMPARATOR);
list->sort();
break;
+ case E_SORT_BY_RECENT_SPEAKERS:
+ list->setComparator(&RECENT_SPEAKER_COMPARATOR);
+ list->sort();
+ break;
+ case E_SORT_BY_DISTANCE:
+ list->setComparator(&DISTANCE_COMPARATOR);
+ list->sort();
+ break;
default:
llwarns << "Unrecognized people sort order for " << list->getName() << llendl;
return;
@@ -759,7 +932,7 @@ void LLPanelPeople::setSortOrder(LLAvatarList* list, ESortOrder order, bool save
else if (list == mRecentList)
setting = "RecentPeopleSortOrder";
else if (list == mNearbyList)
- setting = "NearbyPeopleSortOrder"; // *TODO: unused by current implementation
+ setting = "NearbyPeopleSortOrder";
if (!setting.empty())
gSavedSettings.setU32(setting, order);
@@ -788,16 +961,29 @@ void LLPanelPeople::reSelectedCurrentTab()
mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
}
+bool LLPanelPeople::isRealGroup()
+{
+ return getCurrentItemID() != LLUUID::null;
+}
+
void LLPanelPeople::onFilterEdit(const std::string& search_string)
{
- if (mFilterSubString == search_string)
+ std::string search_upper = search_string;
+ // Searches are case-insensitive
+ LLStringUtil::toUpper(search_upper);
+ LLStringUtil::trimHead(search_upper);
+
+ if (mFilterSubString == search_upper)
return;
- mFilterSubString = search_string;
+ mFilterSubString = search_upper;
+
+ //store accordion tabs state before any manipulation with accordion tabs
+ if(!mFilterSubString.empty())
+ {
+ notifyChildren(LLSD().with("action","store_state"));
+ }
- // Searches are case-insensitive
- LLStringUtil::toUpper(mFilterSubString);
- LLStringUtil::trimHead(mFilterSubString);
// Apply new filter.
mNearbyList->setNameFilter(mFilterSubString);
@@ -805,6 +991,17 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string)
mAllFriendList->setNameFilter(mFilterSubString);
mRecentList->setNameFilter(mFilterSubString);
mGroupList->setNameFilter(mFilterSubString);
+
+ setAccordionCollapsedByUser("tab_online", false);
+ setAccordionCollapsedByUser("tab_all", false);
+
+ showFriendsAccordionsIfNeeded();
+
+ //restore accordion tabs state _after_ all manipulations...
+ if(mFilterSubString.empty())
+ {
+ notifyChildren(LLSD().with("action","restore_state"));
+ }
}
void LLPanelPeople::onTabSelected(const LLSD& param)
@@ -813,18 +1010,23 @@ void LLPanelPeople::onTabSelected(const LLSD& param)
mNearbyListUpdater->setActive(tab_name == NEARBY_TAB_NAME);
updateButtons();
+ showFriendsAccordionsIfNeeded();
+
if (GROUP_TAB_NAME == tab_name)
mFilterEditor->setLabel(getString("groups_filter_label"));
else
mFilterEditor->setLabel(getString("people_filter_label"));
}
-void LLPanelPeople::onAvatarListDoubleClicked(LLAvatarList* list)
+void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl)
{
- LLUUID clicked_id = list->getSelectedUUID();
-
- if (clicked_id.isNull())
+ LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(ctrl);
+ if(!item)
+ {
return;
+ }
+
+ LLUUID clicked_id = item->getAvatarId();
#if 0 // SJB: Useful for testing, but not currently functional or to spec
LLAvatarActions::showProfile(clicked_id);
@@ -864,10 +1066,28 @@ void LLPanelPeople::onAddFriendButtonClicked()
}
}
+bool LLPanelPeople::isItemsFreeOfFriends(const uuid_vec_t& uuids)
+{
+ const LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
+ for ( uuid_vec_t::const_iterator
+ id = uuids.begin(),
+ id_end = uuids.end();
+ id != id_end; ++id )
+ {
+ if (av_tracker.isBuddy (*id))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
void LLPanelPeople::onAddFriendWizButtonClicked()
{
// Show add friend wizard.
- LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(onAvatarPicked, NULL, FALSE, TRUE);
+ LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelPeople::onAvatarPicked, _1, _2), FALSE, TRUE);
+ // Need to disable 'ok' button when friend occurs in selection
+ if (picker) picker->setOkBtnEnableCb(boost::bind(&LLPanelPeople::isItemsFreeOfFriends, this, _1));
LLFloater* root_floater = gFloaterView->getParentFloater(this);
if (root_floater)
{
@@ -877,7 +1097,17 @@ void LLPanelPeople::onAddFriendWizButtonClicked()
void LLPanelPeople::onDeleteFriendButtonClicked()
{
- LLAvatarActions::removeFriendDialog(getCurrentItemID());
+ uuid_vec_t selected_uuids;
+ getCurrentItemIDs(selected_uuids);
+
+ if (selected_uuids.size() == 1)
+ {
+ LLAvatarActions::removeFriendDialog( selected_uuids.front() );
+ }
+ else if (selected_uuids.size() > 1)
+ {
+ LLAvatarActions::removeFriendsDialog( selected_uuids );
+ }
}
void LLPanelPeople::onGroupInfoButtonClicked()
@@ -889,12 +1119,12 @@ void LLPanelPeople::onChatButtonClicked()
{
LLUUID group_id = getCurrentItemID();
if (group_id.notNull())
- LLGroupActions::startChat(group_id);
+ LLGroupActions::startIM(group_id);
}
void LLPanelPeople::onImButtonClicked()
{
- std::vector<LLUUID> selected_uuids;
+ uuid_vec_t selected_uuids;
getCurrentItemIDs(selected_uuids);
if ( selected_uuids.size() == 1 )
{
@@ -916,8 +1146,7 @@ void LLPanelPeople::onActivateButtonClicked()
// static
void LLPanelPeople::onAvatarPicked(
const std::vector<std::string>& names,
- const std::vector<LLUUID>& ids,
- void*)
+ const uuid_vec_t& ids)
{
if (!names.empty() && !ids.empty())
LLAvatarActions::requestFriendshipDialog(ids[0], names[0]);
@@ -925,6 +1154,12 @@ void LLPanelPeople::onAvatarPicked(
void LLPanelPeople::onGroupPlusButtonClicked()
{
+ if (!gAgent.canJoinGroups())
+ {
+ LLNotificationsUtil::add("JoinedTooManyGroups");
+ return;
+ }
+
LLMenuGL* plus_menu = (LLMenuGL*)mGroupPlusMenuHandle.get();
if (!plus_menu)
return;
@@ -963,9 +1198,8 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
- }
- else if (chosen_item == "organize_offline")
- {
+ mAllFriendList->toggleIcons();
+ mOnlineFriendList->toggleIcons();
}
}
@@ -983,20 +1217,39 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)
{
std::string chosen_item = userdata.asString();
- if (chosen_item == "sort_recent")
+ if (chosen_item == "sort_by_recent_speakers")
{
+ setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS);
}
else if (chosen_item == "sort_name")
{
- mNearbyList->sortByName();
+ setSortOrder(mNearbyList, E_SORT_BY_NAME);
}
else if (chosen_item == "view_icons")
{
+ mNearbyList->toggleIcons();
}
else if (chosen_item == "sort_distance")
{
+ setSortOrder(mNearbyList, E_SORT_BY_DISTANCE);
}
}
+
+bool LLPanelPeople::onNearbyViewSortMenuItemCheck(const LLSD& userdata)
+{
+ std::string item = userdata.asString();
+ U32 sort_order = gSavedSettings.getU32("NearbyPeopleSortOrder");
+
+ if (item == "sort_by_recent_speakers")
+ return sort_order == E_SORT_BY_RECENT_SPEAKERS;
+ if (item == "sort_name")
+ return sort_order == E_SORT_BY_NAME;
+ if (item == "sort_distance")
+ return sort_order == E_SORT_BY_DISTANCE;
+
+ return false;
+}
+
void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)
{
std::string chosen_item = userdata.asString();
@@ -1011,7 +1264,7 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)
}
else if (chosen_item == "view_icons")
{
- // *TODO: implement showing/hiding icons
+ mRecentList->toggleIcons();
}
}
@@ -1043,7 +1296,24 @@ bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata)
void LLPanelPeople::onCallButtonClicked()
{
- // *TODO: not implemented yet
+ uuid_vec_t selected_uuids;
+ getCurrentItemIDs(selected_uuids);
+
+ if (selected_uuids.size() == 1)
+ {
+ // initiate a P2P voice chat with the selected user
+ LLAvatarActions::startCall(getCurrentItemID());
+ }
+ else if (selected_uuids.size() > 1)
+ {
+ // initiate an ad-hoc voice chat with multiple users
+ LLAvatarActions::startAdhocCall(selected_uuids);
+ }
+}
+
+void LLPanelPeople::onGroupCallButtonClicked()
+{
+ LLGroupActions::startCall(getCurrentItemID());
}
void LLPanelPeople::onTeleportButtonClicked()
@@ -1053,7 +1323,7 @@ void LLPanelPeople::onTeleportButtonClicked()
void LLPanelPeople::onShareButtonClicked()
{
- // *TODO: not implemented yet
+ LLAvatarActions::share(getCurrentItemID());
}
void LLPanelPeople::onMoreButtonClicked()
@@ -1104,3 +1374,116 @@ void LLPanelPeople::onOpen(const LLSD& key)
else
reSelectedCurrentTab();
}
+
+bool LLPanelPeople::notifyChildren(const LLSD& info)
+{
+ if (info.has("task-panel-action") && info["task-panel-action"].asString() == "handle-tri-state")
+ {
+ LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(getParent());
+ if (!container)
+ {
+ llwarns << "Cannot find People panel container" << llendl;
+ return true;
+ }
+
+ if (container->getCurrentPanelIndex() > 0)
+ {
+ // if not on the default panel, switch to it
+ container->onOpen(LLSD().with(LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME, getName()));
+ }
+ else
+ LLSideTray::getInstance()->collapseSideBar();
+
+ return true; // this notification is only supposed to be handled by task panels
+ }
+
+ return LLPanel::notifyChildren(info);
+}
+
+void LLPanelPeople::showAccordion(const std::string name, bool show)
+{
+ if(name.empty())
+ {
+ llwarns << "No name provided" << llendl;
+ return;
+ }
+
+ LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(name);
+ tab->setVisible(show);
+ if(show)
+ {
+ // don't expand accordion if it was collapsed by user
+ if(!isAccordionCollapsedByUser(tab))
+ {
+ // expand accordion
+ tab->changeOpenClose(false);
+ }
+ }
+}
+
+void LLPanelPeople::showFriendsAccordionsIfNeeded()
+{
+ if(FRIENDS_TAB_NAME == getActiveTabName())
+ {
+ // Expand and show accordions if needed, else - hide them
+ showAccordion("tab_online", mOnlineFriendList->filterHasMatches());
+ showAccordion("tab_all", mAllFriendList->filterHasMatches());
+
+ // Rearrange accordions
+ LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
+ accordion->arrange();
+ }
+}
+
+void LLPanelPeople::onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param)
+{
+ if(ctrl == mOnlineFriendList)
+ {
+ showAccordion("tab_online", param.asInteger());
+ }
+ else if(ctrl == mAllFriendList)
+ {
+ showAccordion("tab_all", param.asInteger());
+ }
+}
+
+void LLPanelPeople::setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed)
+{
+ if(!acc_tab)
+ {
+ llwarns << "Invalid parameter" << llendl;
+ return;
+ }
+
+ LLSD param = acc_tab->getValue();
+ param[COLLAPSED_BY_USER] = collapsed;
+ acc_tab->setValue(param);
+}
+
+void LLPanelPeople::setAccordionCollapsedByUser(const std::string& name, bool collapsed)
+{
+ setAccordionCollapsedByUser(getChild<LLUICtrl>(name), collapsed);
+}
+
+bool LLPanelPeople::isAccordionCollapsedByUser(LLUICtrl* acc_tab)
+{
+ if(!acc_tab)
+ {
+ llwarns << "Invalid parameter" << llendl;
+ return false;
+ }
+
+ LLSD param = acc_tab->getValue();
+ if(!param.has(COLLAPSED_BY_USER))
+ {
+ return false;
+ }
+ return param[COLLAPSED_BY_USER].asBoolean();
+}
+
+bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)
+{
+ return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
+}
+
+// EOF