llpanelgrouproles.cpp 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214
  1. /**
  2. * @file llpanelgrouproles.cpp
  3. * @brief Panel for roles information about a particular group.
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewergpl$
  6. *
  7. * Copyright (c) 2006-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llpanelgrouproles.h"
  34. #include "llbutton.h"
  35. #include "llcheckboxctrl.h"
  36. #include "lliconctrl.h"
  37. #include "lllineeditor.h"
  38. #include "llnamelistctrl.h"
  39. #include "llnotifications.h"
  40. #include "llscrolllistctrl.h"
  41. #include "lltabcontainer.h"
  42. #include "lltextbox.h"
  43. #include "lltexteditor.h"
  44. #include "roles_constants.h"
  45. #include "llagent.h"
  46. #include "llappviewer.h" // For gFrameTimeSeconds
  47. #include "llfloateravatarinfo.h"
  48. #include "llfloatergroupbulkban.h"
  49. #include "llfloatergroupinvite.h"
  50. #include "llviewertexturelist.h"
  51. bool agentCanRemoveFromRole(const LLUUID& group_id,
  52. const LLUUID& role_id)
  53. {
  54. return gAgent.hasPowerInGroup(group_id, GP_ROLE_REMOVE_MEMBER);
  55. }
  56. ////////////////////////////
  57. // LLPanelGroupRoles
  58. ////////////////////////////
  59. //static
  60. void* LLPanelGroupRoles::createTab(void* data)
  61. {
  62. LLUUID* group_id = (LLUUID*)data;
  63. return new LLPanelGroupRoles("panel group roles", *group_id);
  64. }
  65. LLPanelGroupRoles::LLPanelGroupRoles(const std::string& name,
  66. const LLUUID& group_id)
  67. : LLPanelGroupTab(name, group_id),
  68. mCurrentTab(NULL),
  69. mRequestedTab(NULL),
  70. mSubTabContainer(NULL),
  71. mIgnoreTransition(false)
  72. {
  73. }
  74. LLPanelGroupRoles::~LLPanelGroupRoles()
  75. {
  76. if (mSubTabContainer)
  77. {
  78. for (S32 i = 0; i < mSubTabContainer->getTabCount(); ++i)
  79. {
  80. LLPanelGroupSubTab* tabp =
  81. (LLPanelGroupSubTab*)mSubTabContainer->getPanelByIndex(i);
  82. tabp->removeObserver(this);
  83. }
  84. }
  85. }
  86. bool LLPanelGroupRoles::postBuild()
  87. {
  88. mSubTabContainer = getChild<LLTabContainer>("roles_tab_container",
  89. true, false);
  90. if (!mSubTabContainer) return false;
  91. // Hook up each sub-tab callback and widgets.
  92. for (S32 i = 0; i < mSubTabContainer->getTabCount(); ++i)
  93. {
  94. LLPanelGroupSubTab* tabp =
  95. (LLPanelGroupSubTab*)mSubTabContainer->getPanelByIndex(i);
  96. // Add click callbacks to all the tabs.
  97. mSubTabContainer->setTabChangeCallback(tabp, onClickSubTab);
  98. mSubTabContainer->setTabUserData(tabp, this);
  99. // Hand the subtab a pointer to this LLPanelGroupRoles, so that it can
  100. // look around for the widgets it is interested in.
  101. if (!tabp->postBuildSubTab(this)) return false;
  102. tabp->addObserver(this);
  103. }
  104. // Set the current tab to whatever is currently being shown.
  105. mCurrentTab = (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  106. if (!mCurrentTab)
  107. {
  108. // Need to select a tab.
  109. mSubTabContainer->selectFirstTab();
  110. mCurrentTab = (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  111. }
  112. if (!mCurrentTab) return false;
  113. // Act as though this tab was just activated.
  114. mCurrentTab->activate();
  115. // Read apply text from the xml file.
  116. mDefaultNeedsApplyMesg = getString("default_needs_apply_text");
  117. mWantApplyMesg = getString("want_apply_text");
  118. return LLPanelGroupTab::postBuild();
  119. }
  120. bool LLPanelGroupRoles::isVisibleByAgent()
  121. {
  122. #if 0 // This power was removed to make group roles simpler
  123. return agentp && gAgent.hasPowerInGroup(mGroupID,
  124. GP_ROLE_CREATE |
  125. GP_ROLE_DELETE |
  126. GP_ROLE_PROPERTIES |
  127. GP_ROLE_VIEW |
  128. GP_ROLE_ASSIGN_MEMBER |
  129. GP_ROLE_REMOVE_MEMBER |
  130. GP_ROLE_CHANGE_ACTIONS |
  131. GP_MEMBER_INVITE |
  132. GP_MEMBER_EJECT |
  133. GP_MEMBER_OPTIONS);
  134. #else
  135. return mAllowEdit && gAgent.isInGroup(mGroupID);
  136. #endif
  137. }
  138. //static
  139. void LLPanelGroupRoles::onClickSubTab(void* userdata, bool from_click)
  140. {
  141. LLPanelGroupRoles* self = (LLPanelGroupRoles*)userdata;
  142. if (self)
  143. {
  144. self->handleClickSubTab();
  145. }
  146. }
  147. void LLPanelGroupRoles::handleClickSubTab()
  148. {
  149. // If we are already handling a transition, ignore this.
  150. if (mIgnoreTransition)
  151. {
  152. return;
  153. }
  154. mRequestedTab = (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  155. // Make sure they aren't just clicking the same tab...
  156. if (mRequestedTab == mCurrentTab)
  157. {
  158. return;
  159. }
  160. // Try to switch from the current panel to the panel the user selected.
  161. attemptTransition();
  162. }
  163. bool LLPanelGroupRoles::attemptTransition()
  164. {
  165. // Check if the current tab needs to be applied.
  166. std::string mesg;
  167. if (!mCurrentTab || !mCurrentTab->needsApply(mesg))
  168. {
  169. // The current panel did not have anything it needed to apply.
  170. if (mRequestedTab)
  171. {
  172. transitionToTab();
  173. }
  174. return true;
  175. }
  176. // If no message was provided, give a generic one.
  177. if (mesg.empty())
  178. {
  179. mesg = mDefaultNeedsApplyMesg;
  180. }
  181. // Create a notify box, telling the user about the unapplied tab.
  182. LLSD args;
  183. args["NEEDS_APPLY_MESSAGE"] = mesg;
  184. args["WANT_APPLY_MESSAGE"] = mWantApplyMesg;
  185. gNotifications.add("PanelGroupApply", args, LLSD(),
  186. boost::bind(&LLPanelGroupRoles::handleNotifyCallback,
  187. this, _1, _2));
  188. mHasModal = true;
  189. // We need to reselect the current tab, since it isn't finished.
  190. if (mSubTabContainer)
  191. {
  192. mIgnoreTransition = true;
  193. mSubTabContainer->selectTabPanel(mCurrentTab);
  194. mIgnoreTransition = false;
  195. }
  196. // Returning false will block a close action from finishing until we get a
  197. // response back from the user.
  198. return false;
  199. }
  200. void LLPanelGroupRoles::transitionToTab()
  201. {
  202. // Tell the current panel that it is being deactivated.
  203. if (mCurrentTab)
  204. {
  205. mCurrentTab->deactivate();
  206. }
  207. // Tell the new panel that it is being activated.
  208. if (mRequestedTab)
  209. {
  210. // This is now the current tab;
  211. mCurrentTab = mRequestedTab;
  212. mCurrentTab->activate();
  213. }
  214. }
  215. bool LLPanelGroupRoles::handleNotifyCallback(const LLSD& notification,
  216. const LLSD& response)
  217. {
  218. mHasModal = false;
  219. S32 option = LLNotification::getSelectedOption(notification, response);
  220. if (option >= 2 || option < 0) // "Cancel" or unknown option
  221. {
  222. return false;
  223. }
  224. if (option == 1) // "Ignore changes"
  225. {
  226. // Switch to the requested panel without applying changes
  227. cancel();
  228. mIgnoreTransition = true;
  229. mSubTabContainer->selectTabPanel(mRequestedTab);
  230. mIgnoreTransition = false;
  231. transitionToTab();
  232. return false;
  233. }
  234. // option == 0 ("Apply changes"): try to apply changes, and switch to the
  235. // requested tab.
  236. std::string apply_mesg;
  237. if (!apply(apply_mesg))
  238. {
  239. // There was a problem doing the apply.
  240. if (!apply_mesg.empty())
  241. {
  242. mHasModal = true;
  243. LLSD args;
  244. args["MESSAGE"] = apply_mesg;
  245. gNotifications.add("GenericAlert", args, LLSD(),
  246. boost::bind(&LLPanelGroupRoles::onModalClose,
  247. this, _1, _2));
  248. }
  249. // Skip switching tabs.
  250. return false;
  251. }
  252. // This panel's info successfully applied switch to the next panel
  253. mIgnoreTransition = true;
  254. mSubTabContainer->selectTabPanel(mRequestedTab);
  255. mIgnoreTransition = false;
  256. transitionToTab();
  257. return false;
  258. }
  259. bool LLPanelGroupRoles::onModalClose(const LLSD& notification,
  260. const LLSD& response)
  261. {
  262. mHasModal = false;
  263. return false;
  264. }
  265. bool LLPanelGroupRoles::apply(std::string& mesg)
  266. {
  267. // Pass this along to the currently visible sub tab.
  268. LLPanelGroupTab* panelp = NULL;
  269. if (mSubTabContainer)
  270. {
  271. panelp = (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  272. }
  273. if (!panelp)
  274. {
  275. return false;
  276. }
  277. // Ignore the needs apply message.
  278. std::string ignore_mesg;
  279. if (!panelp->needsApply(ignore_mesg))
  280. {
  281. // We do not need to apply anything: we are done.
  282. return true;
  283. }
  284. // Try to do the actual apply.
  285. return panelp->apply(mesg);
  286. }
  287. void LLPanelGroupRoles::cancel()
  288. {
  289. // Pass this along to the currently visible sub tab.
  290. LLPanelGroupTab* panelp = NULL;
  291. if (mSubTabContainer)
  292. {
  293. panelp = (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  294. }
  295. if (panelp)
  296. {
  297. panelp->cancel();
  298. }
  299. }
  300. // Pass all of these messages to the currently visible sub tab.
  301. std::string LLPanelGroupRoles::getHelpText() const
  302. {
  303. LLPanelGroupTab* panelp = NULL;
  304. if (mSubTabContainer)
  305. {
  306. panelp = (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  307. }
  308. return panelp ? panelp->getHelpText() : mHelpText;
  309. }
  310. void LLPanelGroupRoles::update(LLGroupChange gc)
  311. {
  312. if (mGroupID.isNull() || !mSubTabContainer)
  313. {
  314. return;
  315. }
  316. LLPanelGroupTab* panelp =
  317. (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  318. if (panelp)
  319. {
  320. panelp->update(gc);
  321. }
  322. else
  323. {
  324. llwarns << "No subtab to update !" << llendl;
  325. }
  326. }
  327. void LLPanelGroupRoles::activate()
  328. {
  329. if (!mSubTabContainer || !gAgent.isInGroup(mGroupID))
  330. {
  331. return;
  332. }
  333. // Start requesting member and role data if needed.
  334. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  335. #if 0
  336. // Check member data.
  337. if (!gdatap || !gdatap->isMemberDataComplete())
  338. {
  339. gGroupMgr.sendCapGroupMembersRequest(mGroupID);
  340. }
  341. #endif
  342. // Check role data.
  343. if (!gdatap || !gdatap->isRoleDataComplete())
  344. {
  345. // Mildly hackish - clear all pending changes
  346. cancel();
  347. gGroupMgr.sendGroupRoleDataRequest(mGroupID);
  348. }
  349. #if 0
  350. // Check role-member mapping data.
  351. if (!gdatap || !gdatap->isRoleMemberDataComplete())
  352. {
  353. gGroupMgr.sendGroupRoleMembersRequest(mGroupID);
  354. }
  355. #endif
  356. // Need this to get base group member powers
  357. if (!gdatap || !gdatap->isGroupPropertiesDataComplete())
  358. {
  359. gGroupMgr.sendGroupPropertiesRequest(mGroupID);
  360. }
  361. LLPanelGroupTab* panelp =
  362. (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  363. if (panelp)
  364. {
  365. panelp->activate();
  366. }
  367. }
  368. void LLPanelGroupRoles::deactivate()
  369. {
  370. if (!mSubTabContainer) return;
  371. LLPanelGroupTab* panelp =
  372. (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  373. if (panelp)
  374. {
  375. panelp->deactivate();
  376. }
  377. }
  378. bool LLPanelGroupRoles::needsApply(std::string& mesg)
  379. {
  380. if (!mSubTabContainer)
  381. {
  382. return false;
  383. }
  384. LLPanelGroupTab* panelp =
  385. (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  386. return panelp && panelp->needsApply(mesg);
  387. }
  388. bool LLPanelGroupRoles::hasModal()
  389. {
  390. if (mHasModal)
  391. {
  392. return true;
  393. }
  394. if (!mSubTabContainer)
  395. {
  396. return false;
  397. }
  398. LLPanelGroupTab* panelp =
  399. (LLPanelGroupTab*)mSubTabContainer->getCurrentPanel();
  400. return panelp && panelp->hasModal();
  401. }
  402. // PanelGroupTab observer trigger
  403. void LLPanelGroupRoles::tabChanged()
  404. {
  405. notifyObservers();
  406. }
  407. ////////////////////////////
  408. // LLPanelGroupSubTab
  409. ////////////////////////////
  410. LLPanelGroupSubTab::LLPanelGroupSubTab(const std::string& name,
  411. const LLUUID& group_id)
  412. : LLPanelGroupTab(name, group_id),
  413. mHeader(NULL),
  414. mFooter(NULL),
  415. mHasGroupBanPower(false),
  416. mSearchLineEditor(NULL),
  417. mSearchButton(NULL),
  418. mShowAllButton(NULL)
  419. {
  420. }
  421. bool LLPanelGroupSubTab::postBuild()
  422. {
  423. // Hook up the search widgets.
  424. mSearchLineEditor = getChild<LLLineEditor>("search_text", true, false);
  425. if (!mSearchLineEditor) return false;
  426. mSearchLineEditor->setKeystrokeCallback(onSearchKeystroke);
  427. mSearchLineEditor->setCallbackUserData(this);
  428. mSearchButton = getChild<LLButton>("search_button", true, false);
  429. if (!mSearchButton) return false;
  430. mSearchButton->setClickedCallback(onClickSearch);
  431. mSearchButton->setCallbackUserData(this);
  432. mSearchButton->setEnabled(false);
  433. mShowAllButton = getChild<LLButton>("show_all_button", true, false);
  434. if (!mShowAllButton) return false;
  435. mShowAllButton->setClickedCallback(onClickShowAll);
  436. mShowAllButton->setCallbackUserData(this);
  437. mShowAllButton->setEnabled(false);
  438. // Get icons for later use.
  439. mActionIcons.clear();
  440. LLIconCtrl* icon = getChild<LLIconCtrl>("power_folder_icon", false, false);
  441. if (icon && !icon->getImageName().empty())
  442. {
  443. mActionIcons["folder"] = icon->getImageName();
  444. removeChild(icon, true);
  445. }
  446. icon = getChild<LLIconCtrl>("power_all_have_icon", false, false);
  447. if (icon && !icon->getImageName().empty())
  448. {
  449. mActionIcons["full"] = icon->getImageName();
  450. removeChild(icon, true);
  451. }
  452. icon = getChild<LLIconCtrl>("power_partial_icon", false, false);
  453. if (icon && !icon->getImageName().empty())
  454. {
  455. mActionIcons["partial"] = icon->getImageName();
  456. removeChild(icon, true);
  457. }
  458. return LLPanelGroupTab::postBuild();
  459. }
  460. //static
  461. void LLPanelGroupSubTab::onSearchKeystroke(LLLineEditor* caller, void* userdata)
  462. {
  463. LLPanelGroupSubTab* self = (LLPanelGroupSubTab*)userdata;
  464. if (self)
  465. {
  466. self->handleSearchKeystroke(caller);
  467. }
  468. }
  469. void LLPanelGroupSubTab::handleSearchKeystroke(LLLineEditor* caller)
  470. {
  471. if (!mSearchButton) return;
  472. if (caller->getText().size())
  473. {
  474. setDefaultBtn(mSearchButton);
  475. mSearchButton->setEnabled(true);
  476. }
  477. else
  478. {
  479. setDefaultBtn((LLButton*)NULL);
  480. mSearchButton->setEnabled(false);
  481. }
  482. }
  483. //static
  484. void LLPanelGroupSubTab::onClickSearch(void* userdata)
  485. {
  486. LLPanelGroupSubTab* self = (LLPanelGroupSubTab*)userdata;
  487. if (self)
  488. {
  489. self->handleClickSearch();
  490. }
  491. }
  492. void LLPanelGroupSubTab::handleClickSearch()
  493. {
  494. if (!mSearchLineEditor || !mSearchButton || !mShowAllButton)
  495. {
  496. return;
  497. }
  498. if (mSearchLineEditor->getText().empty())
  499. {
  500. // No search text (this should not happen; the search button should
  501. // have been disabled).
  502. llwarns << "No search text !" << llendl;
  503. mSearchButton->setEnabled(false);
  504. return;
  505. }
  506. setSearchFilter(mSearchLineEditor->getText());
  507. mShowAllButton->setEnabled(true);
  508. }
  509. //static
  510. void LLPanelGroupSubTab::onClickShowAll(void* userdata)
  511. {
  512. LLPanelGroupSubTab* self = (LLPanelGroupSubTab*)userdata;
  513. if (self)
  514. {
  515. self->handleClickShowAll();
  516. }
  517. }
  518. void LLPanelGroupSubTab::handleClickShowAll()
  519. {
  520. if (mShowAllButton)
  521. {
  522. setSearchFilter(LLStringUtil::null);
  523. mShowAllButton->setEnabled(false);
  524. }
  525. }
  526. void LLPanelGroupSubTab::setSearchFilter(const std::string& filter)
  527. {
  528. LL_DEBUGS("GroupPanel") << "New search filter: '" << filter << "'"
  529. << LL_ENDL;
  530. mSearchFilter = filter;
  531. LLStringUtil::toLower(mSearchFilter);
  532. update(GC_ALL);
  533. }
  534. void LLPanelGroupSubTab::activate()
  535. {
  536. setOthersVisible(true);
  537. }
  538. void LLPanelGroupSubTab::deactivate()
  539. {
  540. setOthersVisible(false);
  541. }
  542. void LLPanelGroupSubTab::setOthersVisible(bool b)
  543. {
  544. if (mHeader)
  545. {
  546. mHeader->setVisible(b);
  547. }
  548. else
  549. {
  550. llwarns << "LLPanelGroupSubTab missing header !" << llendl;
  551. }
  552. if (mFooter)
  553. {
  554. mFooter->setVisible(b);
  555. }
  556. else
  557. {
  558. llwarns << "LLPanelGroupSubTab missing footer !" << llendl;
  559. }
  560. }
  561. bool LLPanelGroupSubTab::matchesActionSearchFilter(std::string action)
  562. {
  563. // If the search filter is empty, everything passes.
  564. if (mSearchFilter.empty())
  565. {
  566. return true;
  567. }
  568. LLStringUtil::toLower(action);
  569. return action.find(mSearchFilter) != std::string::npos;
  570. }
  571. void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl,
  572. U64 allowed_by_some,
  573. U64 allowed_by_all,
  574. icon_map_t& icons,
  575. void (*commit_callback)(LLUICtrl*, void*),
  576. bool show_all,
  577. bool filter,
  578. bool is_owner_role)
  579. {
  580. if (gGroupMgr.mRoleActionSets.empty())
  581. {
  582. llwarns << "Can't build action list - no actions found." << llendl;
  583. return;
  584. }
  585. mHasGroupBanPower = false;
  586. for (U32 i = 0, count = gGroupMgr.mRoleActionSets.size(); i < count; ++i)
  587. {
  588. buildActionCategory(ctrl, allowed_by_some, allowed_by_all,
  589. gGroupMgr.mRoleActionSets[i], icons,
  590. commit_callback, show_all, filter, is_owner_role);
  591. }
  592. }
  593. void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl,
  594. U64 allowed_by_some,
  595. U64 allowed_by_all,
  596. LLRoleActionSet* action_set,
  597. icon_map_t& icons,
  598. void (*commit_callback)(LLUICtrl*, void*),
  599. bool show_all,
  600. bool filter,
  601. bool is_owner_role)
  602. {
  603. LL_DEBUGS("GroupPanel") << "Building role list for: "
  604. << action_set->mActionSetData->mName << LL_ENDL;
  605. // See if the allow mask matches anything in this category.
  606. if (!show_all && !(allowed_by_some & action_set->mActionSetData->mPowerBit))
  607. {
  608. return;
  609. }
  610. // List all the actions in this category that at least some members have.
  611. LLSD row;
  612. LLSD& columns = row["columns"];
  613. columns[0]["column"] = "icon";
  614. icon_map_t::iterator iter = icons.find("folder");
  615. if (iter != icons.end())
  616. {
  617. columns[0]["type"] = "icon";
  618. columns[0]["value"] = iter->second;
  619. }
  620. columns[1]["column"] = "action";
  621. columns[1]["value"] = action_set->mActionSetData->mName;
  622. columns[1]["font-style"] = "BOLD";
  623. LLScrollListItem* title_row = ctrl->addElement(row, ADD_BOTTOM,
  624. action_set->mActionSetData);
  625. bool category_matches_filter =
  626. !filter ||
  627. matchesActionSearchFilter(action_set->mActionSetData->mName);
  628. bool items_match_filter = false;
  629. bool can_change_actions = !is_owner_role &&
  630. gAgent.hasPowerInGroup(mGroupID,
  631. GP_ROLE_CHANGE_ACTIONS);
  632. for (U32 i = 0, count = action_set->mActions.size(); i < count; ++i)
  633. {
  634. LLRoleAction* rap = action_set->mActions[i];
  635. // See if anyone has these action.
  636. if (!show_all && !(allowed_by_some & rap->mPowerBit))
  637. {
  638. continue;
  639. }
  640. // See if we are filtering out these actions; if we are not using
  641. // filters, category_matches_filter will be true.
  642. if (!category_matches_filter &&
  643. !matchesActionSearchFilter(rap->mDescription))
  644. {
  645. continue;
  646. }
  647. items_match_filter = true;
  648. // See if everyone has these actions.
  649. bool show_full_strength = (allowed_by_some & rap->mPowerBit) ==
  650. (allowed_by_all & rap->mPowerBit);
  651. LLSD row;
  652. LLSD& columns = row["columns"];
  653. S32 column_index = 0;
  654. columns[column_index++]["column"] = "icon";
  655. S32 check_box_index = -1;
  656. if (commit_callback)
  657. {
  658. columns[column_index]["column"] = "checkbox";
  659. columns[column_index]["type"] = "checkbox";
  660. check_box_index = column_index++;
  661. }
  662. else if (show_full_strength)
  663. {
  664. icon_map_t::iterator iter = icons.find("full");
  665. if (iter != icons.end())
  666. {
  667. columns[column_index]["column"] = "checkbox";
  668. columns[column_index]["type"] = "icon";
  669. columns[column_index++]["value"] = iter->second;
  670. }
  671. }
  672. else
  673. {
  674. icon_map_t::iterator iter = icons.find("partial");
  675. if (iter != icons.end())
  676. {
  677. columns[column_index]["column"] = "checkbox";
  678. columns[column_index]["type"] = "icon";
  679. columns[column_index++]["value"] = iter->second;
  680. }
  681. row["enabled"] = false;
  682. }
  683. columns[column_index]["column"] = "action";
  684. columns[column_index]["value"] = rap->mDescription;
  685. columns[column_index]["font"] = "SANSSERIF_SMALL";
  686. if (mHasGroupBanPower)
  687. {
  688. // The ban ability is being set. Prevent these abilities from being
  689. // manipulated
  690. if (rap->mPowerBit == GP_MEMBER_EJECT ||
  691. rap->mPowerBit == GP_ROLE_REMOVE_MEMBER)
  692. {
  693. row["enabled"] = false;
  694. }
  695. }
  696. else
  697. {
  698. // The ban ability is not set. Allow these abilities to be
  699. // manipulated
  700. if (rap->mPowerBit == GP_MEMBER_EJECT ||
  701. rap->mPowerBit == GP_ROLE_REMOVE_MEMBER)
  702. {
  703. row["enabled"] = true;
  704. }
  705. }
  706. if (check_box_index == -1)
  707. {
  708. continue;
  709. }
  710. // Extract the checkbox that was created.
  711. LLScrollListItem* item = ctrl->addElement(row, ADD_BOTTOM, rap);
  712. LLScrollListCheck* check_cell =
  713. (LLScrollListCheck*)item->getColumn(check_box_index);
  714. LLCheckBoxCtrl* check = check_cell->getCheckBox();
  715. check->setEnabled(can_change_actions);
  716. check->setCommitCallback(commit_callback);
  717. check->setCallbackUserData(ctrl->getCallbackUserData());
  718. check->setToolTip(check->getLabel());
  719. if (show_all)
  720. {
  721. check->setTentative(false);
  722. check->set((allowed_by_some & rap->mPowerBit) != 0);
  723. }
  724. else
  725. {
  726. check->set(true);
  727. check->setTentative(!show_full_strength);
  728. }
  729. // Regardless of whether or not this ability is allowed by all or some,
  730. // we want to prevent the group managers from accidentally disabling
  731. // either of the 2 additional abilities tied with GP_GROUP_BAN_ACCESS.
  732. if ((allowed_by_all & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS ||
  733. (allowed_by_some & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS)
  734. {
  735. mHasGroupBanPower = true;
  736. }
  737. }
  738. if (!items_match_filter)
  739. {
  740. S32 title_index = ctrl->getItemIndex(title_row);
  741. ctrl->deleteSingleItem(title_index);
  742. }
  743. }
  744. void LLPanelGroupSubTab::setFooterEnabled(bool enable)
  745. {
  746. if (mFooter)
  747. {
  748. mFooter->setAllChildrenEnabled(enable);
  749. }
  750. }
  751. ////////////////////////////
  752. // LLPanelGroupMembersSubTab
  753. ////////////////////////////
  754. //static
  755. void* LLPanelGroupMembersSubTab::createTab(void* data)
  756. {
  757. LLUUID* group_id = (LLUUID*)data;
  758. return new LLPanelGroupMembersSubTab("panel group members sub tab",
  759. *group_id);
  760. }
  761. LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab(const std::string& name,
  762. const LLUUID& group_id)
  763. : LLPanelGroupSubTab(name, group_id),
  764. mMembersList(NULL),
  765. mAssignedRolesList(NULL),
  766. mAllowedActionsList(NULL),
  767. mChanged(false),
  768. mPendingMemberUpdate(false),
  769. mUpdateInterval(0.5f),
  770. mSkipNextUpdate(false),
  771. mHasMatch(false),
  772. mNumOwnerAdditions(0)
  773. {
  774. }
  775. bool LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
  776. {
  777. // Upcast parent so we can ask it for sibling controls.
  778. LLPanelGroupRoles* parent = (LLPanelGroupRoles*)root;
  779. mHeader = parent->getChild<LLPanel>("members_header", true, false);
  780. mFooter = parent->getChild<LLPanel>("members_footer", true, false);
  781. mMembersList = parent->getChild<LLNameListCtrl>("member_list",
  782. true, false);
  783. mAssignedRolesList =
  784. parent->getChild<LLScrollListCtrl>("member_assigned_roles", true,
  785. false);
  786. mAllowedActionsList =
  787. parent->getChild<LLScrollListCtrl>("member_allowed_actions", true,
  788. false);
  789. if (!mMembersList || !mAssignedRolesList || !mAllowedActionsList)
  790. {
  791. return false;
  792. }
  793. // We want to be notified whenever a member is selected.
  794. mMembersList->setCommitOnSelectionChange(true);
  795. mMembersList->setCommitCallback(onMemberSelect);
  796. // Show the member's profile on double click.
  797. mMembersList->setDoubleClickCallback(onMemberDoubleClick);
  798. mMembersList->setCallbackUserData(this);
  799. LLButton* button = parent->getChild<LLButton>("member_invite",
  800. true, false);
  801. if (button)
  802. {
  803. button->setClickedCallback(onInviteMember);
  804. button->setCallbackUserData(this);
  805. button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE));
  806. }
  807. mEjectBtn = parent->getChild<LLButton>("member_eject", true, false);
  808. if (mEjectBtn)
  809. {
  810. mEjectBtn->setClickedCallback(onEjectMembers);
  811. mEjectBtn->setCallbackUserData(this);
  812. mEjectBtn->setEnabled(false);
  813. }
  814. mBanBtn = parent->getChild<LLButton>("member_ban", true, false);
  815. if (mBanBtn)
  816. {
  817. mBanBtn->setClickedCallback(onBanMember);
  818. mBanBtn->setCallbackUserData(this);
  819. mBanBtn->setEnabled(false);
  820. }
  821. return true;
  822. }
  823. //static
  824. void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* userdata)
  825. {
  826. LLPanelGroupMembersSubTab* self = (LLPanelGroupMembersSubTab*)userdata;
  827. if (self)
  828. {
  829. self->handleMemberSelect();
  830. }
  831. }
  832. void LLPanelGroupMembersSubTab::handleMemberSelect()
  833. {
  834. if (!mAssignedRolesList || !mAllowedActionsList || !mMembersList)
  835. {
  836. return;
  837. }
  838. mAssignedRolesList->deleteAllItems();
  839. mAllowedActionsList->deleteAllItems();
  840. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  841. if (!gdatap)
  842. {
  843. llwarns << "No group data !" << llendl;
  844. return;
  845. }
  846. // Check if there is anything selected.
  847. std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
  848. if (selection.empty())
  849. {
  850. return;
  851. }
  852. // Build a vector of all selected members, and gather allowed actions.
  853. uuid_vec_t selected_members;
  854. U64 allowed_by_all = GP_ALL_POWERS;
  855. U64 allowed_by_some = 0;
  856. for (U32 i = 0, count = selection.size(); i < count; ++i)
  857. {
  858. const LLUUID& item_id = selection[i]->getUUID();
  859. selected_members.emplace_back(item_id);
  860. // Get this member's power mask including any unsaved changes
  861. U64 powers = getAgentPowersBasedOnRoleChanges(item_id);
  862. allowed_by_all &= powers;
  863. allowed_by_some |= powers;
  864. }
  865. std::sort(selected_members.begin(), selected_members.end());
  866. // Build the allowed actions list.
  867. buildActionsList(mAllowedActionsList, allowed_by_some, allowed_by_all,
  868. mActionIcons, NULL, false, false, false);
  869. // Build the assigned roles list.
  870. // Add each role to the assigned roles list.
  871. bool can_ban_members = gAgent.hasPowerInGroup(mGroupID,
  872. GP_GROUP_BAN_ACCESS);
  873. bool can_eject_members = gAgent.hasPowerInGroup(mGroupID,
  874. GP_MEMBER_EJECT);
  875. bool member_is_owner = false;
  876. for (LLGroupMgrGroupData::role_list_t::iterator
  877. iter = gdatap->mRoles.begin(), end = gdatap->mRoles.end();
  878. iter != end; ++iter)
  879. {
  880. // Count how many selected users are in this role.
  881. const LLUUID& role_id = iter->first;
  882. LLGroupRoleData* group_role_data = iter->second;
  883. if (!group_role_data)
  884. {
  885. // This could happen if changes are not synced right on sub-panel
  886. // change.
  887. llwarns << "No group role data for " << iter->second << llendl;
  888. continue;
  889. }
  890. constexpr bool needs_sort = false;
  891. S32 count = group_role_data->getMembersInRole(selected_members,
  892. needs_sort);
  893. // Check if the user has permissions to assign/remove members to/from
  894. // the role (but the ability to add/remove should only be based on the
  895. // "saved" changes to the role not in the temp/meta data. -jwolk
  896. bool cb_enable = count > 0 ? agentCanRemoveFromRole(mGroupID, role_id)
  897. : gGroupMgr.agentCanAddToRole(mGroupID,
  898. role_id);
  899. // Owner role has special enabling permissions for removal.
  900. if (cb_enable && count > 0 && role_id == gdatap->mOwnerRole)
  901. {
  902. // Check if any owners besides this agent are selected.
  903. for (U32 i = 0, mcount = selected_members.size(); i < mcount; ++i)
  904. {
  905. const LLUUID& mid = selected_members[i];
  906. // Do not count the agent.
  907. if (mid == gAgentID)
  908. {
  909. continue;
  910. }
  911. // Look up the member data.
  912. LLGroupMgrGroupData::member_list_t::iterator mi =
  913. gdatap->mMembers.find(mid);
  914. if (mi == gdatap->mMembers.end())
  915. {
  916. continue;
  917. }
  918. LLGroupMemberData* member_data = mi->second;
  919. // Is the member an owner ?
  920. if (member_data && member_data->isInRole(gdatap->mOwnerRole))
  921. {
  922. // Cannot remove other owners.
  923. cb_enable = can_ban_members = false;
  924. break;
  925. }
  926. }
  927. }
  928. // Now see if there are any role changes for the selected members and
  929. // remember to include them
  930. for (U32 i = 0, mcount = selected_members.size(); i < mcount; ++i)
  931. {
  932. const LLUUID& mid = selected_members[i];
  933. LLRoleMemberChangeType type;
  934. if (getRoleChangeType(mid, role_id, type))
  935. {
  936. if (type == RMC_ADD)
  937. {
  938. ++count;
  939. }
  940. else if (type == RMC_REMOVE)
  941. {
  942. --count;
  943. }
  944. }
  945. }
  946. // If anyone selected is in any role besides 'Everyone' then they
  947. // cannot be ejected.
  948. if (count > 0 && role_id.notNull())
  949. {
  950. can_eject_members = false;
  951. if (role_id == gdatap->mOwnerRole)
  952. {
  953. member_is_owner = true;
  954. }
  955. }
  956. LLRoleData rd;
  957. if (gdatap->getRoleData(role_id, rd))
  958. {
  959. std::ostringstream label;
  960. label << rd.mRoleName;
  961. // Do not bother showing a count, if there is only 0 or 1.
  962. if (count > 1)
  963. {
  964. label << ": " << count;
  965. }
  966. LLSD row;
  967. row["id"] = role_id;
  968. LLSD& columns = row["columns"];
  969. columns[0]["column"] = "checkbox";
  970. columns[0]["type"] = "checkbox";
  971. columns[1]["column"] = "role";
  972. columns[1]["value"] = label.str();
  973. if (row["id"].asUUID().isNull())
  974. {
  975. // This is the everyone role, you cannot take people out of the
  976. // "Everyone" role !
  977. row["enabled"] = false;
  978. }
  979. LLScrollListItem* item = mAssignedRolesList->addElement(row);
  980. // Extract the checkbox that was created.
  981. LLScrollListCheck* check_cell;
  982. check_cell = (LLScrollListCheck*)item->getColumn(0);
  983. LLCheckBoxCtrl* check = check_cell->getCheckBox();
  984. check->setCommitCallback(onRoleCheck);
  985. check->setCallbackUserData(this);
  986. check->set(count > 0);
  987. check->setTentative(count != 0 &&
  988. selected_members.size() != (uuid_vec_t::size_type)count);
  989. // NOTE: as of right now a user can break the group by removing
  990. // themselves from a role if he is the last owner. We should
  991. // check for this special case -jwolk
  992. check->setEnabled(cb_enable);
  993. }
  994. }
  995. mAssignedRolesList->setEnabled(true);
  996. if (gAgent.isGodlikeWithoutAdminMenuFakery())
  997. {
  998. can_eject_members = true;
  999. #if 0
  1000. can_ban_members = true;
  1001. #endif
  1002. }
  1003. if (!can_eject_members && !member_is_owner)
  1004. {
  1005. // Maybe we can eject them because we are an owner...
  1006. LLGroupMgrGroupData::member_list_t::iterator mi;
  1007. mi = gdatap->mMembers.find(gAgentID);
  1008. if (mi != gdatap->mMembers.end())
  1009. {
  1010. LLGroupMemberData* member_data = mi->second;
  1011. if (member_data && member_data->isInRole(gdatap->mOwnerRole))
  1012. {
  1013. can_eject_members = true;
  1014. #if 0
  1015. can_ban_members = true;
  1016. #endif
  1017. }
  1018. }
  1019. }
  1020. // ... or we can eject them because we have all the requisite powers...
  1021. if (!member_is_owner &&
  1022. gAgent.hasPowerInGroup(mGroupID, GP_ROLE_REMOVE_MEMBER))
  1023. {
  1024. if (gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT))
  1025. {
  1026. can_eject_members = true;
  1027. }
  1028. if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
  1029. {
  1030. can_ban_members = true;
  1031. }
  1032. }
  1033. for (uuid_vec_t::const_iterator it = selected_members.begin(),
  1034. end = selected_members.end();
  1035. it != end; ++it)
  1036. {
  1037. // Do not count the agent.
  1038. if (*it == gAgentID)
  1039. {
  1040. can_eject_members = false;
  1041. can_ban_members = false;
  1042. }
  1043. }
  1044. if (mBanBtn)
  1045. {
  1046. mBanBtn->setEnabled(can_ban_members);
  1047. }
  1048. if (mEjectBtn)
  1049. {
  1050. mEjectBtn->setEnabled(can_eject_members);
  1051. }
  1052. }
  1053. //static
  1054. void LLPanelGroupMembersSubTab::onMemberDoubleClick(void* userdata)
  1055. {
  1056. LLPanelGroupMembersSubTab* self = (LLPanelGroupMembersSubTab*)userdata;
  1057. if (self && self->mMembersList)
  1058. {
  1059. LLScrollListItem* selected = self->mMembersList->getFirstSelected();
  1060. if (selected)
  1061. {
  1062. LLFloaterAvatarInfo::showFromDirectory(selected->getUUID());
  1063. }
  1064. }
  1065. }
  1066. //static
  1067. void LLPanelGroupMembersSubTab::onInviteMember(void* userdata)
  1068. {
  1069. LLPanelGroupMembersSubTab* self = (LLPanelGroupMembersSubTab*)userdata;
  1070. if (self)
  1071. {
  1072. LLFloaterGroupInvite::showForGroup(self->mGroupID, NULL, self);
  1073. }
  1074. }
  1075. void LLPanelGroupMembersSubTab::onEjectMembers(void* userdata)
  1076. {
  1077. LLPanelGroupMembersSubTab* self = (LLPanelGroupMembersSubTab*)userdata;
  1078. if (self)
  1079. {
  1080. self->handleEjectMembers();
  1081. }
  1082. }
  1083. // Sends an eject message
  1084. void LLPanelGroupMembersSubTab::handleEjectMembers()
  1085. {
  1086. if (!mMembersList) return;
  1087. std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
  1088. if (selection.empty()) return;
  1089. uuid_vec_t selected_members;
  1090. for (U32 i = 0, count = selection.size(); i < count; ++i)
  1091. {
  1092. selected_members.emplace_back(selection[i]->getUUID());
  1093. }
  1094. mMembersList->deleteSelectedItems();
  1095. gGroupMgr.sendGroupMemberEjects(mGroupID, selected_members);
  1096. }
  1097. void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
  1098. LLRoleMemberChangeType type)
  1099. {
  1100. if (!mMembersList) return;
  1101. std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
  1102. if (selection.empty())
  1103. {
  1104. return;
  1105. }
  1106. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1107. if (!gdatap)
  1108. {
  1109. return;
  1110. }
  1111. // Add that the user is requesting to change the roles for selected members
  1112. U64 powers_all_have = GP_ALL_POWERS;
  1113. U64 powers_some_have = 0;
  1114. bool is_owner_role = gdatap->mOwnerRole == role_id;
  1115. for (U32 i = 0, count = selection.size(); i < count; ++i)
  1116. {
  1117. const LLUUID& mid = selection[i]->getUUID();
  1118. // See if we requested a change for this member before
  1119. if (!mMemberRoleChangeData.count(mid))
  1120. {
  1121. mMemberRoleChangeData[mid] = new role_change_data_map_t;
  1122. }
  1123. role_change_data_map_t* rc_datap = mMemberRoleChangeData[mid];
  1124. // Now check to see if the selected group member had changed their
  1125. // association with the selected role before
  1126. role_change_data_map_t::iterator role = rc_datap->find(role_id);
  1127. if (role != rc_datap->end())
  1128. {
  1129. // See if the new change type cancels out the previous change
  1130. if (role->second != type)
  1131. {
  1132. rc_datap->erase(role_id);
  1133. if (is_owner_role)
  1134. {
  1135. --mNumOwnerAdditions;
  1136. }
  1137. }
  1138. // Else do nothing
  1139. if (rc_datap->empty())
  1140. {
  1141. // The current member now has no role changes, so erase the
  1142. // role change and erase the member's entry
  1143. delete rc_datap;
  1144. rc_datap = NULL;
  1145. mMemberRoleChangeData.erase(mid);
  1146. }
  1147. }
  1148. else
  1149. {
  1150. // A previously unchanged role is being changed
  1151. (*rc_datap)[role_id] = type;
  1152. if (is_owner_role && type == RMC_ADD)
  1153. {
  1154. ++mNumOwnerAdditions;
  1155. }
  1156. }
  1157. // We need to calculate what powers the selected members have
  1158. // (including the role changes we are making) so that we can rebuild
  1159. // the action list
  1160. U64 new_powers = getAgentPowersBasedOnRoleChanges(mid);
  1161. powers_all_have &= new_powers;
  1162. powers_some_have |= new_powers;
  1163. }
  1164. mChanged = !mMemberRoleChangeData.empty();
  1165. notifyObservers();
  1166. // Now we need to update the actions list to reflect the changes
  1167. mAllowedActionsList->deleteAllItems();
  1168. buildActionsList(mAllowedActionsList, powers_some_have, powers_all_have,
  1169. mActionIcons, NULL, false, false, false);
  1170. }
  1171. //static
  1172. void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* userdata)
  1173. {
  1174. LLPanelGroupMembersSubTab* self = (LLPanelGroupMembersSubTab*)userdata;
  1175. LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
  1176. if (!check_box || !self || !self->mAssignedRolesList)
  1177. {
  1178. return;
  1179. }
  1180. LLScrollListItem* itemp = self->mAssignedRolesList->getFirstSelected();
  1181. if (itemp)
  1182. {
  1183. self->handleRoleCheck(itemp->getUUID(),
  1184. check_box->get() ? RMC_ADD : RMC_REMOVE);
  1185. }
  1186. }
  1187. void LLPanelGroupMembersSubTab::activate()
  1188. {
  1189. LLPanelGroupSubTab::activate();
  1190. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1191. if (!gdatap || !gdatap->isMemberDataComplete())
  1192. {
  1193. gGroupMgr.sendCapGroupMembersRequest(mGroupID);
  1194. }
  1195. if (!gdatap || !gdatap->isRoleMemberDataComplete())
  1196. {
  1197. gGroupMgr.sendGroupRoleMembersRequest(mGroupID);
  1198. }
  1199. update(GC_ALL);
  1200. }
  1201. void LLPanelGroupMembersSubTab::deactivate()
  1202. {
  1203. LLPanelGroupSubTab::deactivate();
  1204. }
  1205. bool LLPanelGroupMembersSubTab::needsApply(std::string&)
  1206. {
  1207. return mChanged;
  1208. }
  1209. void LLPanelGroupMembersSubTab::cancel()
  1210. {
  1211. if (!mChanged)
  1212. {
  1213. return; // Nothing to do !
  1214. }
  1215. for (member_role_changes_map_t::iterator
  1216. it = mMemberRoleChangeData.begin(),
  1217. end = mMemberRoleChangeData.end();
  1218. it != end; ++it)
  1219. {
  1220. delete it->second;
  1221. }
  1222. mMemberRoleChangeData.clear();
  1223. mChanged = false;
  1224. notifyObservers();
  1225. }
  1226. bool LLPanelGroupMembersSubTab::apply(std::string& mesg)
  1227. {
  1228. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1229. if (!gdatap)
  1230. {
  1231. llwarns << "Unable to get group data for group " << mGroupID << llendl;
  1232. mesg.assign("Unable to save member data. Try again later.");
  1233. return false;
  1234. }
  1235. if (!mChanged)
  1236. {
  1237. return true;
  1238. }
  1239. // Figure out if we are somehow adding an owner or not and alert the user.
  1240. // Possibly make it ignorable.
  1241. if (!mNumOwnerAdditions)
  1242. {
  1243. applyMemberChanges();
  1244. return true;
  1245. }
  1246. LLRoleData rd;
  1247. if (!gdatap->getRoleData(gdatap->mOwnerRole, rd))
  1248. {
  1249. llwarns << "Unable to get role information for the owner role in group "
  1250. << mGroupID << llendl;
  1251. // *TODO: translate
  1252. mesg.assign("Unable to retried specific group information. Try again later");
  1253. return false;
  1254. }
  1255. LLSD args;
  1256. mHasModal = true;
  1257. args["ROLE_NAME"] = rd.mRoleName;
  1258. gNotifications.add("AddGroupOwnerWarning", args, LLSD(),
  1259. boost::bind(&LLPanelGroupMembersSubTab::addOwnerCB,
  1260. this, _1, _2));
  1261. return true;
  1262. }
  1263. bool LLPanelGroupMembersSubTab::addOwnerCB(const LLSD& notification,
  1264. const LLSD& response)
  1265. {
  1266. mHasModal = false;
  1267. if (LLNotification::getSelectedOption(notification, response) == 0)
  1268. {
  1269. // User clicked "Yes"
  1270. applyMemberChanges();
  1271. }
  1272. return false;
  1273. }
  1274. void LLPanelGroupMembersSubTab::applyMemberChanges()
  1275. {
  1276. // Sucks to do a find again here, but it is in constant time, so, could be
  1277. // worse
  1278. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1279. if (!gdatap)
  1280. {
  1281. llwarns << "Unable to get group data for group " << mGroupID << llendl;
  1282. return;
  1283. }
  1284. // We need to add all of the changed roles data for each member whose role
  1285. // changed
  1286. for (member_role_changes_map_t::iterator mit = mMemberRoleChangeData.begin();
  1287. mit != mMemberRoleChangeData.end(); ++mit)
  1288. {
  1289. for (role_change_data_map_t::iterator rit = mit->second->begin();
  1290. rit != mit->second->end(); ++rit)
  1291. {
  1292. gdatap->changeRoleMember(rit->first, // role_id
  1293. mit->first, // member_id
  1294. rit->second); // add/remove
  1295. }
  1296. mit->second->clear();
  1297. delete mit->second;
  1298. }
  1299. mMemberRoleChangeData.clear();
  1300. gGroupMgr.sendGroupRoleMemberChanges(mGroupID);
  1301. // Force an UI update
  1302. handleMemberSelect();
  1303. mChanged = false;
  1304. mNumOwnerAdditions = 0;
  1305. notifyObservers();
  1306. }
  1307. bool LLPanelGroupMembersSubTab::matchesSearchFilter(std::string fullname)
  1308. {
  1309. // If the search filter is empty, everything passes.
  1310. if (mSearchFilter.empty())
  1311. {
  1312. return true;
  1313. }
  1314. // Compare full name to the search filter.
  1315. LLStringUtil::toLower(fullname);
  1316. return fullname.find(mSearchFilter) != std::string::npos;
  1317. }
  1318. U64 LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges(const LLUUID& agent_id)
  1319. {
  1320. // We loop over all of the changes if we are adding a role, then we simply
  1321. // add the role's powers, if we are removing a role, we store that role Id
  1322. // away and then we have to build the powers up bases on the roles the
  1323. // agent is in.
  1324. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1325. if (!gdatap)
  1326. {
  1327. llwarns << "No group data !" << llendl;
  1328. return GP_NO_POWERS;
  1329. }
  1330. LLGroupMemberData* member_data = gdatap->mMembers[agent_id];
  1331. if (!member_data)
  1332. {
  1333. llwarns << "No member data for member with UUID " << agent_id
  1334. << llendl;
  1335. return GP_NO_POWERS;
  1336. }
  1337. // See if there are unsaved role changes for this agent
  1338. role_change_data_map_t* rc_datap = NULL;
  1339. member_role_changes_map_t::iterator member =
  1340. mMemberRoleChangeData.find(agent_id);
  1341. if (member != mMemberRoleChangeData.end())
  1342. {
  1343. // this member has unsaved role changes, so grab them
  1344. rc_datap = member->second;
  1345. }
  1346. U64 new_powers = GP_NO_POWERS;
  1347. if (rc_datap)
  1348. {
  1349. uuid_list_t roles_to_be_removed;
  1350. for (role_change_data_map_t::iterator it = rc_datap->begin(),
  1351. end = rc_datap->end();
  1352. it != end; ++it)
  1353. {
  1354. if (it->second == RMC_ADD)
  1355. {
  1356. new_powers |= gdatap->getRolePowers(it->first);
  1357. }
  1358. else
  1359. {
  1360. roles_to_be_removed.insert(it->first);
  1361. }
  1362. }
  1363. // Loop over the member's current roles, summing up the powers (not
  1364. // including the role we are removing)
  1365. for (LLGroupMemberData::role_list_t::iterator
  1366. it = member_data->roleBegin(), end = member_data->roleEnd();
  1367. it != end; ++it)
  1368. {
  1369. if (!roles_to_be_removed.count(it->second->getID()))
  1370. {
  1371. new_powers |= it->second->getRoleData().mRolePowers;
  1372. }
  1373. }
  1374. }
  1375. else
  1376. {
  1377. // There is no change for this member the member's powers are just the
  1378. // ones stored in the group manager
  1379. new_powers = member_data->getAgentPowers();
  1380. }
  1381. return new_powers;
  1382. }
  1383. // If there is no change, returns false be sure to verify that there is a role
  1384. // change before attempting to get it or else the data will make no sense.
  1385. // Stores the role change type.
  1386. bool LLPanelGroupMembersSubTab::getRoleChangeType(const LLUUID& member_id,
  1387. const LLUUID& role_id,
  1388. LLRoleMemberChangeType& type)
  1389. {
  1390. member_role_changes_map_t::iterator mit =
  1391. mMemberRoleChangeData.find(member_id);
  1392. if (mit != mMemberRoleChangeData.end())
  1393. {
  1394. role_change_data_map_t::iterator rit = mit->second->find(role_id);
  1395. if (rit != mit->second->end())
  1396. {
  1397. type = rit->second;
  1398. return true;
  1399. }
  1400. }
  1401. return false;
  1402. }
  1403. void LLPanelGroupMembersSubTab::draw()
  1404. {
  1405. // Do not update every frame: that would be insane !
  1406. if (mSkipNextUpdate)
  1407. {
  1408. // Compute the time the viewer took to 'digest' the update and come
  1409. // back to us; the name list update takes time, and the avatar name
  1410. // query takes even more time when the name is not cached !
  1411. mUpdateInterval = (mUpdateInterval +
  1412. 3.f * mUpdateTimer.getElapsedTimeF32()) * 0.5f;
  1413. mSkipNextUpdate = false;
  1414. LL_DEBUGS("GroupPanel") << "Interval for next update = "
  1415. << mUpdateInterval << "s" << LL_ENDL;
  1416. mUpdateTimer.reset();
  1417. }
  1418. else if (mPendingMemberUpdate &&
  1419. mUpdateTimer.getElapsedTimeF32() > mUpdateInterval)
  1420. {
  1421. mUpdateTimer.reset();
  1422. updateMembers();
  1423. mSkipNextUpdate = true;
  1424. }
  1425. LLPanelGroupSubTab::draw();
  1426. }
  1427. void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
  1428. {
  1429. if (mGroupID.isNull() || !mMembersList) return;
  1430. if (gc == GC_TITLES || gc == GC_PROPERTIES)
  1431. {
  1432. // Do not care about title or general group properties updates.
  1433. return;
  1434. }
  1435. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1436. if (!gdatap)
  1437. {
  1438. llwarns << "No group data !" << llendl;
  1439. return;
  1440. }
  1441. // Rebuild the members list.
  1442. mMembersList->deleteAllItems();
  1443. // Wait for both all data to be retrieved before displaying anything.
  1444. if (gdatap->isMemberDataComplete() && gdatap->isRoleDataComplete() &&
  1445. gdatap->isRoleMemberDataComplete())
  1446. {
  1447. mMemberProgress = gdatap->mMembers.begin();
  1448. mPendingMemberUpdate = true;
  1449. mHasMatch = false;
  1450. }
  1451. else
  1452. {
  1453. // Build a string with info on retrieval progress.
  1454. std::ostringstream retrieved;
  1455. if (gdatap->isRoleDataComplete() &&
  1456. gdatap->isMemberDataComplete() && !gdatap->mMembers.size())
  1457. {
  1458. // MAINT-5237
  1459. retrieved << "Member list not available.";
  1460. }
  1461. else if (!gdatap->isMemberDataComplete())
  1462. {
  1463. // Still busy retreiving member list.
  1464. retrieved << "Retrieving member list (" << gdatap->mMembers.size()
  1465. << " / " << gdatap->mMemberCount << ")...";
  1466. }
  1467. else if (!gdatap->isRoleDataComplete())
  1468. {
  1469. // Still busy retreiving role list.
  1470. retrieved << "Retrieving role list (" << gdatap->mRoles.size()
  1471. << " / " << gdatap->mRoleCount << ")...";
  1472. }
  1473. else // (!gdatap->isRoleMemberDataComplete())
  1474. {
  1475. // Still busy retreiving role/member mappings.
  1476. retrieved << "Retrieving role member mappings...";
  1477. }
  1478. mMembersList->setEnabled(false);
  1479. mMembersList->addCommentText(retrieved.str());
  1480. }
  1481. }
  1482. void LLPanelGroupMembersSubTab::updateMembers()
  1483. {
  1484. if (!mMembersList) return;
  1485. mPendingMemberUpdate = false;
  1486. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1487. if (!gdatap)
  1488. {
  1489. llwarns << "No group data !" << llendl;
  1490. return;
  1491. }
  1492. // Make sure all data is still complete. Incomplete data may occur if we
  1493. // refresh.
  1494. if (!gdatap->isMemberDataComplete() || !gdatap->isRoleDataComplete() ||
  1495. !gdatap->isRoleMemberDataComplete())
  1496. {
  1497. return;
  1498. }
  1499. mMembersList->setAllowRefresh(false);
  1500. mMembersList->setLazyUpdateInterval(5.f);
  1501. LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
  1502. U32 i;
  1503. LLTimer update_time;
  1504. update_time.setTimerExpirySec(UPDATE_MEMBERS_SECONDS_PER_FRAME);
  1505. for (i = 0; mMemberProgress != end && !update_time.hasExpired();
  1506. ++mMemberProgress, ++i)
  1507. {
  1508. if (!mMemberProgress->second) continue;
  1509. // Do filtering on name if it is already in the cache.
  1510. bool add_member = true;
  1511. LLAvatarName av_name;
  1512. if (LLAvatarNameCache::get(mMemberProgress->first, &av_name))
  1513. {
  1514. // We are only using legacy names here
  1515. std::string fullname = av_name.getLegacyName();
  1516. if (!matchesSearchFilter(fullname))
  1517. {
  1518. add_member = false;
  1519. }
  1520. }
  1521. if (add_member)
  1522. {
  1523. // Build the donated tier string.
  1524. std::ostringstream donated;
  1525. donated << mMemberProgress->second->getContribution() << " m2";
  1526. LLSD row;
  1527. row["id"] = mMemberProgress->first;
  1528. LLSD& columns = row["columns"];
  1529. columns[0]["column"] = "name";
  1530. // value is filled in by name list control
  1531. columns[1]["column"] = "donated";
  1532. columns[1]["value"] = donated.str();
  1533. columns[2]["column"] = "online";
  1534. columns[2]["value"] = mMemberProgress->second->getOnlineStatus();
  1535. columns[2]["font"] = "SANSSERIF_SMALL";
  1536. mMembersList->addElement(row);
  1537. mHasMatch = true;
  1538. }
  1539. }
  1540. if (mMemberProgress == end)
  1541. {
  1542. if (mHasMatch)
  1543. {
  1544. mMembersList->setEnabled(true);
  1545. }
  1546. else if (gdatap->mMembers.size())
  1547. {
  1548. mMembersList->setEnabled(false);
  1549. mMembersList->addCommentText(std::string("No match."));
  1550. }
  1551. mMembersList->setAllowRefresh(true);
  1552. mMembersList->setLazyUpdateInterval(1.f);
  1553. LL_DEBUGS("GroupPanel") << i
  1554. << " members added to the list. No more member pending."
  1555. << LL_ENDL;
  1556. }
  1557. else
  1558. {
  1559. LL_DEBUGS("GroupPanel") << i
  1560. << " members added to the list. There are still pending members."
  1561. << LL_ENDL;
  1562. mPendingMemberUpdate = true;
  1563. }
  1564. // This should clear the other two lists, since nothing is selected.
  1565. handleMemberSelect();
  1566. }
  1567. void LLPanelGroupMembersSubTab::onBanMember(void* userdata)
  1568. {
  1569. LLPanelGroupMembersSubTab* self = (LLPanelGroupMembersSubTab*)userdata;
  1570. if (self)
  1571. {
  1572. self->handleBanMember();
  1573. }
  1574. }
  1575. void LLPanelGroupMembersSubTab::handleBanMember()
  1576. {
  1577. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1578. if (!gdatap)
  1579. {
  1580. llwarns << "Unable to get group data for group " << mGroupID << llendl;
  1581. return;
  1582. }
  1583. std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
  1584. if (selection.empty())
  1585. {
  1586. return;
  1587. }
  1588. uuid_vec_t ban_ids;
  1589. for (U32 i = 0, count = selection.size(); i < count; ++i)
  1590. {
  1591. const LLUUID& ban_id = selection[i]->getUUID();
  1592. ban_ids.emplace_back(ban_id);
  1593. LLGroupBanData ban_data;
  1594. gdatap->createBanEntry(ban_id, ban_data);
  1595. }
  1596. gGroupMgr.sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID,
  1597. LLGroupMgr::BAN_CREATE, ban_ids);
  1598. handleEjectMembers();
  1599. }
  1600. ////////////////////////////
  1601. // LLPanelGroupRolesSubTab
  1602. ////////////////////////////
  1603. //static
  1604. void* LLPanelGroupRolesSubTab::createTab(void* data)
  1605. {
  1606. LLUUID* group_id = (LLUUID*)data;
  1607. return new LLPanelGroupRolesSubTab("panel group roles sub tab", *group_id);
  1608. }
  1609. LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab(const std::string& name,
  1610. const LLUUID& group_id)
  1611. : LLPanelGroupSubTab(name, group_id),
  1612. mRolesList(NULL),
  1613. mAssignedMembersList(NULL),
  1614. mAllowedActionsList(NULL),
  1615. mRoleName(NULL),
  1616. mRoleTitle(NULL),
  1617. mRoleDescription(NULL),
  1618. mMemberVisibleCheck(NULL),
  1619. mDeleteRoleButton(NULL),
  1620. mCreateRoleButton(NULL),
  1621. mFirstOpen(true),
  1622. mHasRoleChange(false)
  1623. {
  1624. }
  1625. bool LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root)
  1626. {
  1627. // Upcast parent so we can ask it for sibling controls.
  1628. LLPanelGroupRoles* parent = (LLPanelGroupRoles*)root;
  1629. if (!parent) return false;
  1630. mHeader = parent->getChild<LLPanel>("roles_header", true, false);
  1631. mFooter = parent->getChild<LLPanel>("roles_footer", true, false);
  1632. mRolesList = parent->getChild<LLScrollListCtrl>("role_list", true, false);
  1633. mAssignedMembersList =
  1634. parent->getChild<LLNameListCtrl>("role_assigned_members", true, false);
  1635. mAllowedActionsList =
  1636. parent->getChild<LLScrollListCtrl>("role_allowed_actions", true,
  1637. false);
  1638. mRoleName = parent->getChild<LLLineEditor>("role_name", true, false);
  1639. mRoleTitle = parent->getChild<LLLineEditor>("role_title", true, false);
  1640. mRoleDescription = parent->getChild<LLTextEditor>("role_description",
  1641. true, false);
  1642. mMemberVisibleCheck =
  1643. parent->getChild<LLCheckBoxCtrl>("role_visible_in_list", true, false);
  1644. if (!mRolesList || !mAssignedMembersList || !mAllowedActionsList ||
  1645. !mRoleName || !mRoleTitle || !mRoleDescription || !mMemberVisibleCheck)
  1646. {
  1647. llwarns << "Missing UI element(s). Aborting panel build." << llendl;
  1648. return false;
  1649. }
  1650. mRemoveEveryoneTxt = getString("cant_delete_role");
  1651. mCreateRoleButton = parent->getChild<LLButton>("role_create", true, false);
  1652. if (mCreateRoleButton)
  1653. {
  1654. mCreateRoleButton->setCallbackUserData(this);
  1655. mCreateRoleButton->setClickedCallback(onCreateRole);
  1656. mCreateRoleButton->setEnabled(false);
  1657. }
  1658. mDeleteRoleButton = parent->getChild<LLButton>("role_delete", true, false);
  1659. if (mDeleteRoleButton)
  1660. {
  1661. mDeleteRoleButton->setCallbackUserData(this);
  1662. mDeleteRoleButton->setClickedCallback(onDeleteRole);
  1663. mDeleteRoleButton->setEnabled(false);
  1664. }
  1665. // Show the member's profile on double click.
  1666. mAssignedMembersList->setDoubleClickCallback(onAssignedMemberDoubleClick);
  1667. mAssignedMembersList->setCallbackUserData(this);
  1668. mRolesList->setCommitOnSelectionChange(true);
  1669. mRolesList->setCommitCallback(onRoleSelect);
  1670. mRolesList->setCallbackUserData(this);
  1671. mMemberVisibleCheck->setCommitCallback(onMemberVisibilityChange);
  1672. mMemberVisibleCheck->setCallbackUserData(this);
  1673. mAllowedActionsList->setCommitOnSelectionChange(true);
  1674. mAllowedActionsList->setCallbackUserData(this);
  1675. mRoleName->setCommitOnFocusLost(true);
  1676. mRoleName->setKeystrokeCallback(onPropertiesKey);
  1677. mRoleName->setCallbackUserData(this);
  1678. mRoleTitle->setCommitOnFocusLost(true);
  1679. mRoleTitle->setKeystrokeCallback(onPropertiesKey);
  1680. mRoleTitle->setCallbackUserData(this);
  1681. mRoleDescription->setCommitOnFocusLost(true);
  1682. mRoleDescription->setCommitCallback(onDescriptionCommit);
  1683. mRoleDescription->setCallbackUserData(this);
  1684. mRoleDescription->setFocusReceivedCallback(onDescriptionFocus, this);
  1685. setFooterEnabled(false);
  1686. return true;
  1687. }
  1688. void LLPanelGroupRolesSubTab::activate()
  1689. {
  1690. LLPanelGroupSubTab::activate();
  1691. if (mRolesList) mRolesList->deselectAllItems();
  1692. if (mAssignedMembersList) mAssignedMembersList->deleteAllItems();
  1693. if (mAllowedActionsList) mAllowedActionsList->deleteAllItems();
  1694. if (mRoleName) mRoleName->clear();
  1695. if (mRoleDescription) mRoleDescription->clear();
  1696. if (mRoleTitle) mRoleTitle->clear();
  1697. setFooterEnabled(false);
  1698. mHasRoleChange = false;
  1699. update(GC_ALL);
  1700. }
  1701. void LLPanelGroupRolesSubTab::deactivate()
  1702. {
  1703. LLPanelGroupSubTab::deactivate();
  1704. mFirstOpen = false;
  1705. }
  1706. bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg)
  1707. {
  1708. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1709. return mHasRoleChange || // Text changed in current role...
  1710. // ... or pending role changed in the group
  1711. (gdatap && gdatap->pendingRoleChanges());
  1712. }
  1713. bool LLPanelGroupRolesSubTab::apply(std::string& mesg)
  1714. {
  1715. saveRoleChanges();
  1716. mFirstOpen = false;
  1717. gGroupMgr.sendGroupRoleChanges(mGroupID);
  1718. notifyObservers();
  1719. return true;
  1720. }
  1721. void LLPanelGroupRolesSubTab::cancel()
  1722. {
  1723. mHasRoleChange = false;
  1724. gGroupMgr.cancelGroupRoleChanges(mGroupID);
  1725. notifyObservers();
  1726. }
  1727. LLSD LLPanelGroupRolesSubTab::createRoleItem(const LLUUID& role_id,
  1728. std::string name,
  1729. std::string title,
  1730. S32 members)
  1731. {
  1732. LLSD row;
  1733. row["id"] = role_id;
  1734. LLSD& columns = row["columns"];
  1735. columns[0]["column"] = "name";
  1736. columns[0]["value"] = name;
  1737. columns[1]["column"] = "title";
  1738. columns[1]["value"] = title;
  1739. columns[2]["column"] = "members";
  1740. columns[2]["value"] = members;
  1741. return row;
  1742. }
  1743. bool LLPanelGroupRolesSubTab::matchesSearchFilter(std::string rolename,
  1744. std::string roletitle)
  1745. {
  1746. // If the search filter is empty, everything passes.
  1747. if (mSearchFilter.empty()) return true;
  1748. LLStringUtil::toLower(rolename);
  1749. LLStringUtil::toLower(roletitle);
  1750. std::string::size_type match_name = rolename.find(mSearchFilter);
  1751. std::string::size_type match_title = roletitle.find(mSearchFilter);
  1752. if (std::string::npos == match_name && std::string::npos == match_title)
  1753. {
  1754. // not found
  1755. return false;
  1756. }
  1757. else
  1758. {
  1759. return true;
  1760. }
  1761. }
  1762. void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
  1763. {
  1764. if (mGroupID.isNull() || !mRolesList) return;
  1765. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1766. if (!gdatap || !gdatap->isRoleDataComplete())
  1767. {
  1768. gGroupMgr.sendGroupRoleDataRequest(mGroupID);
  1769. }
  1770. else
  1771. {
  1772. bool had_selection = false;
  1773. LLUUID last_selected;
  1774. if (mRolesList->getFirstSelected())
  1775. {
  1776. last_selected = mRolesList->getFirstSelected()->getUUID();
  1777. had_selection = true;
  1778. }
  1779. mRolesList->deleteAllItems();
  1780. LLScrollListItem* item = NULL;
  1781. LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
  1782. LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
  1783. for ( ; rit != end; ++rit)
  1784. {
  1785. LLRoleData rd;
  1786. if (gdatap->getRoleData(rit->first,rd))
  1787. {
  1788. if (matchesSearchFilter(rd.mRoleName, rd.mRoleTitle))
  1789. {
  1790. // If this is the everyone role, then EVERYONE is in it.
  1791. S32 members_in_role = rit->first.isNull() ? gdatap->mMembers.size()
  1792. : rit->second->getTotalMembersInRole();
  1793. LLSD row = createRoleItem(rit->first, rd.mRoleName,
  1794. rd.mRoleTitle, members_in_role);
  1795. item = mRolesList->addElement(row,
  1796. rit->first.isNull() ? ADD_TOP
  1797. : ADD_BOTTOM,
  1798. this);
  1799. if (had_selection && (rit->first == last_selected))
  1800. {
  1801. item->setSelected(true);
  1802. }
  1803. }
  1804. }
  1805. else
  1806. {
  1807. llwarns << "No role data for role " << rit->first << llendl;
  1808. }
  1809. }
  1810. mRolesList->sortByColumn(std::string("name"), true);
  1811. if (mCreateRoleButton)
  1812. {
  1813. if (gdatap->mRoles.size() < (U32)MAX_ROLES &&
  1814. gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE))
  1815. {
  1816. mCreateRoleButton->setEnabled(true);
  1817. }
  1818. else
  1819. {
  1820. mCreateRoleButton->setEnabled(false);
  1821. }
  1822. }
  1823. if (had_selection)
  1824. {
  1825. handleRoleSelect();
  1826. }
  1827. else
  1828. {
  1829. if (mAssignedMembersList) mAssignedMembersList->deleteAllItems();
  1830. if (mAllowedActionsList) mAllowedActionsList->deleteAllItems();
  1831. if (mRoleName) mRoleName->clear();
  1832. if (mRoleDescription) mRoleDescription->clear();
  1833. if (mRoleTitle) mRoleTitle->clear();
  1834. setFooterEnabled(false);
  1835. if (mDeleteRoleButton) mDeleteRoleButton->setEnabled(false);
  1836. }
  1837. }
  1838. #if 0
  1839. if (!mFirstOpen)
  1840. {
  1841. if (!gdatap || !gdatap->isMemberDataComplete())
  1842. {
  1843. gGroupMgr.sendCapGroupMembersRequest(mGroupID);
  1844. }
  1845. if (!gdatap || !gdatap->isRoleMemberDataComplete())
  1846. {
  1847. gGroupMgr.sendGroupRoleMembersRequest(mGroupID);
  1848. }
  1849. }
  1850. #endif
  1851. if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc) &&
  1852. gdatap && gdatap->isMemberDataComplete() &&
  1853. gdatap->isRoleMemberDataComplete())
  1854. {
  1855. buildMembersList();
  1856. }
  1857. }
  1858. //static
  1859. void LLPanelGroupRolesSubTab::onAssignedMemberDoubleClick(void* userdata)
  1860. {
  1861. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  1862. if (self && self->mAssignedMembersList)
  1863. {
  1864. LLScrollListItem* selected =
  1865. self->mAssignedMembersList->getFirstSelected();
  1866. if (selected)
  1867. {
  1868. LLFloaterAvatarInfo::showFromDirectory(selected->getUUID());
  1869. }
  1870. }
  1871. }
  1872. //static
  1873. void LLPanelGroupRolesSubTab::onRoleSelect(LLUICtrl* ctrl, void* userdata)
  1874. {
  1875. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  1876. if (self)
  1877. {
  1878. self->handleRoleSelect();
  1879. }
  1880. }
  1881. void LLPanelGroupRolesSubTab::handleRoleSelect()
  1882. {
  1883. if (!mAssignedMembersList || !mAllowedActionsList) return;
  1884. mAssignedMembersList->deleteAllItems();
  1885. mAllowedActionsList->deleteAllItems();
  1886. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1887. if (!gdatap)
  1888. {
  1889. llwarns << "No group data !" << llendl;
  1890. return;
  1891. }
  1892. saveRoleChanges();
  1893. // Check if there is anything selected.
  1894. LLScrollListItem* item = mRolesList->getFirstSelected();
  1895. if (!item)
  1896. {
  1897. setFooterEnabled(false);
  1898. return;
  1899. }
  1900. setFooterEnabled(true);
  1901. bool can_delete = true;
  1902. LLRoleData rd;
  1903. if (gdatap->getRoleData(item->getUUID(), rd))
  1904. {
  1905. bool is_owner_role = (gdatap->mOwnerRole == item->getUUID());
  1906. if (is_owner_role)
  1907. {
  1908. // you can't delete the owner role
  1909. can_delete = false;
  1910. }
  1911. if (mRoleName)
  1912. {
  1913. mRoleName->setText(rd.mRoleName);
  1914. mRoleName->setEnabled(!is_owner_role &&
  1915. gAgent.hasPowerInGroup(mGroupID,
  1916. GP_ROLE_PROPERTIES));
  1917. }
  1918. if (mRoleTitle)
  1919. {
  1920. mRoleTitle->setText(rd.mRoleTitle);
  1921. mRoleTitle->setEnabled(gAgent.hasPowerInGroup(mGroupID,
  1922. GP_ROLE_PROPERTIES));
  1923. }
  1924. if (mRoleDescription)
  1925. {
  1926. mRoleDescription->setText(rd.mRoleDescription);
  1927. mRoleDescription->setEnabled(gAgent.hasPowerInGroup(mGroupID,
  1928. GP_ROLE_PROPERTIES));
  1929. }
  1930. if (mAllowedActionsList)
  1931. {
  1932. mAllowedActionsList->setEnabled(gAgent.hasPowerInGroup(mGroupID,
  1933. GP_ROLE_CHANGE_ACTIONS));
  1934. buildActionsList(mAllowedActionsList, rd.mRolePowers, 0LL,
  1935. mActionIcons, onActionCheck, true, false,
  1936. is_owner_role);
  1937. }
  1938. if (mMemberVisibleCheck)
  1939. {
  1940. mMemberVisibleCheck->set((rd.mRolePowers & GP_MEMBER_VISIBLE_IN_DIR) == GP_MEMBER_VISIBLE_IN_DIR);
  1941. if (is_owner_role)
  1942. {
  1943. mMemberVisibleCheck->setEnabled(false);
  1944. }
  1945. else
  1946. {
  1947. mMemberVisibleCheck->setEnabled(gAgent.hasPowerInGroup(mGroupID,
  1948. GP_ROLE_PROPERTIES));
  1949. }
  1950. }
  1951. if (item->getUUID().isNull())
  1952. {
  1953. // Everyone role, can't edit description or name or delete
  1954. if (mRoleDescription) mRoleDescription->setEnabled(false);
  1955. if (mRoleName) mRoleName->setEnabled(false);
  1956. can_delete = false;
  1957. }
  1958. }
  1959. else
  1960. {
  1961. mAssignedMembersList->deleteAllItems();
  1962. mAllowedActionsList->deleteAllItems();
  1963. if (mRolesList) mRolesList->deselectAllItems();
  1964. if (mRoleName) mRoleName->clear();
  1965. if (mRoleDescription) mRoleDescription->clear();
  1966. if (mRoleTitle) mRoleTitle->clear();
  1967. setFooterEnabled(false);
  1968. can_delete = false;
  1969. }
  1970. mSelectedRole = item->getUUID();
  1971. buildMembersList();
  1972. can_delete = can_delete && gAgent.hasPowerInGroup(mGroupID,
  1973. GP_ROLE_DELETE);
  1974. if (mDeleteRoleButton) mDeleteRoleButton->setEnabled(can_delete);
  1975. }
  1976. void LLPanelGroupRolesSubTab::buildMembersList()
  1977. {
  1978. if (!mAssignedMembersList || !mRolesList) return;
  1979. mAssignedMembersList->deleteAllItems();
  1980. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  1981. if (!gdatap)
  1982. {
  1983. llwarns << "No group data !" << llendl;
  1984. return;
  1985. }
  1986. // Check if there is anything selected.
  1987. LLScrollListItem* item = mRolesList->getFirstSelected();
  1988. if (!item) return;
  1989. if (item->getUUID().isNull())
  1990. {
  1991. // Special cased 'Everyone' role
  1992. LLGroupMgrGroupData::member_list_t::iterator mit = gdatap->mMembers.begin();
  1993. LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
  1994. for ( ; mit != end; ++mit)
  1995. {
  1996. mAssignedMembersList->addNameItem(mit->first);
  1997. }
  1998. }
  1999. else
  2000. {
  2001. LLGroupMgrGroupData::role_list_t::iterator rit;
  2002. rit = gdatap->mRoles.find(item->getUUID());
  2003. if (rit != gdatap->mRoles.end())
  2004. {
  2005. LLGroupRoleData* rdatap = rit->second;
  2006. if (rdatap)
  2007. {
  2008. uuid_vec_t::const_iterator mit = rdatap->getMembersBegin();
  2009. uuid_vec_t::const_iterator end = rdatap->getMembersEnd();
  2010. for ( ; mit != end; ++mit)
  2011. {
  2012. mAssignedMembersList->addNameItem(*mit);
  2013. }
  2014. }
  2015. }
  2016. }
  2017. }
  2018. //static
  2019. void LLPanelGroupRolesSubTab::onActionCheck(LLUICtrl* ctrl, void* userdata)
  2020. {
  2021. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  2022. LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)ctrl;
  2023. if (check && self)
  2024. {
  2025. self->handleActionCheck(check);
  2026. }
  2027. }
  2028. struct ActionCBData
  2029. {
  2030. LLPanelGroupRolesSubTab* mSelf;
  2031. LLCheckBoxCtrl* mCheck;
  2032. };
  2033. void LLPanelGroupRolesSubTab::handleActionCheck(LLCheckBoxCtrl* check,
  2034. bool force)
  2035. {
  2036. if (!mAssignedMembersList || !mRolesList) return;
  2037. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2038. if (!gdatap)
  2039. {
  2040. llwarns << "No group data !" << llendl;
  2041. return;
  2042. }
  2043. LLScrollListItem* action_item = mAllowedActionsList->getFirstSelected();
  2044. if (!action_item)
  2045. {
  2046. return;
  2047. }
  2048. LLScrollListItem* role_item = mRolesList->getFirstSelected();
  2049. if (!role_item)
  2050. {
  2051. return;
  2052. }
  2053. LLUUID role_id = role_item->getUUID();
  2054. LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata();
  2055. U64 power = rap->mPowerBit;
  2056. LLRoleData rd;
  2057. LLSD args;
  2058. bool is_enabling_ability = check->get();
  2059. if (is_enabling_ability && !force &&
  2060. (GP_ROLE_ASSIGN_MEMBER == power || GP_ROLE_CHANGE_ACTIONS == power))
  2061. {
  2062. // Uncheck the item, for now. It will be checked if they click 'Yes',
  2063. // below.
  2064. check->set(false);
  2065. if (gdatap->getRoleData(role_id, rd))
  2066. {
  2067. args["ACTION_NAME"] = rap->mDescription;
  2068. args["ROLE_NAME"] = rd.mRoleName;
  2069. mHasModal = true;
  2070. std::string warning = "AssignDangerousActionWarning";
  2071. if (GP_ROLE_CHANGE_ACTIONS == power)
  2072. {
  2073. warning = "AssignDangerousAbilityWarning";
  2074. }
  2075. gNotifications.add(warning, args, LLSD(),
  2076. boost::bind(&LLPanelGroupRolesSubTab::addActionCB,
  2077. this, _1, _2, check));
  2078. }
  2079. else
  2080. {
  2081. llwarns << "Unable to look up role information for role id: "
  2082. << role_id << llendl;
  2083. }
  2084. }
  2085. if (power == GP_GROUP_BAN_ACCESS)
  2086. {
  2087. std::string warning = is_enabling_ability ? "AssignBanAbilityWarning"
  2088. : "RemoveBanAbilityWarning";
  2089. // Get role data for both GP_ROLE_REMOVE_MEMBER and GP_MEMBER_EJECT.
  2090. // Add description and role name to LLSD. Pop up dialog saying "You
  2091. // also granted these other abilities when you did this!"
  2092. if (gdatap->getRoleData(role_id, rd))
  2093. {
  2094. args["ACTION_NAME"] = rap->mDescription;
  2095. args["ROLE_NAME"] = rd.mRoleName;
  2096. mHasModal = true;
  2097. std::vector<LLScrollListItem*> all_data =
  2098. mAllowedActionsList->getAllData();
  2099. for (U32 i = 0, count = all_data.size(); i < count; ++i)
  2100. {
  2101. LLRoleAction* adp = (LLRoleAction*)all_data[i]->getUserdata();
  2102. if (!adp) continue; // Paranoia
  2103. if (adp->mPowerBit == GP_MEMBER_EJECT)
  2104. {
  2105. args["ACTION_NAME_2"] = adp->mDescription;
  2106. }
  2107. else if(adp->mPowerBit == GP_ROLE_REMOVE_MEMBER)
  2108. {
  2109. args["ACTION_NAME_3"] = adp->mDescription;
  2110. }
  2111. }
  2112. gNotifications.add(warning, args);
  2113. }
  2114. else
  2115. {
  2116. llwarns << "Unable to look up role information for role id: "
  2117. << role_id << llendl;
  2118. }
  2119. LLGroupMgrGroupData::role_list_t::iterator rit;
  2120. rit = gdatap->mRoles.find(role_id);
  2121. U64 current_role_powers = GP_NO_POWERS;
  2122. if (rit != gdatap->mRoles.end())
  2123. {
  2124. current_role_powers = rit->second->getRoleData().mRolePowers;
  2125. }
  2126. if (is_enabling_ability)
  2127. {
  2128. power |= GP_ROLE_REMOVE_MEMBER | GP_MEMBER_EJECT;
  2129. current_role_powers |= power;
  2130. }
  2131. else
  2132. {
  2133. current_role_powers &= ~GP_GROUP_BAN_ACCESS;
  2134. }
  2135. mAllowedActionsList->deleteAllItems();
  2136. buildActionsList(mAllowedActionsList,
  2137. current_role_powers, current_role_powers,
  2138. mActionIcons, onActionCheck, true, false, false);
  2139. }
  2140. // Adding non-specific ability to role
  2141. if (is_enabling_ability)
  2142. {
  2143. gdatap->addRolePower(role_id, power);
  2144. }
  2145. else
  2146. {
  2147. gdatap->removeRolePower(role_id, power);
  2148. }
  2149. mHasRoleChange = true;
  2150. notifyObservers();
  2151. }
  2152. bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification,
  2153. const LLSD& response,
  2154. LLCheckBoxCtrl* check)
  2155. {
  2156. if (!check) return false;
  2157. mHasModal = false;
  2158. S32 option = LLNotification::getSelectedOption(notification, response);
  2159. if (0 == option)
  2160. {
  2161. // User clicked "Yes"
  2162. check->set(true);
  2163. constexpr bool force_add = true;
  2164. handleActionCheck(check, force_add);
  2165. }
  2166. return false;
  2167. }
  2168. //static
  2169. void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl,
  2170. void* userdata)
  2171. {
  2172. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  2173. if (self)
  2174. {
  2175. self->mHasRoleChange = true;
  2176. self->notifyObservers();
  2177. }
  2178. }
  2179. //static
  2180. void LLPanelGroupRolesSubTab::onDescriptionFocus(LLFocusableElement* ctrl,
  2181. void* userdata)
  2182. {
  2183. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  2184. if (self)
  2185. {
  2186. self->mHasRoleChange = true;
  2187. self->notifyObservers();
  2188. }
  2189. }
  2190. //static
  2191. void LLPanelGroupRolesSubTab::onDescriptionCommit(LLUICtrl* ctrl,
  2192. void* userdata)
  2193. {
  2194. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  2195. if (self)
  2196. {
  2197. self->mHasRoleChange = true;
  2198. self->notifyObservers();
  2199. }
  2200. }
  2201. //static
  2202. void LLPanelGroupRolesSubTab::onMemberVisibilityChange(LLUICtrl* ctrl,
  2203. void* userdata)
  2204. {
  2205. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  2206. LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)ctrl;
  2207. if (check && self)
  2208. {
  2209. self->handleMemberVisibilityChange(check->get());
  2210. }
  2211. }
  2212. void LLPanelGroupRolesSubTab::handleMemberVisibilityChange(bool value)
  2213. {
  2214. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2215. if (!gdatap)
  2216. {
  2217. llwarns << "No group data !" << llendl;
  2218. return;
  2219. }
  2220. LLScrollListItem* role_item = mRolesList->getFirstSelected();
  2221. if (!role_item)
  2222. {
  2223. return;
  2224. }
  2225. if (value)
  2226. {
  2227. gdatap->addRolePower(role_item->getUUID(), GP_MEMBER_VISIBLE_IN_DIR);
  2228. }
  2229. else
  2230. {
  2231. gdatap->removeRolePower(role_item->getUUID(),
  2232. GP_MEMBER_VISIBLE_IN_DIR);
  2233. }
  2234. }
  2235. //static
  2236. void LLPanelGroupRolesSubTab::onCreateRole(void* userdata)
  2237. {
  2238. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  2239. if (self)
  2240. {
  2241. self->handleCreateRole();
  2242. }
  2243. }
  2244. void LLPanelGroupRolesSubTab::handleCreateRole()
  2245. {
  2246. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2247. if (!gdatap || !mRolesList) return;
  2248. LLUUID new_role_id;
  2249. new_role_id.generate();
  2250. LLRoleData rd;
  2251. rd.mRoleName = "New Role";
  2252. gdatap->createRole(new_role_id,rd);
  2253. mRolesList->deselectAllItems(true);
  2254. LLSD row;
  2255. row["id"] = new_role_id;
  2256. row["columns"][0]["column"] = "name";
  2257. row["columns"][0]["value"] = rd.mRoleName;
  2258. mRolesList->addElement(row, ADD_BOTTOM, this);
  2259. mRolesList->selectByID(new_role_id);
  2260. // put focus on name field and select its contents
  2261. if (mRoleName)
  2262. {
  2263. mRoleName->setFocus(true);
  2264. mRoleName->onTabInto();
  2265. gFocusMgr.triggerFocusFlash();
  2266. }
  2267. notifyObservers();
  2268. }
  2269. //static
  2270. void LLPanelGroupRolesSubTab::onDeleteRole(void* userdata)
  2271. {
  2272. LLPanelGroupRolesSubTab* self = (LLPanelGroupRolesSubTab*)userdata;
  2273. if (self)
  2274. {
  2275. self->handleDeleteRole();
  2276. }
  2277. }
  2278. void LLPanelGroupRolesSubTab::handleDeleteRole()
  2279. {
  2280. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2281. if (!gdatap || !mRolesList) return;
  2282. LLScrollListItem* role_item = mRolesList->getFirstSelected();
  2283. if (!role_item)
  2284. {
  2285. return;
  2286. }
  2287. if (role_item->getUUID().isNull() ||
  2288. role_item->getUUID() == gdatap->mOwnerRole)
  2289. {
  2290. LLSD args;
  2291. args["MESSAGE"] = mRemoveEveryoneTxt;
  2292. gNotifications.add("GenericAlert", args);
  2293. return;
  2294. }
  2295. gdatap->deleteRole(role_item->getUUID());
  2296. mRolesList->deleteSingleItem(mRolesList->getFirstSelectedIndex());
  2297. mRolesList->selectFirstItem();
  2298. notifyObservers();
  2299. }
  2300. void LLPanelGroupRolesSubTab::saveRoleChanges()
  2301. {
  2302. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2303. if (gdatap && mRolesList && mHasRoleChange)
  2304. {
  2305. LLRoleData rd;
  2306. if (!gdatap->getRoleData(mSelectedRole,rd)) return;
  2307. rd.mRoleName = mRoleName->getText();
  2308. rd.mRoleDescription = mRoleDescription->getText();
  2309. rd.mRoleTitle = mRoleTitle->getText();
  2310. gdatap->setRoleData(mSelectedRole,rd);
  2311. mRolesList->deleteSingleItem(mRolesList->getItemIndex(mSelectedRole));
  2312. LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,0);
  2313. LLScrollListItem* item = mRolesList->addElement(row, ADD_BOTTOM, this);
  2314. item->setSelected(true);
  2315. mHasRoleChange = false;
  2316. }
  2317. }
  2318. ////////////////////////////
  2319. // LLPanelGroupActionsSubTab
  2320. ////////////////////////////
  2321. //static
  2322. void* LLPanelGroupActionsSubTab::createTab(void* data)
  2323. {
  2324. LLUUID* group_id = (LLUUID*)data;
  2325. return new LLPanelGroupActionsSubTab("panel group actions sub tab",
  2326. *group_id);
  2327. }
  2328. LLPanelGroupActionsSubTab::LLPanelGroupActionsSubTab(const std::string& name,
  2329. const LLUUID& group_id)
  2330. : LLPanelGroupSubTab(name, group_id)
  2331. {
  2332. }
  2333. bool LLPanelGroupActionsSubTab::postBuildSubTab(LLView* root)
  2334. {
  2335. // Upcast parent so we can ask it for sibling controls.
  2336. LLPanelGroupRoles* parent = (LLPanelGroupRoles*) root;
  2337. mHeader = parent->getChild<LLPanel>("actions_header", true, false);
  2338. mFooter = parent->getChild<LLPanel>("actions_footer", true, false);
  2339. mActionDescription = parent->getChild<LLTextEditor>("action_description",
  2340. true, false);
  2341. if (!mActionDescription) return false;
  2342. mActionList = parent->getChild<LLScrollListCtrl>("action_list",
  2343. true, false);
  2344. if (!mActionList) return false;
  2345. mActionRoles = parent->getChild<LLScrollListCtrl>("action_roles",
  2346. true, false);
  2347. if (!mActionRoles) return false;
  2348. mActionMembers = parent->getChild<LLNameListCtrl>("action_members",
  2349. true, false);
  2350. if (!mActionMembers) return false;
  2351. mActionList->setCallbackUserData(this);
  2352. mActionList->setCommitOnSelectionChange(true);
  2353. mActionList->setCommitCallback(onActionSelect);
  2354. mActionMembers->setCallbackUserData(this);
  2355. mActionRoles->setCallbackUserData(this);
  2356. update(GC_ALL);
  2357. return true;
  2358. }
  2359. void LLPanelGroupActionsSubTab::activate()
  2360. {
  2361. LLPanelGroupSubTab::activate();
  2362. if (mActionList) mActionList->deselectAllItems();
  2363. if (mActionMembers) mActionMembers->deleteAllItems();
  2364. if (mActionRoles) mActionRoles->deleteAllItems();
  2365. if (mActionDescription) mActionDescription->clear();
  2366. }
  2367. void LLPanelGroupActionsSubTab::deactivate()
  2368. {
  2369. LLPanelGroupSubTab::deactivate();
  2370. }
  2371. bool LLPanelGroupActionsSubTab::needsApply(std::string& mesg)
  2372. {
  2373. return false;
  2374. }
  2375. bool LLPanelGroupActionsSubTab::apply(std::string& mesg)
  2376. {
  2377. return true;
  2378. }
  2379. void LLPanelGroupActionsSubTab::update(LLGroupChange gc)
  2380. {
  2381. if (mGroupID.isNull()) return;
  2382. if (mActionList) mActionList->deselectAllItems();
  2383. if (mActionMembers) mActionMembers->deleteAllItems();
  2384. if (mActionRoles) mActionRoles->deleteAllItems();
  2385. if (mActionDescription) mActionDescription->clear();
  2386. mActionList->deleteAllItems();
  2387. buildActionsList(mActionList, GP_ALL_POWERS, GP_ALL_POWERS, mActionIcons,
  2388. NULL, false, true, false);
  2389. }
  2390. //static
  2391. void LLPanelGroupActionsSubTab::onActionSelect(LLUICtrl* scroll, void* data)
  2392. {
  2393. LLPanelGroupActionsSubTab* self = (LLPanelGroupActionsSubTab*)data;
  2394. if (self)
  2395. {
  2396. self->handleActionSelect();
  2397. }
  2398. }
  2399. void LLPanelGroupActionsSubTab::handleActionSelect()
  2400. {
  2401. if (!mActionMembers || !mActionRoles || !mActionDescription) return;
  2402. mActionMembers->deleteAllItems();
  2403. mActionRoles->deleteAllItems();
  2404. setFooterEnabled(true);
  2405. std::vector<LLScrollListItem*> selection = mActionList->getAllSelected();
  2406. if (selection.empty()) return;
  2407. U64 power_mask = GP_NO_POWERS;
  2408. LLRoleAction* rap;
  2409. for (U32 i = 0, count = selection.size(); i < count; ++i)
  2410. {
  2411. rap = (LLRoleAction*)selection[i]->getUserdata();
  2412. power_mask |= rap->mPowerBit;
  2413. }
  2414. if (selection.size() == 1)
  2415. {
  2416. LLScrollListItem* item = selection[0];
  2417. rap = (LLRoleAction*)(item->getUserdata());
  2418. if (rap->mLongDescription.empty())
  2419. {
  2420. mActionDescription->setText(rap->mDescription);
  2421. }
  2422. else
  2423. {
  2424. mActionDescription->setText(rap->mLongDescription);
  2425. }
  2426. }
  2427. else
  2428. {
  2429. mActionDescription->clear();
  2430. }
  2431. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2432. if (!gdatap) return;
  2433. if (gdatap->isMemberDataComplete())
  2434. {
  2435. LLGroupMemberData* gmd;
  2436. for (LLGroupMgrGroupData::member_list_t::iterator
  2437. it = gdatap->mMembers.begin(),
  2438. end = gdatap->mMembers.end();
  2439. it != end; ++it)
  2440. {
  2441. gmd = it->second;
  2442. if (gmd && (gmd->getAgentPowers() & power_mask) == power_mask)
  2443. {
  2444. mActionMembers->addNameItem(gmd->getID());
  2445. }
  2446. }
  2447. }
  2448. else
  2449. {
  2450. gGroupMgr.sendCapGroupMembersRequest(mGroupID);
  2451. }
  2452. if (gdatap->isRoleDataComplete())
  2453. {
  2454. LLGroupRoleData* rmd;
  2455. for (LLGroupMgrGroupData::role_list_t::iterator
  2456. it = gdatap->mRoles.begin(),
  2457. end = gdatap->mRoles.end();
  2458. it != end; ++it)
  2459. {
  2460. rmd = it->second;
  2461. if (rmd &&
  2462. (rmd->getRoleData().mRolePowers & power_mask) == power_mask)
  2463. {
  2464. mActionRoles->addSimpleElement(rmd->getRoleData().mRoleName);
  2465. }
  2466. }
  2467. }
  2468. else
  2469. {
  2470. gGroupMgr.sendGroupRoleDataRequest(mGroupID);
  2471. }
  2472. }
  2473. ////////////////////////////
  2474. // LLPanelGroupBanListSubTab
  2475. ////////////////////////////
  2476. //static
  2477. void* LLPanelGroupBanListSubTab::createTab(void* data)
  2478. {
  2479. LLUUID* group_id = (LLUUID*)data;
  2480. return new LLPanelGroupBanListSubTab("panel_group_banlist_subtab",
  2481. *group_id);
  2482. }
  2483. LLPanelGroupBanListSubTab::LLPanelGroupBanListSubTab(const std::string& name,
  2484. const LLUUID& group_id)
  2485. : LLPanelGroupSubTab(name, group_id),
  2486. mBanList(NULL),
  2487. mCreateBanButton(NULL),
  2488. mDeleteBanButton(NULL),
  2489. mRefreshBanListButton(NULL),
  2490. mBanNotSupportedText(NULL),
  2491. mBanCountText(NULL),
  2492. mLastUpdate(0.f)
  2493. {
  2494. }
  2495. bool LLPanelGroupBanListSubTab::postBuildSubTab(LLView* root)
  2496. {
  2497. // Upcast parent so we can ask it for sibling controls.
  2498. LLPanelGroupRoles* parent = (LLPanelGroupRoles*) root;
  2499. mHeader = parent->getChild<LLPanel>("banlist_header", true, false);
  2500. mFooter = parent->getChild<LLPanel>("banlist_footer", true, false);
  2501. mBanList = parent->getChild<LLNameListCtrl>("ban_list", true, false);
  2502. mCreateBanButton = parent->getChild<LLButton>("ban_create", true, false);
  2503. mDeleteBanButton = parent->getChild<LLButton>("ban_delete", true, false);
  2504. mRefreshBanListButton = parent->getChild<LLButton>("ban_refresh",
  2505. true, false);
  2506. if (!mBanList || !mCreateBanButton || !mDeleteBanButton ||
  2507. !mRefreshBanListButton)
  2508. {
  2509. return false;
  2510. }
  2511. mBanList->setCommitCallback(onBanEntrySelect);
  2512. mBanList->setCallbackUserData(this);
  2513. mBanList->setCommitOnSelectionChange(true);
  2514. // Show the member's profile on double click.
  2515. mBanList->setDoubleClickCallback(onBanListMemberDoubleClick);
  2516. mBanList->setCallbackUserData(this);
  2517. mCreateBanButton->setClickedCallback(onCreateBanEntry);
  2518. mCreateBanButton->setCallbackUserData(this);
  2519. mCreateBanButton->setEnabled(false);
  2520. mDeleteBanButton->setClickedCallback(onDeleteBanEntry);
  2521. mDeleteBanButton->setCallbackUserData(this);
  2522. mDeleteBanButton->setEnabled(false);
  2523. mRefreshBanListButton->setClickedCallback(onRefreshBanList);
  2524. mRefreshBanListButton->setCallbackUserData(this);
  2525. mRefreshBanListButton->setEnabled(false);
  2526. mBanNotSupportedText = parent->getChild<LLTextBox>("ban_not_supported",
  2527. true, false);
  2528. mBanCountText = parent->getChild<LLTextBox>("ban_count", true, false);
  2529. if (mBanCountText)
  2530. {
  2531. mBanCountString = mBanCountText->getText();
  2532. }
  2533. setBanCount(0);
  2534. populateBanList();
  2535. setFooterEnabled(false);
  2536. return true;
  2537. }
  2538. void LLPanelGroupBanListSubTab::draw()
  2539. {
  2540. constexpr F32 UPDATE_INTERVAL = 2.f;
  2541. if (gFrameTimeSeconds - mLastUpdate > UPDATE_INTERVAL)
  2542. {
  2543. bool got_cap = gAgent.hasRegionCapability("GroupAPIv1");
  2544. if (mBanList && got_cap != mBanList->getEnabled())
  2545. {
  2546. populateBanList();
  2547. }
  2548. if (mBanNotSupportedText)
  2549. {
  2550. mBanNotSupportedText->setVisible(!got_cap);
  2551. mBanNotSupportedText->setEnabled(!got_cap);
  2552. }
  2553. if (mBanCountText)
  2554. {
  2555. mBanCountText->setVisible(got_cap);
  2556. mBanCountText->setEnabled(got_cap);
  2557. }
  2558. mLastUpdate = gFrameTimeSeconds;
  2559. }
  2560. LLPanelGroupSubTab::draw();
  2561. }
  2562. void LLPanelGroupBanListSubTab::activate()
  2563. {
  2564. LLPanelGroupSubTab::activate();
  2565. if (mBanList)
  2566. {
  2567. mBanList->deselectAllItems();
  2568. }
  2569. if (mDeleteBanButton)
  2570. {
  2571. mDeleteBanButton->setEnabled(false);
  2572. }
  2573. if (mCreateBanButton)
  2574. {
  2575. mCreateBanButton->setEnabled(gAgent.hasPowerInGroup(mGroupID,
  2576. GP_GROUP_BAN_ACCESS));
  2577. }
  2578. // BAKER: Should I really request everytime activate() is called ?
  2579. // Perhaps I should only do it on a force refresh, or if an action
  2580. // on the list happens...
  2581. // Because it's not going to live-update the list anyway... You'd
  2582. // have to refresh if you wanted to see someone else's additions
  2583. // anyway...
  2584. gGroupMgr.sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID);
  2585. setFooterEnabled(false);
  2586. update(GC_ALL);
  2587. }
  2588. void LLPanelGroupBanListSubTab::update(LLGroupChange gc)
  2589. {
  2590. populateBanList();
  2591. }
  2592. void LLPanelGroupBanListSubTab::onBanEntrySelect(LLUICtrl* ctrl,
  2593. void* user_data)
  2594. {
  2595. LLPanelGroupBanListSubTab* self = (LLPanelGroupBanListSubTab*)user_data;
  2596. if (self)
  2597. {
  2598. self->handleBanEntrySelect();
  2599. }
  2600. }
  2601. void LLPanelGroupBanListSubTab::handleBanEntrySelect()
  2602. {
  2603. if (mDeleteBanButton &&
  2604. gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
  2605. {
  2606. mDeleteBanButton->setEnabled(true);
  2607. }
  2608. }
  2609. void LLPanelGroupBanListSubTab::onCreateBanEntry(void* user_data)
  2610. {
  2611. LLPanelGroupBanListSubTab* self = (LLPanelGroupBanListSubTab*)user_data;
  2612. if (self)
  2613. {
  2614. self->handleCreateBanEntry();
  2615. }
  2616. }
  2617. void LLPanelGroupBanListSubTab::handleCreateBanEntry()
  2618. {
  2619. LLFloaterGroupBulkBan::showForGroup(mGroupID, NULL, this);
  2620. }
  2621. void LLPanelGroupBanListSubTab::onDeleteBanEntry(void* user_data)
  2622. {
  2623. LLPanelGroupBanListSubTab* self = (LLPanelGroupBanListSubTab*)user_data;
  2624. if (self)
  2625. {
  2626. self->handleDeleteBanEntry();
  2627. }
  2628. }
  2629. void LLPanelGroupBanListSubTab::handleDeleteBanEntry()
  2630. {
  2631. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2632. if (!gdatap)
  2633. {
  2634. llwarns << "Unable to get group data for group " << mGroupID << llendl;
  2635. return;
  2636. }
  2637. std::vector<LLScrollListItem*> selection = mBanList->getAllSelected();
  2638. if (selection.empty())
  2639. {
  2640. return;
  2641. }
  2642. bool can_ban_members = false;
  2643. if (gAgent.isGodlikeWithoutAdminMenuFakery() ||
  2644. gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
  2645. {
  2646. can_ban_members = true;
  2647. }
  2648. // Owners can ban anyone in the group.
  2649. LLGroupMgrGroupData::member_list_t::iterator mi;
  2650. mi = gdatap->mMembers.find(gAgentID);
  2651. if (mi != gdatap->mMembers.end())
  2652. {
  2653. LLGroupMemberData* member_data = mi->second;
  2654. if (member_data && member_data->isInRole(gdatap->mOwnerRole))
  2655. {
  2656. can_ban_members = true;
  2657. }
  2658. }
  2659. if (!can_ban_members)
  2660. {
  2661. return;
  2662. }
  2663. uuid_vec_t ban_ids;
  2664. for (U32 i = 0, count = selection.size(); i < count; ++i)
  2665. {
  2666. const LLUUID& ban_id = selection[i]->getUUID();
  2667. ban_ids.emplace_back(ban_id);
  2668. gdatap->removeBanEntry(ban_id);
  2669. if (mBanList)
  2670. {
  2671. mBanList->removeNameItem(ban_id);
  2672. }
  2673. // Removing an item removes the selection, we should not be able to
  2674. // click the button anymore until we reselect another entry.
  2675. if (mDeleteBanButton)
  2676. {
  2677. mDeleteBanButton->setEnabled(false);
  2678. }
  2679. }
  2680. gGroupMgr.sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID,
  2681. LLGroupMgr::BAN_DELETE, ban_ids);
  2682. setBanCount(gdatap->mBanList.size());
  2683. }
  2684. void LLPanelGroupBanListSubTab::onRefreshBanList(void* user_data)
  2685. {
  2686. LLPanelGroupBanListSubTab* self = (LLPanelGroupBanListSubTab*)user_data;
  2687. if (self)
  2688. {
  2689. self->handleRefreshBanList();
  2690. }
  2691. }
  2692. void LLPanelGroupBanListSubTab::handleRefreshBanList()
  2693. {
  2694. mRefreshBanListButton->setEnabled(false);
  2695. gGroupMgr.sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID);
  2696. }
  2697. void LLPanelGroupBanListSubTab::populateBanList()
  2698. {
  2699. if (!gAgent.hasRegionCapability("GroupAPIv1"))
  2700. {
  2701. if (mRefreshBanListButton)
  2702. {
  2703. mRefreshBanListButton->setEnabled(false);
  2704. }
  2705. if (mBanList)
  2706. {
  2707. mBanList->deleteAllItems();
  2708. mBanList->setEnabled(false);
  2709. }
  2710. if (mCreateBanButton)
  2711. {
  2712. mCreateBanButton->setEnabled(false);
  2713. }
  2714. if (mDeleteBanButton)
  2715. {
  2716. mDeleteBanButton->setEnabled(false);
  2717. }
  2718. return;
  2719. }
  2720. if (mCreateBanButton)
  2721. {
  2722. mCreateBanButton->setEnabled(gAgent.hasPowerInGroup(mGroupID,
  2723. GP_GROUP_BAN_ACCESS));
  2724. }
  2725. if (mRefreshBanListButton)
  2726. {
  2727. mRefreshBanListButton->setEnabled(true);
  2728. }
  2729. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
  2730. if (!gdatap)
  2731. {
  2732. llwarns << "Unable to get group data for group " << mGroupID << llendl;
  2733. return;
  2734. }
  2735. if (!mBanList) return;
  2736. mBanList->setEnabled(true);
  2737. mBanList->deleteAllItems();
  2738. for (LLGroupMgrGroupData::ban_list_t::const_iterator
  2739. it = gdatap->mBanList.begin(), end = gdatap->mBanList.end();
  2740. it != end; ++it)
  2741. {
  2742. LLSD row;
  2743. row["id"] = it->first;
  2744. LLSD& columns = row["columns"];
  2745. columns[0]["column"] = "name";
  2746. // Value is filled in by name list control
  2747. LLGroupBanData bd = it->second;
  2748. columns[1]["column"] = "bandate";
  2749. columns[1]["value"] = bd.mBanDate.asTimeStamp();
  2750. mBanList->addElement(row);
  2751. }
  2752. #if 0
  2753. mMembersList->setAllowRefresh(true);
  2754. mMembersList->setLazyUpdateInterval(2.f);
  2755. #endif
  2756. setBanCount(gdatap->mBanList.size());
  2757. }
  2758. void LLPanelGroupBanListSubTab::setBanCount(S32 count)
  2759. {
  2760. if (mBanCountText)
  2761. {
  2762. mBanCountText->setText(mBanCountString +
  2763. llformat(" %d/%d", count,
  2764. GB_MAX_BANNED_AGENTS));
  2765. }
  2766. }
  2767. //static
  2768. void LLPanelGroupBanListSubTab::onBanListMemberDoubleClick(void* userdata)
  2769. {
  2770. LLPanelGroupBanListSubTab* self = (LLPanelGroupBanListSubTab*)userdata;
  2771. if (self && self->mBanList)
  2772. {
  2773. LLScrollListItem* itemp = self->mBanList->getFirstSelected();
  2774. if (itemp)
  2775. {
  2776. LLFloaterAvatarInfo::showFromDirectory(itemp->getUUID());
  2777. }
  2778. }
  2779. }