llpanelgroupbulk.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /**
  2. * @file llpanelgroupbulk.cpp
  3. * @brief Implementation of llpanelgroupbulk
  4. * @author [email protected]
  5. *
  6. * $LicenseInfo:firstyear=2006&license=viewergpl$
  7. *
  8. * Copyright (c) 2006-2009, Linden Research, Inc.
  9. *
  10. * Second Life Viewer Source Code
  11. * The source code in this file ("Source Code") is provided by Linden Lab
  12. * to you under the terms of the GNU General Public License, version 2.0
  13. * ("GPL"), unless you have obtained a separate licensing agreement
  14. * ("Other License"), formally executed by you and Linden Lab. Terms of
  15. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17. *
  18. * There are special exceptions to the terms and conditions of the GPL as
  19. * it is applied to this Source Code. View the full text of the exception
  20. * in the file doc/FLOSS-exception.txt in this software distribution, or
  21. * online at
  22. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23. *
  24. * By copying, modifying or distributing this software, you acknowledge
  25. * that you have read and understood your obligations described above,
  26. * and agree to abide by those obligations.
  27. *
  28. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30. * COMPLETENESS OR PERFORMANCE.
  31. * $/LicenseInfo$
  32. */
  33. #include "llviewerprecompiledheaders.h"
  34. #include "llpanelgroupbulk.h"
  35. #include "llavatarnamecache.h"
  36. #include "llbutton.h"
  37. #include "llcombobox.h"
  38. #include "llnamelistctrl.h"
  39. #include "llnotifications.h"
  40. #include "llscrolllistctrl.h"
  41. #include "lltextbox.h"
  42. #include "lluictrlfactory.h"
  43. #include "llagent.h"
  44. #include "llavatartracker.h"
  45. #include "llfloateravatarpicker.h"
  46. #include "llgroupmgr.h"
  47. #include "llviewerobjectlist.h"
  48. static fast_hset<LLPanelGroupBulkImpl*> sImplList;
  49. //////////////////////////////////////////////////////////////////////////
  50. // LLPanelGroupBulkImpl
  51. //////////////////////////////////////////////////////////////////////////
  52. LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id,
  53. LLFloater* parent)
  54. : mGroupID(group_id),
  55. mParentFloater(parent),
  56. mBulkAgentList(NULL),
  57. mOKButton(NULL),
  58. mRemoveButton(NULL),
  59. mGroupName(NULL),
  60. mLoadingText(),
  61. mTooManySelected(),
  62. mRoleNames(NULL),
  63. mOwnerWarning(),
  64. mAlreadyInGroup(),
  65. mConfirmedOwnerInvite(false),
  66. mListFullNotificationSent(false)
  67. {
  68. sImplList.insert(this);
  69. }
  70. LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl()
  71. {
  72. sImplList.erase(this);
  73. }
  74. //static
  75. void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata)
  76. {
  77. LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)userdata;
  78. if (panelp && panelp->mImplementation)
  79. {
  80. LLFloaterAvatarPicker* picker;
  81. picker = LLFloaterAvatarPicker::show(callbackAddUsers,
  82. panelp->mImplementation,
  83. true, false);
  84. if (picker && gFloaterViewp)
  85. {
  86. LLFloater* parentp = gFloaterViewp->getParentFloater(panelp);
  87. if (parentp)
  88. {
  89. parentp->addDependentFloater(picker);
  90. }
  91. }
  92. gGroupMgr.sendCapGroupMembersRequest(panelp->mImplementation->mGroupID);
  93. }
  94. }
  95. //static
  96. void LLPanelGroupBulkImpl::callbackClickRemove(void* userdata)
  97. {
  98. LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata;
  99. if (selfp)
  100. {
  101. selfp->handleRemove();
  102. }
  103. }
  104. //static
  105. void LLPanelGroupBulkImpl::callbackClickCancel(void* userdata)
  106. {
  107. LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata;
  108. if (selfp && selfp->mParentFloater)
  109. {
  110. selfp->mParentFloater->close();
  111. }
  112. }
  113. //static
  114. void LLPanelGroupBulkImpl::callbackSelect(LLUICtrl* ctrl, void* userdata)
  115. {
  116. LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata;
  117. if (selfp)
  118. {
  119. selfp->handleSelection();
  120. }
  121. }
  122. //static
  123. void LLPanelGroupBulkImpl::callbackAddUsers(const std::vector<std::string>&,
  124. const uuid_vec_t& agent_ids,
  125. void* user_data)
  126. {
  127. LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)user_data;
  128. if (!sImplList.count(selfp))
  129. {
  130. return;
  131. }
  132. std::vector<std::string> names;
  133. for (S32 i = 0, count = agent_ids.size(); i < count; ++i)
  134. {
  135. LLAvatarName av_name;
  136. if (LLAvatarNameCache::get(agent_ids[i], &av_name))
  137. {
  138. onAvatarNameCache(agent_ids[i], av_name, selfp);
  139. }
  140. else
  141. {
  142. // *TODO : Add a callback per avatar name being fetched.
  143. LLAvatarNameCache::get(agent_ids[i],
  144. boost::bind(onAvatarNameCache, _1, _2,
  145. selfp));
  146. }
  147. }
  148. }
  149. //static
  150. void LLPanelGroupBulkImpl::onAvatarNameCache(const LLUUID& agent_id,
  151. const LLAvatarName& av_name,
  152. void* user_data)
  153. {
  154. LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)user_data;
  155. if (sImplList.count(selfp))
  156. {
  157. std::vector<std::string> names;
  158. uuid_vec_t agent_ids;
  159. agent_ids.emplace_back(agent_id);
  160. names.emplace_back(av_name.getCompleteName());
  161. selfp->addUsers(names, agent_ids);
  162. }
  163. }
  164. void LLPanelGroupBulkImpl::handleRemove()
  165. {
  166. if (!mBulkAgentList) return;
  167. std::vector<LLScrollListItem*> selection = mBulkAgentList->getAllSelected();
  168. if (selection.empty())
  169. {
  170. return;
  171. }
  172. for (std::vector<LLScrollListItem*>::iterator iter = selection.begin(),
  173. end = selection.end();
  174. iter != end; ++iter)
  175. {
  176. mInviteeIDs.erase((*iter)->getUUID());
  177. }
  178. mBulkAgentList->deleteSelectedItems();
  179. if (mRemoveButton)
  180. {
  181. mRemoveButton->setEnabled(false);
  182. }
  183. if (mOKButton && mOKButton->getEnabled() && mBulkAgentList->isEmpty())
  184. {
  185. mOKButton->setEnabled(false);
  186. }
  187. }
  188. void LLPanelGroupBulkImpl::handleSelection()
  189. {
  190. if (!mBulkAgentList) return;
  191. std::vector<LLScrollListItem*> selection = mBulkAgentList->getAllSelected();
  192. if (mRemoveButton)
  193. {
  194. mRemoveButton->setEnabled(!selection.empty());
  195. }
  196. }
  197. void LLPanelGroupBulkImpl::addUsers(const std::vector<std::string>& names,
  198. const uuid_vec_t& agent_ids)
  199. {
  200. if (mListFullNotificationSent || !mBulkAgentList)
  201. {
  202. return;
  203. }
  204. if (!mListFullNotificationSent &&
  205. (S32)(names.size() + mInviteeIDs.size()) > MAX_GROUP_INVITES)
  206. {
  207. mListFullNotificationSent = true;
  208. // Fail ! Show a warning and don't add any names.
  209. LLSD msg;
  210. msg["MESSAGE"] = mTooManySelected;
  211. gNotifications.add("GenericAlert", msg);
  212. return;
  213. }
  214. for (S32 i = 0, count = names.size(); i < count; ++i)
  215. {
  216. const LLUUID& id = agent_ids[i];
  217. if (mInviteeIDs.count(id))
  218. {
  219. continue;
  220. }
  221. // add the name to the names list
  222. LLSD row;
  223. row["id"] = id;
  224. row["columns"][0]["value"] = names[i];
  225. mBulkAgentList->addElement(row);
  226. mInviteeIDs.emplace(id);
  227. // We've successfully added someone to the list.
  228. if (mOKButton && !mOKButton->getEnabled())
  229. {
  230. mOKButton->setEnabled(true);
  231. }
  232. }
  233. }
  234. void LLPanelGroupBulkImpl::setGroupName(std::string name)
  235. {
  236. if (mGroupName)
  237. {
  238. mGroupName->setText(name);
  239. }
  240. }
  241. //////////////////////////////////////////////////////////////////////////
  242. // LLPanelGroupBulk
  243. //////////////////////////////////////////////////////////////////////////
  244. LLPanelGroupBulk::LLPanelGroupBulk(const LLUUID& group_id, LLFloater* parent)
  245. : LLPanel(),
  246. mImplementation(new LLPanelGroupBulkImpl(group_id, parent)),
  247. mPendingGroupPropertiesUpdate(false),
  248. mPendingRoleDataUpdate(false),
  249. mPendingMemberDataUpdate(false)
  250. {
  251. }
  252. LLPanelGroupBulk::~LLPanelGroupBulk()
  253. {
  254. if (mImplementation)
  255. {
  256. delete mImplementation;
  257. mImplementation = NULL;
  258. }
  259. }
  260. void LLPanelGroupBulk::clear()
  261. {
  262. mImplementation->mInviteeIDs.clear();
  263. if (mImplementation->mBulkAgentList)
  264. {
  265. mImplementation->mBulkAgentList->deleteAllItems();
  266. }
  267. if (mImplementation->mOKButton)
  268. {
  269. mImplementation->mOKButton->setEnabled(false);
  270. }
  271. }
  272. void LLPanelGroupBulk::update()
  273. {
  274. updateGroupName();
  275. updateGroupData();
  276. }
  277. void LLPanelGroupBulk::draw()
  278. {
  279. LLPanel::draw();
  280. update();
  281. }
  282. void LLPanelGroupBulk::updateGroupName()
  283. {
  284. LLGroupMgrGroupData* gdatap =
  285. gGroupMgr.getGroupData(mImplementation->mGroupID);
  286. if (gdatap && gdatap->isGroupPropertiesDataComplete())
  287. {
  288. // Only do work if the current group name differs
  289. if (mImplementation->mGroupName &&
  290. mImplementation->mGroupName->getText().compare(gdatap->mName) != 0)
  291. {
  292. mImplementation->setGroupName(gdatap->mName);
  293. }
  294. }
  295. else
  296. {
  297. mImplementation->setGroupName(mImplementation->mLoadingText);
  298. }
  299. }
  300. void LLPanelGroupBulk::updateGroupData()
  301. {
  302. LLGroupMgrGroupData* gdatap =
  303. gGroupMgr.getGroupData(mImplementation->mGroupID);
  304. if (gdatap && gdatap->isGroupPropertiesDataComplete())
  305. {
  306. mPendingGroupPropertiesUpdate = false;
  307. }
  308. else if (!mPendingGroupPropertiesUpdate)
  309. {
  310. mPendingGroupPropertiesUpdate = true;
  311. gGroupMgr.sendGroupPropertiesRequest(mImplementation->mGroupID);
  312. }
  313. if (gdatap && gdatap->isRoleDataComplete())
  314. {
  315. mPendingRoleDataUpdate = false;
  316. }
  317. else if (!mPendingRoleDataUpdate)
  318. {
  319. mPendingRoleDataUpdate = true;
  320. gGroupMgr.sendGroupRoleDataRequest(mImplementation->mGroupID);
  321. }
  322. if (gdatap && gdatap->isMemberDataComplete())
  323. {
  324. mPendingMemberDataUpdate = false;
  325. }
  326. else if (!mPendingMemberDataUpdate)
  327. {
  328. mPendingMemberDataUpdate = true;
  329. gGroupMgr.sendCapGroupMembersRequest(mImplementation->mGroupID);
  330. }
  331. }
  332. void LLPanelGroupBulk::addUserCallback(const LLUUID& id,
  333. const LLAvatarName& av_name)
  334. {
  335. std::vector<std::string> names;
  336. uuid_vec_t agent_ids;
  337. agent_ids.emplace_back(id);
  338. names.emplace_back(av_name.getLegacyName());
  339. mImplementation->addUsers(names, agent_ids);
  340. }
  341. void LLPanelGroupBulk::addUsers(uuid_vec_t& agent_ids)
  342. {
  343. std::vector<std::string> names;
  344. for (S32 i = 0, count = agent_ids.size(); i < count; ++i)
  345. {
  346. std::string fullname;
  347. LLUUID agent_id = agent_ids[i];
  348. LLViewerObject* dest = gObjectList.findObject(agent_id);
  349. if (dest && dest->isAvatar())
  350. {
  351. LLNameValue* nvfirst = dest->getNVPair("FirstName");
  352. LLNameValue* nvlast = dest->getNVPair("LastName");
  353. if (nvfirst && nvlast)
  354. {
  355. fullname = LLCacheName::buildFullName(nvfirst->getString(),
  356. nvlast->getString());
  357. }
  358. if (!fullname.empty())
  359. {
  360. names.emplace_back(fullname);
  361. }
  362. else
  363. {
  364. llwarns << "Selected avatar has no name: " << dest->getID()
  365. << llendl;
  366. names.emplace_back("(Unknown)");
  367. }
  368. }
  369. else
  370. {
  371. // It looks like the user tries to invite offline friend; for
  372. // offline avatar_id gObjectList.findObject() will return null so
  373. // we need to do this additional search in avatar tracker, see
  374. // EXT-4732
  375. if (LLAvatarTracker::isAgentFriend(agent_id))
  376. {
  377. LLAvatarName av_name;
  378. if (!LLAvatarNameCache::get(agent_id, &av_name))
  379. {
  380. // actually it should happen, just in case
  381. LLAvatarNameCache::get(LLUUID(agent_id),
  382. boost::bind(&LLPanelGroupBulk::addUserCallback,
  383. this, _1, _2));
  384. // For this special case !
  385. // When there is no cached name we should remove resident
  386. // from agent_ids list to avoid breaking of sequence
  387. // removed id will be added in callback.
  388. agent_ids.erase(agent_ids.begin() + i);
  389. }
  390. else
  391. {
  392. names.emplace_back(av_name.getLegacyName());
  393. }
  394. }
  395. }
  396. }
  397. mImplementation->mListFullNotificationSent = false;
  398. mImplementation->addUsers(names, agent_ids);
  399. }