PageRenderTime 43ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llpanelgroupinvite.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 630 lines | 475 code | 83 blank | 72 comment | 68 complexity | f8ba63665936d78aaf9412887dca6ff9 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llpanelgroupinvite.cpp
  3. *
  4. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "llviewerprecompiledheaders.h"
  26. #include "llpanelgroupinvite.h"
  27. #include "llagent.h"
  28. #include "llavatarnamecache.h"
  29. #include "llfloateravatarpicker.h"
  30. #include "llbutton.h"
  31. #include "llcallingcard.h"
  32. #include "llcombobox.h"
  33. #include "llgroupactions.h"
  34. #include "llgroupmgr.h"
  35. #include "llnamelistctrl.h"
  36. #include "llnotificationsutil.h"
  37. #include "llscrolllistitem.h"
  38. #include "llspinctrl.h"
  39. #include "lltextbox.h"
  40. #include "llviewerobject.h"
  41. #include "llviewerobjectlist.h"
  42. #include "lluictrlfactory.h"
  43. #include "llviewerwindow.h"
  44. class LLPanelGroupInvite::impl
  45. {
  46. public:
  47. impl(const LLUUID& group_id);
  48. ~impl();
  49. void addUsers(const std::vector<std::string>& names,
  50. const uuid_vec_t& agent_ids);
  51. void submitInvitations();
  52. void addRoleNames(LLGroupMgrGroupData* gdatap);
  53. void handleRemove();
  54. void handleSelection();
  55. static void callbackClickCancel(void* userdata);
  56. static void callbackClickOK(void* userdata);
  57. static void callbackClickAdd(void* userdata);
  58. static void callbackClickRemove(void* userdata);
  59. static void callbackSelect(LLUICtrl* ctrl, void* userdata);
  60. static void callbackAddUsers(const uuid_vec_t& agent_ids,
  61. void* user_data);
  62. static void onAvatarNameCache(const LLUUID& agent_id,
  63. const LLAvatarName& av_name,
  64. void* user_data);
  65. bool inviteOwnerCallback(const LLSD& notification, const LLSD& response);
  66. public:
  67. LLUUID mGroupID;
  68. std::string mLoadingText;
  69. LLNameListCtrl *mInvitees;
  70. LLComboBox *mRoleNames;
  71. LLButton *mOKButton;
  72. LLButton *mRemoveButton;
  73. LLTextBox *mGroupName;
  74. std::string mOwnerWarning;
  75. std::string mAlreadyInGroup;
  76. bool mConfirmedOwnerInvite;
  77. void (*mCloseCallback)(void* data);
  78. void* mCloseCallbackUserData;
  79. };
  80. LLPanelGroupInvite::impl::impl(const LLUUID& group_id):
  81. mGroupID( group_id ),
  82. mLoadingText (),
  83. mInvitees ( NULL ),
  84. mRoleNames( NULL ),
  85. mOKButton ( NULL ),
  86. mRemoveButton( NULL ),
  87. mGroupName( NULL ),
  88. mConfirmedOwnerInvite( false ),
  89. mCloseCallback( NULL ),
  90. mCloseCallbackUserData( NULL )
  91. {
  92. }
  93. LLPanelGroupInvite::impl::~impl()
  94. {
  95. }
  96. void LLPanelGroupInvite::impl::addUsers(const std::vector<std::string>& names,
  97. const uuid_vec_t& agent_ids)
  98. {
  99. std::string name;
  100. LLUUID id;
  101. for (S32 i = 0; i < (S32)names.size(); i++)
  102. {
  103. name = names[i];
  104. id = agent_ids[i];
  105. // Make sure this agent isn't already in the list.
  106. bool already_in_list = false;
  107. std::vector<LLScrollListItem*> items = mInvitees->getAllData();
  108. for (std::vector<LLScrollListItem*>::iterator iter = items.begin();
  109. iter != items.end(); ++iter)
  110. {
  111. LLScrollListItem* item = *iter;
  112. if (item->getUUID() == id)
  113. {
  114. already_in_list = true;
  115. break;
  116. }
  117. }
  118. if (already_in_list)
  119. {
  120. continue;
  121. }
  122. //add the name to the names list
  123. LLSD row;
  124. row["id"] = id;
  125. row["columns"][0]["value"] = name;
  126. mInvitees->addElement(row);
  127. }
  128. }
  129. void LLPanelGroupInvite::impl::submitInvitations()
  130. {
  131. std::map<LLUUID, LLUUID> role_member_pairs;
  132. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
  133. // Default to everyone role.
  134. LLUUID role_id = LLUUID::null;
  135. if (mRoleNames)
  136. {
  137. role_id = mRoleNames->getCurrentID();
  138. // owner role: display confirmation and wait for callback
  139. if ((role_id == gdatap->mOwnerRole) && (!mConfirmedOwnerInvite))
  140. {
  141. LLSD args;
  142. args["MESSAGE"] = mOwnerWarning;
  143. LLNotificationsUtil::add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupInvite::impl::inviteOwnerCallback, this, _1, _2));
  144. return; // we'll be called again if user confirms
  145. }
  146. }
  147. bool already_in_group = false;
  148. //loop over the users
  149. std::vector<LLScrollListItem*> items = mInvitees->getAllData();
  150. for (std::vector<LLScrollListItem*>::iterator iter = items.begin();
  151. iter != items.end(); ++iter)
  152. {
  153. LLScrollListItem* item = *iter;
  154. if(LLGroupActions::isAvatarMemberOfGroup(mGroupID, item->getUUID()))
  155. {
  156. already_in_group = true;
  157. continue;
  158. }
  159. role_member_pairs[item->getUUID()] = role_id;
  160. }
  161. LLGroupMgr::getInstance()->sendGroupMemberInvites(mGroupID, role_member_pairs);
  162. if(already_in_group)
  163. {
  164. LLSD msg;
  165. msg["MESSAGE"] = mAlreadyInGroup;
  166. LLNotificationsUtil::add("GenericAlert", msg);
  167. }
  168. //then close
  169. (*mCloseCallback)(mCloseCallbackUserData);
  170. }
  171. bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification, const LLSD& response)
  172. {
  173. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  174. switch(option)
  175. {
  176. case 0:
  177. // user confirmed that they really want a new group owner
  178. mConfirmedOwnerInvite = true;
  179. submitInvitations();
  180. break;
  181. case 1:
  182. // fall through
  183. default:
  184. break;
  185. }
  186. return false;
  187. }
  188. void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
  189. {
  190. LLGroupMgrGroupData::member_list_t::iterator agent_iter =
  191. gdatap->mMembers.find(gAgent.getID());
  192. //get the member data for the agent if it exists
  193. if ( agent_iter != gdatap->mMembers.end() )
  194. {
  195. LLGroupMemberData* member_data = (*agent_iter).second;
  196. //loop over the agent's roles in the group
  197. //then add those roles to the list of roles that the agent
  198. //can invite people to be
  199. if ( member_data && mRoleNames)
  200. {
  201. //if the user is the owner then we add
  202. //all of the roles in the group
  203. //else if they have the add to roles power
  204. //we add every role but owner,
  205. //else if they have the limited add to roles power
  206. //we add every role the user is in
  207. //else we just add to everyone
  208. bool is_owner = member_data->isInRole(gdatap->mOwnerRole);
  209. bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
  210. GP_ROLE_ASSIGN_MEMBER);
  211. bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
  212. GP_ROLE_ASSIGN_MEMBER_LIMITED);
  213. LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
  214. LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
  215. //populate the role list
  216. for ( ; rit != end; ++rit)
  217. {
  218. LLUUID role_id = (*rit).first;
  219. LLRoleData rd;
  220. if ( gdatap->getRoleData(role_id,rd) )
  221. {
  222. // Owners can add any role.
  223. if ( is_owner
  224. // Even 'can_assign_any' can't add owner role.
  225. || (can_assign_any && role_id != gdatap->mOwnerRole)
  226. // Add all roles user is in
  227. || (can_assign_limited && member_data->isInRole(role_id))
  228. // Everyone role.
  229. || role_id == LLUUID::null )
  230. {
  231. mRoleNames->add(rd.mRoleName,
  232. role_id,
  233. ADD_BOTTOM);
  234. }
  235. }
  236. }
  237. }//end if member data is not null
  238. }//end if agent is in the group
  239. }
  240. //static
  241. void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata)
  242. {
  243. LLPanelGroupInvite* panelp = (LLPanelGroupInvite*) userdata;
  244. if ( panelp )
  245. {
  246. //Right now this is hard coded with some knowledge that it is part
  247. //of a floater since the avatar picker needs to be added as a dependent
  248. //floater to the parent floater.
  249. //Soon the avatar picker will be embedded into this panel
  250. //instead of being it's own separate floater. But that is next week.
  251. //This will do for now. -jwolk May 10, 2006
  252. LLFloater* parentp;
  253. parentp = gFloaterView->getParentFloater(panelp);
  254. parentp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(impl::callbackAddUsers, _1,
  255. panelp->mImplementation),
  256. TRUE));
  257. }
  258. }
  259. //static
  260. void LLPanelGroupInvite::impl::callbackClickRemove(void* userdata)
  261. {
  262. impl* selfp = (impl*) userdata;
  263. if ( selfp ) selfp->handleRemove();
  264. }
  265. void LLPanelGroupInvite::impl::handleRemove()
  266. {
  267. // Check if there is anything selected.
  268. std::vector<LLScrollListItem*> selection =
  269. mInvitees->getAllSelected();
  270. if (selection.empty()) return;
  271. // Remove all selected invitees.
  272. mInvitees->deleteSelectedItems();
  273. mRemoveButton->setEnabled(FALSE);
  274. }
  275. // static
  276. void LLPanelGroupInvite::impl::callbackSelect(
  277. LLUICtrl* ctrl, void* userdata)
  278. {
  279. impl* selfp = (impl*) userdata;
  280. if ( selfp ) selfp->handleSelection();
  281. }
  282. void LLPanelGroupInvite::impl::handleSelection()
  283. {
  284. // Check if there is anything selected.
  285. std::vector<LLScrollListItem*> selection =
  286. mInvitees->getAllSelected();
  287. if (selection.empty())
  288. {
  289. mRemoveButton->setEnabled(FALSE);
  290. }
  291. else
  292. {
  293. mRemoveButton->setEnabled(TRUE);
  294. }
  295. }
  296. void LLPanelGroupInvite::impl::callbackClickCancel(void* userdata)
  297. {
  298. impl* selfp = (impl*) userdata;
  299. if ( selfp )
  300. {
  301. (*(selfp->mCloseCallback))(selfp->mCloseCallbackUserData);
  302. }
  303. }
  304. void LLPanelGroupInvite::impl::callbackClickOK(void* userdata)
  305. {
  306. impl* selfp = (impl*) userdata;
  307. if ( selfp ) selfp->submitInvitations();
  308. }
  309. //static
  310. void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data)
  311. {
  312. std::vector<std::string> names;
  313. for (S32 i = 0; i < (S32)agent_ids.size(); i++)
  314. {
  315. LLAvatarNameCache::get(agent_ids[i],
  316. boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, _1, _2, user_data));
  317. }
  318. }
  319. void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id,
  320. const LLAvatarName& av_name,
  321. void* user_data)
  322. {
  323. impl* selfp = (impl*) user_data;
  324. if (selfp)
  325. {
  326. std::vector<std::string> names;
  327. uuid_vec_t agent_ids;
  328. agent_ids.push_back(agent_id);
  329. names.push_back(av_name.getCompleteName());
  330. selfp->addUsers(names, agent_ids);
  331. }
  332. }
  333. LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id)
  334. : LLPanel(),
  335. mImplementation(new impl(group_id)),
  336. mPendingUpdate(FALSE)
  337. {
  338. // Pass on construction of this panel to the control factory.
  339. buildFromFile( "panel_group_invite.xml");
  340. }
  341. LLPanelGroupInvite::~LLPanelGroupInvite()
  342. {
  343. delete mImplementation;
  344. }
  345. void LLPanelGroupInvite::setCloseCallback(void (*close_callback)(void*),
  346. void* data)
  347. {
  348. mImplementation->mCloseCallback = close_callback;
  349. mImplementation->mCloseCallbackUserData = data;
  350. }
  351. void LLPanelGroupInvite::clear()
  352. {
  353. mStoreSelected = LLUUID::null;
  354. mImplementation->mInvitees->deleteAllItems();
  355. mImplementation->mRoleNames->clear();
  356. mImplementation->mRoleNames->removeall();
  357. mImplementation->mOKButton->setEnabled(FALSE);
  358. }
  359. void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
  360. {
  361. std::vector<std::string> names;
  362. for (S32 i = 0; i < (S32)agent_ids.size(); i++)
  363. {
  364. std::string fullname;
  365. LLUUID agent_id = agent_ids[i];
  366. LLViewerObject* dest = gObjectList.findObject(agent_id);
  367. if(dest && dest->isAvatar())
  368. {
  369. LLNameValue* nvfirst = dest->getNVPair("FirstName");
  370. LLNameValue* nvlast = dest->getNVPair("LastName");
  371. if(nvfirst && nvlast)
  372. {
  373. fullname = LLCacheName::buildFullName(
  374. nvfirst->getString(), nvlast->getString());
  375. }
  376. if (!fullname.empty())
  377. {
  378. names.push_back(fullname);
  379. }
  380. else
  381. {
  382. llwarns << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << llendl;
  383. names.push_back("(Unknown)");
  384. }
  385. }
  386. else
  387. {
  388. //looks like user try to invite offline friend
  389. //for offline avatar_id gObjectList.findObject() will return null
  390. //so we need to do this additional search in avatar tracker, see EXT-4732
  391. if (LLAvatarTracker::instance().isBuddy(agent_id))
  392. {
  393. if (!gCacheName->getFullName(agent_id, fullname))
  394. {
  395. // actually it should happen, just in case
  396. gCacheName->get(LLUUID(agent_id), false, boost::bind(
  397. &LLPanelGroupInvite::addUserCallback, this, _1, _2));
  398. // for this special case!
  399. //when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence
  400. // removed id will be added in callback
  401. agent_ids.erase(agent_ids.begin() + i);
  402. }
  403. else
  404. {
  405. names.push_back(fullname);
  406. }
  407. }
  408. }
  409. }
  410. mImplementation->addUsers(names, agent_ids);
  411. }
  412. void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const std::string& full_name)
  413. {
  414. std::vector<std::string> names;
  415. uuid_vec_t agent_ids;
  416. agent_ids.push_back(id);
  417. names.push_back(full_name);
  418. mImplementation->addUsers(names, agent_ids);
  419. }
  420. void LLPanelGroupInvite::draw()
  421. {
  422. LLPanel::draw();
  423. if (mPendingUpdate)
  424. {
  425. updateLists();
  426. }
  427. }
  428. void LLPanelGroupInvite::update()
  429. {
  430. mPendingUpdate = FALSE;
  431. if (mImplementation->mGroupName)
  432. {
  433. mImplementation->mGroupName->setText(mImplementation->mLoadingText);
  434. }
  435. if ( mImplementation->mRoleNames )
  436. {
  437. mStoreSelected = mImplementation->mRoleNames->getCurrentID();
  438. mImplementation->mRoleNames->clear();
  439. mImplementation->mRoleNames->removeall();
  440. mImplementation->mRoleNames->add(mImplementation->mLoadingText, LLUUID::null, ADD_BOTTOM);
  441. mImplementation->mRoleNames->setCurrentByID(LLUUID::null);
  442. }
  443. updateLists();
  444. }
  445. void LLPanelGroupInvite::updateLists()
  446. {
  447. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
  448. bool waiting = false;
  449. if (gdatap)
  450. {
  451. if (gdatap->isGroupPropertiesDataComplete())
  452. {
  453. if (mImplementation->mGroupName)
  454. {
  455. mImplementation->mGroupName->setText(gdatap->mName);
  456. }
  457. }
  458. else
  459. {
  460. waiting = true;
  461. }
  462. if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete())
  463. {
  464. if ( mImplementation->mRoleNames )
  465. {
  466. mImplementation->mRoleNames->clear();
  467. mImplementation->mRoleNames->removeall();
  468. //add the role names and select the everybody role by default
  469. mImplementation->addRoleNames(gdatap);
  470. mImplementation->mRoleNames->setCurrentByID(mStoreSelected);
  471. }
  472. }
  473. else
  474. {
  475. waiting = true;
  476. }
  477. }
  478. else
  479. {
  480. waiting = true;
  481. }
  482. if (waiting)
  483. {
  484. if (!mPendingUpdate)
  485. {
  486. LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID);
  487. LLGroupMgr::getInstance()->sendGroupMembersRequest(mImplementation->mGroupID);
  488. LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
  489. }
  490. mPendingUpdate = TRUE;
  491. }
  492. else
  493. {
  494. mPendingUpdate = FALSE;
  495. if (mImplementation->mOKButton && mImplementation->mRoleNames->getItemCount())
  496. {
  497. mImplementation->mOKButton->setEnabled(TRUE);
  498. }
  499. }
  500. }
  501. BOOL LLPanelGroupInvite::postBuild()
  502. {
  503. BOOL recurse = TRUE;
  504. mImplementation->mLoadingText = getString("loading");
  505. mImplementation->mRoleNames = getChild<LLComboBox>("role_name",
  506. recurse);
  507. mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse);
  508. mImplementation->mInvitees =
  509. getChild<LLNameListCtrl>("invitee_list", recurse);
  510. if ( mImplementation->mInvitees )
  511. {
  512. mImplementation->mInvitees->setCommitOnSelectionChange(TRUE);
  513. mImplementation->mInvitees->setCommitCallback(impl::callbackSelect, mImplementation);
  514. }
  515. LLButton* button = getChild<LLButton>("add_button", recurse);
  516. if ( button )
  517. {
  518. // default to opening avatarpicker automatically
  519. // (*impl::callbackClickAdd)((void*)this);
  520. button->setClickedCallback(impl::callbackClickAdd, this);
  521. }
  522. mImplementation->mRemoveButton =
  523. getChild<LLButton>("remove_button", recurse);
  524. if ( mImplementation->mRemoveButton )
  525. {
  526. mImplementation->mRemoveButton->setClickedCallback(impl::callbackClickRemove, mImplementation);
  527. mImplementation->mRemoveButton->setEnabled(FALSE);
  528. }
  529. mImplementation->mOKButton =
  530. getChild<LLButton>("ok_button", recurse);
  531. if ( mImplementation->mOKButton )
  532. {
  533. mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation);
  534. mImplementation->mOKButton->setEnabled(FALSE);
  535. }
  536. button = getChild<LLButton>("cancel_button", recurse);
  537. if ( button )
  538. {
  539. button->setClickedCallback(impl::callbackClickCancel, mImplementation);
  540. }
  541. mImplementation->mOwnerWarning = getString("confirm_invite_owner_str");
  542. mImplementation->mAlreadyInGroup = getString("already_in_group");
  543. update();
  544. return (mImplementation->mRoleNames &&
  545. mImplementation->mInvitees &&
  546. mImplementation->mRemoveButton);
  547. }