PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/newview/llpanelpeople.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1553 lines | 1175 code | 237 blank | 141 comment | 238 complexity | 60174ecaf0ae2b5b936878c9359966a3 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llpanelpeople.cpp
  3. * @brief Side tray "People" panel
  4. *
  5. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. // libs
  28. #include "llavatarname.h"
  29. #include "llfloaterreg.h"
  30. #include "llfloatersidepanelcontainer.h"
  31. #include "llmenubutton.h"
  32. #include "llmenugl.h"
  33. #include "llnotificationsutil.h"
  34. #include "lleventtimer.h"
  35. #include "llfiltereditor.h"
  36. #include "lltabcontainer.h"
  37. #include "lltoggleablemenu.h"
  38. #include "lluictrlfactory.h"
  39. #include "llpanelpeople.h"
  40. // newview
  41. #include "llaccordionctrl.h"
  42. #include "llaccordionctrltab.h"
  43. #include "llagent.h"
  44. #include "llavataractions.h"
  45. #include "llavatarlist.h"
  46. #include "llavatarlistitem.h"
  47. #include "llcallingcard.h" // for LLAvatarTracker
  48. #include "llfloateravatarpicker.h"
  49. //#include "llfloaterminiinspector.h"
  50. #include "llfriendcard.h"
  51. #include "llgroupactions.h"
  52. #include "llgrouplist.h"
  53. #include "llinventoryobserver.h"
  54. #include "llnetmap.h"
  55. #include "llpanelpeoplemenus.h"
  56. #include "llsidetraypanelcontainer.h"
  57. #include "llrecentpeople.h"
  58. #include "llviewercontrol.h" // for gSavedSettings
  59. #include "llviewermenu.h" // for gMenuHolder
  60. #include "llvoiceclient.h"
  61. #include "llworld.h"
  62. #include "llspeakers.h"
  63. #define FRIEND_LIST_UPDATE_TIMEOUT 0.5
  64. #define NEARBY_LIST_UPDATE_INTERVAL 1
  65. static const std::string NEARBY_TAB_NAME = "nearby_panel";
  66. static const std::string FRIENDS_TAB_NAME = "friends_panel";
  67. static const std::string GROUP_TAB_NAME = "groups_panel";
  68. static const std::string RECENT_TAB_NAME = "recent_panel";
  69. static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
  70. /** Comparator for comparing avatar items by last interaction date */
  71. class LLAvatarItemRecentComparator : public LLAvatarItemComparator
  72. {
  73. public:
  74. LLAvatarItemRecentComparator() {};
  75. virtual ~LLAvatarItemRecentComparator() {};
  76. protected:
  77. virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const
  78. {
  79. LLRecentPeople& people = LLRecentPeople::instance();
  80. const LLDate& date1 = people.getDate(avatar_item1->getAvatarId());
  81. const LLDate& date2 = people.getDate(avatar_item2->getAvatarId());
  82. //older comes first
  83. return date1 > date2;
  84. }
  85. };
  86. /** Compares avatar items by online status, then by name */
  87. class LLAvatarItemStatusComparator : public LLAvatarItemComparator
  88. {
  89. public:
  90. LLAvatarItemStatusComparator() {};
  91. protected:
  92. /**
  93. * @return true if item1 < item2, false otherwise
  94. */
  95. virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const
  96. {
  97. LLAvatarTracker& at = LLAvatarTracker::instance();
  98. bool online1 = at.isBuddyOnline(item1->getAvatarId());
  99. bool online2 = at.isBuddyOnline(item2->getAvatarId());
  100. if (online1 == online2)
  101. {
  102. std::string name1 = item1->getAvatarName();
  103. std::string name2 = item2->getAvatarName();
  104. LLStringUtil::toUpper(name1);
  105. LLStringUtil::toUpper(name2);
  106. return name1 < name2;
  107. }
  108. return online1 > online2;
  109. }
  110. };
  111. /** Compares avatar items by distance between you and them */
  112. class LLAvatarItemDistanceComparator : public LLAvatarItemComparator
  113. {
  114. public:
  115. typedef std::map < LLUUID, LLVector3d > id_to_pos_map_t;
  116. LLAvatarItemDistanceComparator() {};
  117. void updateAvatarsPositions(std::vector<LLVector3d>& positions, uuid_vec_t& uuids)
  118. {
  119. std::vector<LLVector3d>::const_iterator
  120. pos_it = positions.begin(),
  121. pos_end = positions.end();
  122. uuid_vec_t::const_iterator
  123. id_it = uuids.begin(),
  124. id_end = uuids.end();
  125. LLAvatarItemDistanceComparator::id_to_pos_map_t pos_map;
  126. mAvatarsPositions.clear();
  127. for (;pos_it != pos_end && id_it != id_end; ++pos_it, ++id_it )
  128. {
  129. mAvatarsPositions[*id_it] = *pos_it;
  130. }
  131. };
  132. protected:
  133. virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const
  134. {
  135. const LLVector3d& me_pos = gAgent.getPositionGlobal();
  136. const LLVector3d& item1_pos = mAvatarsPositions.find(item1->getAvatarId())->second;
  137. const LLVector3d& item2_pos = mAvatarsPositions.find(item2->getAvatarId())->second;
  138. return dist_vec_squared(item1_pos, me_pos) < dist_vec_squared(item2_pos, me_pos);
  139. }
  140. private:
  141. id_to_pos_map_t mAvatarsPositions;
  142. };
  143. /** Comparator for comparing nearby avatar items by last spoken time */
  144. class LLAvatarItemRecentSpeakerComparator : public LLAvatarItemNameComparator
  145. {
  146. public:
  147. LLAvatarItemRecentSpeakerComparator() {};
  148. virtual ~LLAvatarItemRecentSpeakerComparator() {};
  149. protected:
  150. virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const
  151. {
  152. LLPointer<LLSpeaker> lhs = LLActiveSpeakerMgr::instance().findSpeaker(item1->getAvatarId());
  153. LLPointer<LLSpeaker> rhs = LLActiveSpeakerMgr::instance().findSpeaker(item2->getAvatarId());
  154. if ( lhs.notNull() && rhs.notNull() )
  155. {
  156. // Compare by last speaking time
  157. if( lhs->mLastSpokeTime != rhs->mLastSpokeTime )
  158. return ( lhs->mLastSpokeTime > rhs->mLastSpokeTime );
  159. }
  160. else if ( lhs.notNull() )
  161. {
  162. // True if only item1 speaker info available
  163. return true;
  164. }
  165. else if ( rhs.notNull() )
  166. {
  167. // False if only item2 speaker info available
  168. return false;
  169. }
  170. // By default compare by name.
  171. return LLAvatarItemNameComparator::doCompare(item1, item2);
  172. }
  173. };
  174. static const LLAvatarItemRecentComparator RECENT_COMPARATOR;
  175. static const LLAvatarItemStatusComparator STATUS_COMPARATOR;
  176. static LLAvatarItemDistanceComparator DISTANCE_COMPARATOR;
  177. static const LLAvatarItemRecentSpeakerComparator RECENT_SPEAKER_COMPARATOR;
  178. static LLRegisterPanelClassWrapper<LLPanelPeople> t_people("panel_people");
  179. //=============================================================================
  180. /**
  181. * Updates given list either on regular basis or on external events (up to implementation).
  182. */
  183. class LLPanelPeople::Updater
  184. {
  185. public:
  186. typedef boost::function<void()> callback_t;
  187. Updater(callback_t cb)
  188. : mCallback(cb)
  189. {
  190. }
  191. virtual ~Updater()
  192. {
  193. }
  194. /**
  195. * Activate/deactivate updater.
  196. *
  197. * This may start/stop regular updates.
  198. */
  199. virtual void setActive(bool) {}
  200. protected:
  201. void update()
  202. {
  203. mCallback();
  204. }
  205. callback_t mCallback;
  206. };
  207. /**
  208. * Update buttons on changes in our friend relations (STORM-557).
  209. */
  210. class LLButtonsUpdater : public LLPanelPeople::Updater, public LLFriendObserver
  211. {
  212. public:
  213. LLButtonsUpdater(callback_t cb)
  214. : LLPanelPeople::Updater(cb)
  215. {
  216. LLAvatarTracker::instance().addObserver(this);
  217. }
  218. ~LLButtonsUpdater()
  219. {
  220. LLAvatarTracker::instance().removeObserver(this);
  221. }
  222. /*virtual*/ void changed(U32 mask)
  223. {
  224. (void) mask;
  225. update();
  226. }
  227. };
  228. class LLAvatarListUpdater : public LLPanelPeople::Updater, public LLEventTimer
  229. {
  230. public:
  231. LLAvatarListUpdater(callback_t cb, F32 period)
  232. : LLEventTimer(period),
  233. LLPanelPeople::Updater(cb)
  234. {
  235. mEventTimer.stop();
  236. }
  237. virtual BOOL tick() // from LLEventTimer
  238. {
  239. return FALSE;
  240. }
  241. };
  242. /**
  243. * Updates the friends list.
  244. *
  245. * Updates the list on external events which trigger the changed() method.
  246. */
  247. class LLFriendListUpdater : public LLAvatarListUpdater, public LLFriendObserver
  248. {
  249. LOG_CLASS(LLFriendListUpdater);
  250. class LLInventoryFriendCardObserver;
  251. public:
  252. friend class LLInventoryFriendCardObserver;
  253. LLFriendListUpdater(callback_t cb)
  254. : LLAvatarListUpdater(cb, FRIEND_LIST_UPDATE_TIMEOUT)
  255. , mIsActive(false)
  256. {
  257. LLAvatarTracker::instance().addObserver(this);
  258. // For notification when SIP online status changes.
  259. LLVoiceClient::getInstance()->addObserver(this);
  260. mInvObserver = new LLInventoryFriendCardObserver(this);
  261. }
  262. ~LLFriendListUpdater()
  263. {
  264. // will be deleted by ~LLInventoryModel
  265. //delete mInvObserver;
  266. LLVoiceClient::getInstance()->removeObserver(this);
  267. LLAvatarTracker::instance().removeObserver(this);
  268. }
  269. /*virtual*/ void changed(U32 mask)
  270. {
  271. if (mIsActive)
  272. {
  273. // events can arrive quickly in bulk - we need not process EVERY one of them -
  274. // so we wait a short while to let others pile-in, and process them in aggregate.
  275. mEventTimer.start();
  276. }
  277. // save-up all the mask-bits which have come-in
  278. mMask |= mask;
  279. }
  280. /*virtual*/ BOOL tick()
  281. {
  282. if (!mIsActive) return FALSE;
  283. if (mMask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
  284. {
  285. update();
  286. }
  287. // Stop updates.
  288. mEventTimer.stop();
  289. mMask = 0;
  290. return FALSE;
  291. }
  292. // virtual
  293. void setActive(bool active)
  294. {
  295. mIsActive = active;
  296. if (active)
  297. {
  298. tick();
  299. }
  300. }
  301. private:
  302. U32 mMask;
  303. LLInventoryFriendCardObserver* mInvObserver;
  304. bool mIsActive;
  305. /**
  306. * This class is intended for updating Friend List when Inventory Friend Card is added/removed.
  307. *
  308. * The main usage is when Inventory Friends/All content is added while synchronizing with
  309. * friends list on startup is performed. In this case Friend Panel should be updated when
  310. * missing Inventory Friend Card is created.
  311. * *NOTE: updating is fired when Inventory item is added into CallingCards/Friends subfolder.
  312. * Otherwise LLFriendObserver functionality is enough to keep Friends Panel synchronized.
  313. */
  314. class LLInventoryFriendCardObserver : public LLInventoryObserver
  315. {
  316. LOG_CLASS(LLFriendListUpdater::LLInventoryFriendCardObserver);
  317. friend class LLFriendListUpdater;
  318. private:
  319. LLInventoryFriendCardObserver(LLFriendListUpdater* updater) : mUpdater(updater)
  320. {
  321. gInventory.addObserver(this);
  322. }
  323. ~LLInventoryFriendCardObserver()
  324. {
  325. gInventory.removeObserver(this);
  326. }
  327. /*virtual*/ void changed(U32 mask)
  328. {
  329. lldebugs << "Inventory changed: " << mask << llendl;
  330. static bool synchronize_friends_folders = true;
  331. if (synchronize_friends_folders)
  332. {
  333. // Checks whether "Friends" and "Friends/All" folders exist in "Calling Cards" folder,
  334. // fetches their contents if needed and synchronizes it with buddies list.
  335. // If the folders are not found they are created.
  336. LLFriendCardsManager::instance().syncFriendCardsFolders();
  337. synchronize_friends_folders = false;
  338. }
  339. // *NOTE: deleting of InventoryItem is performed via moving to Trash.
  340. // That means LLInventoryObserver::STRUCTURE is present in MASK instead of LLInventoryObserver::REMOVE
  341. if ((CALLINGCARD_ADDED & mask) == CALLINGCARD_ADDED)
  342. {
  343. lldebugs << "Calling card added: count: " << gInventory.getChangedIDs().size()
  344. << ", first Inventory ID: "<< (*gInventory.getChangedIDs().begin())
  345. << llendl;
  346. bool friendFound = false;
  347. std::set<LLUUID> changedIDs = gInventory.getChangedIDs();
  348. for (std::set<LLUUID>::const_iterator it = changedIDs.begin(); it != changedIDs.end(); ++it)
  349. {
  350. if (isDescendentOfInventoryFriends(*it))
  351. {
  352. friendFound = true;
  353. break;
  354. }
  355. }
  356. if (friendFound)
  357. {
  358. lldebugs << "friend found, panel should be updated" << llendl;
  359. mUpdater->changed(LLFriendObserver::ADD);
  360. }
  361. }
  362. }
  363. bool isDescendentOfInventoryFriends(const LLUUID& invItemID)
  364. {
  365. LLViewerInventoryItem * item = gInventory.getItem(invItemID);
  366. if (NULL == item)
  367. return false;
  368. return LLFriendCardsManager::instance().isItemInAnyFriendsList(item);
  369. }
  370. LLFriendListUpdater* mUpdater;
  371. static const U32 CALLINGCARD_ADDED = LLInventoryObserver::ADD | LLInventoryObserver::CALLING_CARD;
  372. };
  373. };
  374. /**
  375. * Periodically updates the nearby people list while the Nearby tab is active.
  376. *
  377. * The period is defined by NEARBY_LIST_UPDATE_INTERVAL constant.
  378. */
  379. class LLNearbyListUpdater : public LLAvatarListUpdater
  380. {
  381. LOG_CLASS(LLNearbyListUpdater);
  382. public:
  383. LLNearbyListUpdater(callback_t cb)
  384. : LLAvatarListUpdater(cb, NEARBY_LIST_UPDATE_INTERVAL)
  385. {
  386. setActive(false);
  387. }
  388. /*virtual*/ void setActive(bool val)
  389. {
  390. if (val)
  391. {
  392. // update immediately and start regular updates
  393. update();
  394. mEventTimer.start();
  395. }
  396. else
  397. {
  398. // stop regular updates
  399. mEventTimer.stop();
  400. }
  401. }
  402. /*virtual*/ BOOL tick()
  403. {
  404. update();
  405. return FALSE;
  406. }
  407. private:
  408. };
  409. /**
  410. * Updates the recent people list (those the agent has recently interacted with).
  411. */
  412. class LLRecentListUpdater : public LLAvatarListUpdater, public boost::signals2::trackable
  413. {
  414. LOG_CLASS(LLRecentListUpdater);
  415. public:
  416. LLRecentListUpdater(callback_t cb)
  417. : LLAvatarListUpdater(cb, 0)
  418. {
  419. LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::update, this));
  420. }
  421. };
  422. //=============================================================================
  423. LLPanelPeople::LLPanelPeople()
  424. : LLPanel(),
  425. mFilterSubString(LLStringUtil::null),
  426. mFilterSubStringOrig(LLStringUtil::null),
  427. mFilterEditor(NULL),
  428. mTabContainer(NULL),
  429. mOnlineFriendList(NULL),
  430. mAllFriendList(NULL),
  431. mNearbyList(NULL),
  432. mRecentList(NULL),
  433. mGroupList(NULL),
  434. mNearbyGearButton(NULL),
  435. mFriendsGearButton(NULL),
  436. mGroupsGearButton(NULL),
  437. mRecentGearButton(NULL),
  438. mMiniMap(NULL)
  439. {
  440. mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this));
  441. mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this));
  442. mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this));
  443. mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this));
  444. mCommitCallbackRegistrar.add("People.addFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this));
  445. }
  446. LLPanelPeople::~LLPanelPeople()
  447. {
  448. delete mButtonsUpdater;
  449. delete mNearbyListUpdater;
  450. delete mFriendListUpdater;
  451. delete mRecentListUpdater;
  452. if(LLVoiceClient::instanceExists())
  453. {
  454. LLVoiceClient::getInstance()->removeObserver(this);
  455. }
  456. if (mGroupPlusMenuHandle.get()) mGroupPlusMenuHandle.get()->die();
  457. if (mNearbyViewSortMenuHandle.get()) mNearbyViewSortMenuHandle.get()->die();
  458. if (mNearbyViewSortMenuHandle.get()) mNearbyViewSortMenuHandle.get()->die();
  459. if (mGroupsViewSortMenuHandle.get()) mGroupsViewSortMenuHandle.get()->die();
  460. if (mRecentViewSortMenuHandle.get()) mRecentViewSortMenuHandle.get()->die();
  461. }
  462. void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list)
  463. {
  464. if(!avatar_list)
  465. {
  466. llerrs << "Bad parameter" << llendl;
  467. return;
  468. }
  469. bool expanded = param.asBoolean();
  470. setAccordionCollapsedByUser(ctrl, !expanded);
  471. if(!expanded)
  472. {
  473. avatar_list->resetSelection();
  474. }
  475. }
  476. BOOL LLPanelPeople::postBuild()
  477. {
  478. mFilterEditor = getChild<LLFilterEditor>("filter_input");
  479. mFilterEditor->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2));
  480. mTabContainer = getChild<LLTabContainer>("tabs");
  481. mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2));
  482. LLPanel* friends_tab = getChild<LLPanel>(FRIENDS_TAB_NAME);
  483. // updater is active only if panel is visible to user.
  484. friends_tab->setVisibleCallback(boost::bind(&Updater::setActive, mFriendListUpdater, _2));
  485. mOnlineFriendList = friends_tab->getChild<LLAvatarList>("avatars_online");
  486. mAllFriendList = friends_tab->getChild<LLAvatarList>("avatars_all");
  487. mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online"));
  488. mOnlineFriendList->setShowIcons("FriendsListShowIcons");
  489. mOnlineFriendList->showPermissions("FriendsListShowPermissions");
  490. mAllFriendList->setNoItemsCommentText(getString("no_friends"));
  491. mAllFriendList->setShowIcons("FriendsListShowIcons");
  492. mAllFriendList->showPermissions("FriendsListShowPermissions");
  493. LLPanel* nearby_tab = getChild<LLPanel>(NEARBY_TAB_NAME);
  494. nearby_tab->setVisibleCallback(boost::bind(&Updater::setActive, mNearbyListUpdater, _2));
  495. mNearbyList = nearby_tab->getChild<LLAvatarList>("avatar_list");
  496. mNearbyList->setNoItemsCommentText(getString("no_one_near"));
  497. mNearbyList->setNoItemsMsg(getString("no_one_near"));
  498. mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
  499. mNearbyList->setShowIcons("NearbyListShowIcons");
  500. mMiniMap = (LLNetMap*)getChildView("Net Map",true);
  501. mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ?
  502. getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg"));
  503. mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
  504. mRecentList->setNoItemsCommentText(getString("no_recent_people"));
  505. mRecentList->setNoItemsMsg(getString("no_recent_people"));
  506. mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people"));
  507. mRecentList->setShowIcons("RecentListShowIcons");
  508. mGroupList = getChild<LLGroupList>("group_list");
  509. mGroupList->setNoItemsMsg(getString("no_groups_msg"));
  510. mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg"));
  511. mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
  512. mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
  513. mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
  514. mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
  515. setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false);
  516. setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false);
  517. setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false);
  518. LLPanel* groups_panel = getChild<LLPanel>(GROUP_TAB_NAME);
  519. groups_panel->childSetAction("activate_btn", boost::bind(&LLPanelPeople::onActivateButtonClicked, this));
  520. groups_panel->childSetAction("plus_btn", boost::bind(&LLPanelPeople::onGroupPlusButtonClicked, this));
  521. LLPanel* friends_panel = getChild<LLPanel>(FRIENDS_TAB_NAME);
  522. friends_panel->childSetAction("add_btn", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this));
  523. friends_panel->childSetAction("del_btn", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this));
  524. mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
  525. mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
  526. mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
  527. mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
  528. mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList));
  529. mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList));
  530. mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList));
  531. mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList));
  532. // Set openning IM as default on return action for avatar lists
  533. mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
  534. mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
  535. mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
  536. mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
  537. mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this));
  538. mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this));
  539. mGroupList->setReturnCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this));
  540. LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>("tab_all");
  541. accordion_tab->setDropDownStateChangedCallback(
  542. boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mAllFriendList));
  543. accordion_tab = getChild<LLAccordionCtrlTab>("tab_online");
  544. accordion_tab->setDropDownStateChangedCallback(
  545. boost::bind(&LLPanelPeople::onFriendsAccordionExpandedCollapsed, this, _1, _2, mOnlineFriendList));
  546. buttonSetAction("view_profile_btn", boost::bind(&LLPanelPeople::onViewProfileButtonClicked, this));
  547. buttonSetAction("group_info_btn", boost::bind(&LLPanelPeople::onGroupInfoButtonClicked, this));
  548. buttonSetAction("chat_btn", boost::bind(&LLPanelPeople::onChatButtonClicked, this));
  549. buttonSetAction("im_btn", boost::bind(&LLPanelPeople::onImButtonClicked, this));
  550. buttonSetAction("call_btn", boost::bind(&LLPanelPeople::onCallButtonClicked, this));
  551. buttonSetAction("group_call_btn", boost::bind(&LLPanelPeople::onGroupCallButtonClicked, this));
  552. buttonSetAction("teleport_btn", boost::bind(&LLPanelPeople::onTeleportButtonClicked, this));
  553. buttonSetAction("share_btn", boost::bind(&LLPanelPeople::onShareButtonClicked, this));
  554. // Must go after setting commit callback and initializing all pointers to children.
  555. mTabContainer->selectTabByName(NEARBY_TAB_NAME);
  556. // Create menus.
  557. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  558. LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
  559. registrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2));
  560. registrar.add("People.Group.Minus.Action", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this));
  561. registrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2));
  562. registrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2));
  563. registrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2));
  564. registrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2));
  565. enable_registrar.add("People.Group.Minus.Enable", boost::bind(&LLPanelPeople::isRealGroup, this));
  566. enable_registrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2));
  567. enable_registrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2));
  568. enable_registrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2));
  569. mNearbyGearButton = getChild<LLMenuButton>("nearby_view_sort_btn");
  570. mFriendsGearButton = getChild<LLMenuButton>("friends_viewsort_btn");
  571. mGroupsGearButton = getChild<LLMenuButton>("groups_viewsort_btn");
  572. mRecentGearButton = getChild<LLMenuButton>("recent_viewsort_btn");
  573. LLMenuGL* plus_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_group_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  574. mGroupPlusMenuHandle = plus_menu->getHandle();
  575. LLToggleableMenu* nearby_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_nearby_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  576. if(nearby_view_sort)
  577. {
  578. mNearbyViewSortMenuHandle = nearby_view_sort->getHandle();
  579. mNearbyGearButton->setMenu(nearby_view_sort);
  580. }
  581. LLToggleableMenu* friend_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_friends_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  582. if(friend_view_sort)
  583. {
  584. mFriendsViewSortMenuHandle = friend_view_sort->getHandle();
  585. mFriendsGearButton->setMenu(friend_view_sort);
  586. }
  587. LLToggleableMenu* group_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_groups_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  588. if(group_view_sort)
  589. {
  590. mGroupsViewSortMenuHandle = group_view_sort->getHandle();
  591. mGroupsGearButton->setMenu(group_view_sort);
  592. }
  593. LLToggleableMenu* recent_view_sort = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_people_recent_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  594. if(recent_view_sort)
  595. {
  596. mRecentViewSortMenuHandle = recent_view_sort->getHandle();
  597. mRecentGearButton->setMenu(recent_view_sort);
  598. }
  599. LLVoiceClient::getInstance()->addObserver(this);
  600. // call this method in case some list is empty and buttons can be in inconsistent state
  601. updateButtons();
  602. mOnlineFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2));
  603. mAllFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2));
  604. return TRUE;
  605. }
  606. // virtual
  607. void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, bool proximal)
  608. {
  609. if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
  610. {
  611. return;
  612. }
  613. updateButtons();
  614. }
  615. void LLPanelPeople::updateFriendListHelpText()
  616. {
  617. // show special help text for just created account to help finding friends. EXT-4836
  618. static LLTextBox* no_friends_text = getChild<LLTextBox>("no_friends_help_text");
  619. // Seems sometimes all_friends can be empty because of issue with Inventory loading (clear cache, slow connection...)
  620. // So, lets check all lists to avoid overlapping the text with online list. See EXT-6448.
  621. bool any_friend_exists = mAllFriendList->filterHasMatches() || mOnlineFriendList->filterHasMatches();
  622. no_friends_text->setVisible(!any_friend_exists);
  623. if (no_friends_text->getVisible())
  624. {
  625. //update help text for empty lists
  626. std::string message_name = mFilterSubString.empty() ? "no_friends_msg" : "no_filtered_friends_msg";
  627. LLStringUtil::format_map_t args;
  628. args["[SEARCH_TERM]"] = LLURI::escape(mFilterSubStringOrig);
  629. no_friends_text->setText(getString(message_name, args));
  630. }
  631. }
  632. void LLPanelPeople::updateFriendList()
  633. {
  634. if (!mOnlineFriendList || !mAllFriendList)
  635. return;
  636. // get all buddies we know about
  637. const LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
  638. LLAvatarTracker::buddy_map_t all_buddies;
  639. av_tracker.copyBuddyList(all_buddies);
  640. // save them to the online and all friends vectors
  641. uuid_vec_t& online_friendsp = mOnlineFriendList->getIDs();
  642. uuid_vec_t& all_friendsp = mAllFriendList->getIDs();
  643. all_friendsp.clear();
  644. online_friendsp.clear();
  645. uuid_vec_t buddies_uuids;
  646. LLAvatarTracker::buddy_map_t::const_iterator buddies_iter;
  647. // Fill the avatar list with friends UUIDs
  648. for (buddies_iter = all_buddies.begin(); buddies_iter != all_buddies.end(); ++buddies_iter)
  649. {
  650. buddies_uuids.push_back(buddies_iter->first);
  651. }
  652. if (buddies_uuids.size() > 0)
  653. {
  654. lldebugs << "Friends added to the list: " << buddies_uuids.size() << llendl;
  655. all_friendsp = buddies_uuids;
  656. }
  657. else
  658. {
  659. lldebugs << "No friends found" << llendl;
  660. }
  661. LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin();
  662. for (; buddy_it != all_buddies.end(); ++buddy_it)
  663. {
  664. LLUUID buddy_id = buddy_it->first;
  665. if (av_tracker.isBuddyOnline(buddy_id))
  666. online_friendsp.push_back(buddy_id);
  667. }
  668. /*
  669. * Avatarlists will be hidden by showFriendsAccordionsIfNeeded(), if they do not have items.
  670. * But avatarlist can be updated only if it is visible @see LLAvatarList::draw();
  671. * So we need to do force update of lists to avoid inconsistency of data and view of avatarlist.
  672. */
  673. mOnlineFriendList->setDirty(true, !mOnlineFriendList->filterHasMatches());// do force update if list do NOT have items
  674. mAllFriendList->setDirty(true, !mAllFriendList->filterHasMatches());
  675. //update trash and other buttons according to a selected item
  676. updateButtons();
  677. showFriendsAccordionsIfNeeded();
  678. }
  679. void LLPanelPeople::updateNearbyList()
  680. {
  681. if (!mNearbyList)
  682. return;
  683. std::vector<LLVector3d> positions;
  684. LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
  685. mNearbyList->setDirty();
  686. DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs());
  687. LLActiveSpeakerMgr::instance().update(TRUE);
  688. }
  689. void LLPanelPeople::updateRecentList()
  690. {
  691. if (!mRecentList)
  692. return;
  693. LLRecentPeople::instance().get(mRecentList->getIDs());
  694. mRecentList->setDirty();
  695. }
  696. void LLPanelPeople::buttonSetVisible(std::string btn_name, BOOL visible)
  697. {
  698. // To make sure we're referencing the right widget (a child of the button bar).
  699. LLButton* button = getChild<LLView>("button_bar")->getChild<LLButton>(btn_name);
  700. button->setVisible(visible);
  701. }
  702. void LLPanelPeople::buttonSetEnabled(const std::string& btn_name, bool enabled)
  703. {
  704. // To make sure we're referencing the right widget (a child of the button bar).
  705. LLButton* button = getChild<LLView>("button_bar")->getChild<LLButton>(btn_name);
  706. button->setEnabled(enabled);
  707. }
  708. void LLPanelPeople::buttonSetAction(const std::string& btn_name, const commit_signal_t::slot_type& cb)
  709. {
  710. // To make sure we're referencing the right widget (a child of the button bar).
  711. LLButton* button = getChild<LLView>("button_bar")->getChild<LLButton>(btn_name);
  712. button->setClickedCallback(cb);
  713. }
  714. void LLPanelPeople::updateButtons()
  715. {
  716. std::string cur_tab = getActiveTabName();
  717. bool nearby_tab_active = (cur_tab == NEARBY_TAB_NAME);
  718. bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME);
  719. bool group_tab_active = (cur_tab == GROUP_TAB_NAME);
  720. //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME);
  721. LLUUID selected_id;
  722. uuid_vec_t selected_uuids;
  723. getCurrentItemIDs(selected_uuids);
  724. bool item_selected = (selected_uuids.size() == 1);
  725. bool multiple_selected = (selected_uuids.size() >= 1);
  726. buttonSetVisible("group_info_btn", group_tab_active);
  727. buttonSetVisible("chat_btn", group_tab_active);
  728. buttonSetVisible("view_profile_btn", !group_tab_active);
  729. buttonSetVisible("im_btn", !group_tab_active);
  730. buttonSetVisible("call_btn", !group_tab_active);
  731. buttonSetVisible("group_call_btn", group_tab_active);
  732. buttonSetVisible("teleport_btn", friends_tab_active);
  733. buttonSetVisible("share_btn", nearby_tab_active || friends_tab_active);
  734. if (group_tab_active)
  735. {
  736. bool cur_group_active = true;
  737. if (item_selected)
  738. {
  739. selected_id = mGroupList->getSelectedUUID();
  740. cur_group_active = (gAgent.getGroupID() == selected_id);
  741. }
  742. LLPanel* groups_panel = mTabContainer->getCurrentPanel();
  743. groups_panel->getChildView("activate_btn")->setEnabled(item_selected && !cur_group_active); // "none" or a non-active group selected
  744. groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull());
  745. }
  746. else
  747. {
  748. bool is_friend = true;
  749. // Check whether selected avatar is our friend.
  750. if (item_selected)
  751. {
  752. selected_id = selected_uuids.front();
  753. is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL;
  754. }
  755. LLPanel* cur_panel = mTabContainer->getCurrentPanel();
  756. if (cur_panel)
  757. {
  758. cur_panel->getChildView("add_friend_btn")->setEnabled(!is_friend);
  759. if (friends_tab_active)
  760. {
  761. cur_panel->getChildView("del_btn")->setEnabled(multiple_selected);
  762. }
  763. }
  764. }
  765. bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled();
  766. buttonSetEnabled("view_profile_btn",item_selected);
  767. buttonSetEnabled("share_btn", item_selected);
  768. buttonSetEnabled("im_btn", multiple_selected); // allow starting the friends conference for multiple selection
  769. buttonSetEnabled("call_btn", multiple_selected && enable_calls);
  770. buttonSetEnabled("teleport_btn", multiple_selected && LLAvatarActions::canOfferTeleport(selected_uuids));
  771. bool none_group_selected = item_selected && selected_id.isNull();
  772. buttonSetEnabled("group_info_btn", !none_group_selected);
  773. buttonSetEnabled("group_call_btn", !none_group_selected && enable_calls);
  774. buttonSetEnabled("chat_btn", !none_group_selected);
  775. }
  776. std::string LLPanelPeople::getActiveTabName() const
  777. {
  778. return mTabContainer->getCurrentPanel()->getName();
  779. }
  780. LLUUID LLPanelPeople::getCurrentItemID() const
  781. {
  782. std::string cur_tab = getActiveTabName();
  783. if (cur_tab == FRIENDS_TAB_NAME) // this tab has two lists
  784. {
  785. LLUUID cur_online_friend;
  786. if ((cur_online_friend = mOnlineFriendList->getSelectedUUID()).notNull())
  787. return cur_online_friend;
  788. return mAllFriendList->getSelectedUUID();
  789. }
  790. if (cur_tab == NEARBY_TAB_NAME)
  791. return mNearbyList->getSelectedUUID();
  792. if (cur_tab == RECENT_TAB_NAME)
  793. return mRecentList->getSelectedUUID();
  794. if (cur_tab == GROUP_TAB_NAME)
  795. return mGroupList->getSelectedUUID();
  796. llassert(0 && "unknown tab selected");
  797. return LLUUID::null;
  798. }
  799. void LLPanelPeople::getCurrentItemIDs(uuid_vec_t& selected_uuids) const
  800. {
  801. std::string cur_tab = getActiveTabName();
  802. if (cur_tab == FRIENDS_TAB_NAME)
  803. {
  804. // friends tab has two lists
  805. mOnlineFriendList->getSelectedUUIDs(selected_uuids);
  806. mAllFriendList->getSelectedUUIDs(selected_uuids);
  807. }
  808. else if (cur_tab == NEARBY_TAB_NAME)
  809. mNearbyList->getSelectedUUIDs(selected_uuids);
  810. else if (cur_tab == RECENT_TAB_NAME)
  811. mRecentList->getSelectedUUIDs(selected_uuids);
  812. else if (cur_tab == GROUP_TAB_NAME)
  813. mGroupList->getSelectedUUIDs(selected_uuids);
  814. else
  815. llassert(0 && "unknown tab selected");
  816. }
  817. void LLPanelPeople::showGroupMenu(LLMenuGL* menu)
  818. {
  819. // Shows the menu at the top of the button bar.
  820. // Calculate its coordinates.
  821. // (assumes that groups panel is the current tab)
  822. LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild<LLPanel>("bottom_panel");
  823. LLPanel* parent_panel = mTabContainer->getCurrentPanel();
  824. menu->arrangeAndClear();
  825. S32 menu_height = menu->getRect().getHeight();
  826. S32 menu_x = -2; // *HACK: compensates HPAD in showPopup()
  827. S32 menu_y = bottom_panel->getRect().mTop + menu_height;
  828. // Actually show the menu.
  829. menu->buildDrawLabels();
  830. menu->updateParent(LLMenuGL::sMenuContainer);
  831. LLMenuGL::showPopup(parent_panel, menu, menu_x, menu_y);
  832. }
  833. void LLPanelPeople::setSortOrder(LLAvatarList* list, ESortOrder order, bool save)
  834. {
  835. switch (order)
  836. {
  837. case E_SORT_BY_NAME:
  838. list->sortByName();
  839. break;
  840. case E_SORT_BY_STATUS:
  841. list->setComparator(&STATUS_COMPARATOR);
  842. list->sort();
  843. break;
  844. case E_SORT_BY_MOST_RECENT:
  845. list->setComparator(&RECENT_COMPARATOR);
  846. list->sort();
  847. break;
  848. case E_SORT_BY_RECENT_SPEAKERS:
  849. list->setComparator(&RECENT_SPEAKER_COMPARATOR);
  850. list->sort();
  851. break;
  852. case E_SORT_BY_DISTANCE:
  853. list->setComparator(&DISTANCE_COMPARATOR);
  854. list->sort();
  855. break;
  856. default:
  857. llwarns << "Unrecognized people sort order for " << list->getName() << llendl;
  858. return;
  859. }
  860. if (save)
  861. {
  862. std::string setting;
  863. if (list == mAllFriendList || list == mOnlineFriendList)
  864. setting = "FriendsSortOrder";
  865. else if (list == mRecentList)
  866. setting = "RecentPeopleSortOrder";
  867. else if (list == mNearbyList)
  868. setting = "NearbyPeopleSortOrder";
  869. if (!setting.empty())
  870. gSavedSettings.setU32(setting, order);
  871. }
  872. }
  873. bool LLPanelPeople::isRealGroup()
  874. {
  875. return getCurrentItemID() != LLUUID::null;
  876. }
  877. void LLPanelPeople::onFilterEdit(const std::string& search_string)
  878. {
  879. mFilterSubStringOrig = search_string;
  880. LLStringUtil::trimHead(mFilterSubStringOrig);
  881. // Searches are case-insensitive
  882. std::string search_upper = mFilterSubStringOrig;
  883. LLStringUtil::toUpper(search_upper);
  884. if (mFilterSubString == search_upper)
  885. return;
  886. mFilterSubString = search_upper;
  887. //store accordion tabs state before any manipulation with accordion tabs
  888. if(!mFilterSubString.empty())
  889. {
  890. notifyChildren(LLSD().with("action","store_state"));
  891. }
  892. // Apply new filter.
  893. mNearbyList->setNameFilter(mFilterSubStringOrig);
  894. mOnlineFriendList->setNameFilter(mFilterSubStringOrig);
  895. mAllFriendList->setNameFilter(mFilterSubStringOrig);
  896. mRecentList->setNameFilter(mFilterSubStringOrig);
  897. mGroupList->setNameFilter(mFilterSubStringOrig);
  898. setAccordionCollapsedByUser("tab_online", false);
  899. setAccordionCollapsedByUser("tab_all", false);
  900. showFriendsAccordionsIfNeeded();
  901. //restore accordion tabs state _after_ all manipulations...
  902. if(mFilterSubString.empty())
  903. {
  904. notifyChildren(LLSD().with("action","restore_state"));
  905. }
  906. }
  907. void LLPanelPeople::onTabSelected(const LLSD& param)
  908. {
  909. std::string tab_name = getChild<LLPanel>(param.asString())->getName();
  910. updateButtons();
  911. showFriendsAccordionsIfNeeded();
  912. if (GROUP_TAB_NAME == tab_name)
  913. mFilterEditor->setLabel(getString("groups_filter_label"));
  914. else
  915. mFilterEditor->setLabel(getString("people_filter_label"));
  916. }
  917. void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl)
  918. {
  919. LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*>(ctrl);
  920. if(!item)
  921. {
  922. return;
  923. }
  924. LLUUID clicked_id = item->getAvatarId();
  925. #if 0 // SJB: Useful for testing, but not currently functional or to spec
  926. LLAvatarActions::showProfile(clicked_id);
  927. #else // spec says open IM window
  928. LLAvatarActions::startIM(clicked_id);
  929. #endif
  930. }
  931. void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list)
  932. {
  933. if (getActiveTabName() == NEARBY_TAB_NAME)
  934. {
  935. uuid_vec_t selected_uuids;
  936. getCurrentItemIDs(selected_uuids);
  937. mMiniMap->setSelected(selected_uuids);
  938. } else
  939. // Make sure only one of the friends lists (online/all) has selection.
  940. if (getActiveTabName() == FRIENDS_TAB_NAME)
  941. {
  942. if (list == mOnlineFriendList)
  943. mAllFriendList->resetSelection(true);
  944. else if (list == mAllFriendList)
  945. mOnlineFriendList->resetSelection(true);
  946. else
  947. llassert(0 && "commit on unknown friends list");
  948. }
  949. updateButtons();
  950. }
  951. void LLPanelPeople::onViewProfileButtonClicked()
  952. {
  953. LLUUID id = getCurrentItemID();
  954. LLAvatarActions::showProfile(id);
  955. }
  956. void LLPanelPeople::onAddFriendButtonClicked()
  957. {
  958. LLUUID id = getCurrentItemID();
  959. if (id.notNull())
  960. {
  961. LLAvatarActions::requestFriendshipDialog(id);
  962. }
  963. }
  964. bool LLPanelPeople::isItemsFreeOfFriends(const uuid_vec_t& uuids)
  965. {
  966. const LLAvatarTracker& av_tracker = LLAvatarTracker::instance();
  967. for ( uuid_vec_t::const_iterator
  968. id = uuids.begin(),
  969. id_end = uuids.end();
  970. id != id_end; ++id )
  971. {
  972. if (av_tracker.isBuddy (*id))
  973. {
  974. return false;
  975. }
  976. }
  977. return true;
  978. }
  979. void LLPanelPeople::onAddFriendWizButtonClicked()
  980. {
  981. // Show add friend wizard.
  982. LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelPeople::onAvatarPicked, _1, _2), FALSE, TRUE);
  983. // Need to disable 'ok' button when friend occurs in selection
  984. if (picker) picker->setOkBtnEnableCb(boost::bind(&LLPanelPeople::isItemsFreeOfFriends, this, _1));
  985. LLFloater* root_floater = gFloaterView->getParentFloater(this);
  986. if (root_floater)
  987. {
  988. root_floater->addDependentFloater(picker);
  989. }
  990. }
  991. void LLPanelPeople::onDeleteFriendButtonClicked()
  992. {
  993. uuid_vec_t selected_uuids;
  994. getCurrentItemIDs(selected_uuids);
  995. if (selected_uuids.size() == 1)
  996. {
  997. LLAvatarActions::removeFriendDialog( selected_uuids.front() );
  998. }
  999. else if (selected_uuids.size() > 1)
  1000. {
  1001. LLAvatarActions::removeFriendsDialog( selected_uuids );
  1002. }
  1003. }
  1004. void LLPanelPeople::onGroupInfoButtonClicked()
  1005. {
  1006. LLGroupActions::show(getCurrentItemID());
  1007. }
  1008. void LLPanelPeople::onChatButtonClicked()
  1009. {
  1010. LLUUID group_id = getCurrentItemID();
  1011. if (group_id.notNull())
  1012. LLGroupActions::startIM(group_id);
  1013. }
  1014. void LLPanelPeople::onImButtonClicked()
  1015. {
  1016. uuid_vec_t selected_uuids;
  1017. getCurrentItemIDs(selected_uuids);
  1018. if ( selected_uuids.size() == 1 )
  1019. {
  1020. // if selected only one person then start up IM
  1021. LLAvatarActions::startIM(selected_uuids.at(0));
  1022. }
  1023. else if ( selected_uuids.size() > 1 )
  1024. {
  1025. // for multiple selection start up friends conference
  1026. LLAvatarActions::startConference(selected_uuids);
  1027. }
  1028. }
  1029. void LLPanelPeople::onActivateButtonClicked()
  1030. {
  1031. LLGroupActions::activate(mGroupList->getSelectedUUID());
  1032. }
  1033. // static
  1034. void LLPanelPeople::onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
  1035. {
  1036. if (!names.empty() && !ids.empty())
  1037. LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName());
  1038. }
  1039. void LLPanelPeople::onGroupPlusButtonClicked()
  1040. {
  1041. if (!gAgent.canJoinGroups())
  1042. {
  1043. LLNotificationsUtil::add("JoinedTooManyGroups");
  1044. return;
  1045. }
  1046. LLMenuGL* plus_menu = (LLMenuGL*)mGroupPlusMenuHandle.get();
  1047. if (!plus_menu)
  1048. return;
  1049. showGroupMenu(plus_menu);
  1050. }
  1051. void LLPanelPeople::onGroupMinusButtonClicked()
  1052. {
  1053. LLUUID group_id = getCurrentItemID();
  1054. if (group_id.notNull())
  1055. LLGroupActions::leave(group_id);
  1056. }
  1057. void LLPanelPeople::onGroupPlusMenuItemClicked(const LLSD& userdata)
  1058. {
  1059. std::string chosen_item = userdata.asString();
  1060. if (chosen_item == "join_group")
  1061. LLGroupActions::search();
  1062. else if (chosen_item == "new_group")
  1063. LLGroupActions::createGroup();
  1064. }
  1065. void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)
  1066. {
  1067. std::string chosen_item = userdata.asString();
  1068. if (chosen_item == "sort_name")
  1069. {
  1070. setSortOrder(mAllFriendList, E_SORT_BY_NAME);
  1071. }
  1072. else if (chosen_item == "sort_status")
  1073. {
  1074. setSortOrder(mAllFriendList, E_SORT_BY_STATUS);
  1075. }
  1076. else if (chosen_item == "view_icons")
  1077. {
  1078. mAllFriendList->toggleIcons();
  1079. mOnlineFriendList->toggleIcons();
  1080. }
  1081. else if (chosen_item == "view_permissions")
  1082. {
  1083. bool show_permissions = !gSavedSettings.getBOOL("FriendsListShowPermissions");
  1084. gSavedSettings.setBOOL("FriendsListShowPermissions", show_permissions);
  1085. mAllFriendList->showPermissions(show_permissions);
  1086. mOnlineFriendList->showPermissions(show_permissions);
  1087. }
  1088. else if (chosen_item == "panel_block_list_sidetray")
  1089. {
  1090. LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD());
  1091. }
  1092. }
  1093. void LLPanelPeople::onGroupsViewSortMenuItemClicked(const LLSD& userdata)
  1094. {
  1095. std::string chosen_item = userdata.asString();
  1096. if (chosen_item == "show_icons")
  1097. {
  1098. mGroupList->toggleIcons();
  1099. }
  1100. }
  1101. void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)
  1102. {
  1103. std::string chosen_item = userdata.asString();
  1104. if (chosen_item == "sort_by_recent_speakers")
  1105. {
  1106. setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS);
  1107. }
  1108. else if (chosen_item == "sort_name")
  1109. {
  1110. setSortOrder(mNearbyList, E_SORT_BY_NAME);
  1111. }
  1112. else if (chosen_item == "view_icons")
  1113. {
  1114. mNearbyList->toggleIcons();
  1115. }
  1116. else if (chosen_item == "sort_distance")
  1117. {
  1118. setSortOrder(mNearbyList, E_SORT_BY_DISTANCE);
  1119. }
  1120. else if (chosen_item == "panel_block_list_sidetray")
  1121. {
  1122. LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD());
  1123. }
  1124. }
  1125. bool LLPanelPeople::onNearbyViewSortMenuItemCheck(const LLSD& userdata)
  1126. {
  1127. std::string item = userdata.asString();
  1128. U32 sort_order = gSavedSettings.getU32("NearbyPeopleSortOrder");
  1129. if (item == "sort_by_recent_speakers")
  1130. return sort_order == E_SORT_BY_RECENT_SPEAKERS;
  1131. if (item == "sort_name")
  1132. return sort_order == E_SORT_BY_NAME;
  1133. if (item == "sort_distance")
  1134. return sort_order == E_SORT_BY_DISTANCE;
  1135. return false;
  1136. }
  1137. void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)
  1138. {
  1139. std::string chosen_item = userdata.asString();
  1140. if (chosen_item == "sort_recent")
  1141. {
  1142. setSortOrder(mRecentList, E_SORT_BY_MOST_RECENT);
  1143. }
  1144. else if (chosen_item == "sort_name")
  1145. {
  1146. setSortOrder(mRecentList, E_SORT_BY_NAME);
  1147. }
  1148. else if (chosen_item == "view_icons")
  1149. {
  1150. mRecentList->toggleIcons();
  1151. }
  1152. else if (chosen_item == "panel_block_list_sidetray")
  1153. {
  1154. LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD());
  1155. }
  1156. }
  1157. bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata)
  1158. {
  1159. std::string item = userdata.asString();
  1160. U32 sort_order = gSavedSettings.getU32("FriendsSortOrder");
  1161. if (item == "sort_name")
  1162. return sort_order == E_SORT_BY_NAME;
  1163. if (item == "sort_status")
  1164. return sort_order == E_SORT_BY_STATUS;
  1165. return false;
  1166. }
  1167. bool LLPanelPeople::onRecentViewSortMenuItemCheck(const LLSD& userdata)
  1168. {
  1169. std::string item = userdata.asString();
  1170. U32 sort_order = gSavedSettings.getU32("RecentPeopleSortOrder");
  1171. if (item == "sort_recent")
  1172. return sort_order == E_SORT_BY_MOST_RECENT;
  1173. if (item == "sort_name")
  1174. return sort_order == E_SORT_BY_NAME;
  1175. return false;
  1176. }
  1177. void LLPanelPeople::onCallButtonClicked()
  1178. {
  1179. uuid_vec_t selected_uuids;
  1180. getCurrentItemIDs(selected_uuids);
  1181. if (selected_uuids.size() == 1)
  1182. {
  1183. // initiate a P2P voice chat with the selected user
  1184. LLAvatarActions::startCall(getCurrentItemID());
  1185. }
  1186. else if (selected_uuids.size() > 1)
  1187. {
  1188. // initiate an ad-hoc voice chat with multiple users
  1189. LLAvatarActions::startAdhocCall(selected_uuids);
  1190. }
  1191. }
  1192. void LLPanelPeople::onGroupCallButtonClicked()
  1193. {
  1194. LLGroupActions::startCall(getCurrentItemID());
  1195. }
  1196. void LLPanelPeople::onTeleportButtonClicked()
  1197. {
  1198. uuid_vec_t selected_uuids;
  1199. getCurrentItemIDs(selected_uuids);
  1200. LLAvatarActions::offerTeleport(selected_uuids);
  1201. }
  1202. void LLPanelPeople::onShareButtonClicked()
  1203. {
  1204. LLAvatarActions::share(getCurrentItemID());
  1205. }
  1206. void LLPanelPeople::onMoreButtonClicked()
  1207. {
  1208. // *TODO: not implemented yet
  1209. }
  1210. void LLPanelPeople::onOpen(const LLSD& key)
  1211. {
  1212. std::string tab_name = key["people_panel_tab_name"];
  1213. if (!tab_name.empty())
  1214. mTabContainer->selectTabByName(tab_name);
  1215. }
  1216. bool LLPanelPeople::notifyChildren(const LLSD& info)
  1217. {
  1218. if (info.has("task-panel-action") && info["task-panel-action"].asString() == "handle-tri-state")
  1219. {
  1220. LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(getParent());
  1221. if (!container)
  1222. {
  1223. llwarns << "Cannot find People panel container" << llendl;
  1224. return true;
  1225. }
  1226. if (container->getCurrentPanelIndex() > 0)
  1227. {
  1228. // if not on the default panel, switch to it
  1229. container->onOpen(LLSD().with(LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME, getName()));
  1230. }
  1231. else
  1232. LLFloaterReg::hideInstance("people");
  1233. return true; // this notification is only supposed to be handled by task panels
  1234. }
  1235. return LLPanel::notifyChildren(info);
  1236. }
  1237. void LLPanelPeople::showAccordion(const std::string name, bool show)
  1238. {
  1239. if(name.empty())
  1240. {
  1241. llwarns << "No name provided" << llendl;
  1242. return;
  1243. }
  1244. LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(name);
  1245. tab->setVisible(show);
  1246. if(show)
  1247. {
  1248. // don't expand accordion if it was collapsed by user
  1249. if(!isAccordionCollapsedByUser(tab))
  1250. {
  1251. // expand accordion
  1252. tab->changeOpenClose(false);
  1253. }
  1254. }
  1255. }
  1256. void LLPanelPeople::showFriendsAccordionsIfNeeded()
  1257. {
  1258. if(FRIENDS_TAB_NAME == getActiveTabName())
  1259. {
  1260. // Expand and show accordions if needed, else - hide them
  1261. showAccordion("tab_online", mOnlineFriendList->filterHasMatches());
  1262. showAccordion("tab_all", mAllFriendList->filterHasMatches());
  1263. // Rearrange accordions
  1264. LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("friends_accordion");
  1265. accordion->arrange();
  1266. // *TODO: new no_matched_tabs_text attribute was implemented in accordion (EXT-7368).
  1267. // this code should be refactored to use it
  1268. // keep help text in a synchronization with accordions visibility.
  1269. updateFriendListHelpText();
  1270. }
  1271. }
  1272. void LLPanelPeople::onFriendListRefreshComplete(LLUICtrl*ctrl, const LLSD& param)
  1273. {
  1274. if(ctrl == mOnlineFriendList)
  1275. {
  1276. showAccordion("tab_online", param.asInteger());
  1277. }
  1278. else if(ctrl == mAllFriendList)
  1279. {
  1280. showAccordion("tab_all", param.asInteger());
  1281. }
  1282. }
  1283. void LLPanelPeople::setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed)
  1284. {
  1285. if(!acc_tab)
  1286. {
  1287. llwarns << "Invalid parameter" << llendl;
  1288. return;
  1289. }
  1290. LLSD param = acc_tab->getValue();
  1291. param[COLLAPSED_BY_USER] = collapsed;
  1292. acc_tab->setValue(param);
  1293. }
  1294. void LLPanelPeople::setAccordionCollapsedByUser(const std::string& name, bool collapsed)
  1295. {
  1296. setAccordionCollapsedByUser(getChild<LLUICtrl>(name), collapsed);
  1297. }
  1298. bool LLPanelPeople::isAccordionCollapsedByUser(LLUICtrl* acc_tab)
  1299. {
  1300. if(!acc_tab)
  1301. {
  1302. llwarns << "Invalid parameter" << llendl;
  1303. return false;
  1304. }
  1305. LLSD param = acc_tab->getValue();
  1306. if(!param.has(COLLAPSED_BY_USER))
  1307. {
  1308. return false;
  1309. }
  1310. return param[COLLAPSED_BY_USER].asBoolean();
  1311. }
  1312. bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name)
  1313. {
  1314. return isAccordionCollapsedByUser(getChild<LLUICtrl>(name));
  1315. }
  1316. // EOF