PageRenderTime 134ms CodeModel.GetById 19ms app.highlight 101ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llpanelgrouproles.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2485 lines | 1828 code | 425 blank | 232 comment | 347 complexity | bb32cc6690ff46a106b20a14dffc7978 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llpanelgrouproles.cpp
   3 * @brief Panel for roles information about a particular group.
   4 *
   5 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llcheckboxctrl.h"
  30
  31#include "llagent.h"
  32#include "llbutton.h"
  33#include "llfiltereditor.h"
  34#include "llfloatergroupinvite.h"
  35#include "llavataractions.h"
  36#include "lliconctrl.h"
  37#include "lllineeditor.h"
  38#include "llnamelistctrl.h"
  39#include "llnotifications.h"
  40#include "llnotificationsutil.h"
  41#include "llpanelgrouproles.h"
  42#include "llscrolllistctrl.h"
  43#include "llscrolllistitem.h"
  44#include "llscrolllistcell.h"
  45#include "llslurl.h"
  46#include "lltabcontainer.h"
  47#include "lltextbox.h"
  48#include "lltexteditor.h"
  49#include "lltrans.h"
  50#include "llviewertexturelist.h"
  51#include "llviewerwindow.h"
  52#include "llfocusmgr.h"
  53#include "llviewercontrol.h"
  54
  55#include "roles_constants.h"
  56
  57static LLRegisterPanelClassWrapper<LLPanelGroupRoles> t_panel_group_roles("panel_group_roles");
  58
  59bool agentCanRemoveFromRole(const LLUUID& group_id,
  60							const LLUUID& role_id)
  61{
  62	return gAgent.hasPowerInGroup(group_id, GP_ROLE_REMOVE_MEMBER);
  63}
  64
  65bool agentCanAddToRole(const LLUUID& group_id,
  66					   const LLUUID& role_id)
  67{
  68	if (gAgent.isGodlike())
  69		return true;
  70    
  71	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
  72	if (!gdatap) 
  73	{
  74		llwarns << "agentCanAddToRole "
  75				<< "-- No group data!" << llendl;
  76		return false;
  77	}
  78
  79	//make sure the agent is in the group
  80	LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(gAgent.getID());
  81	if (mi == gdatap->mMembers.end())
  82	{
  83		return false;
  84	}
  85	
  86	LLGroupMemberData* member_data = (*mi).second;
  87
  88	// Owners can add to any role.
  89	if ( member_data->isInRole(gdatap->mOwnerRole) )
  90	{
  91		return true;
  92	}
  93
  94	// 'Limited assign members' can add to roles the user is in.
  95	if ( gAgent.hasPowerInGroup(group_id, GP_ROLE_ASSIGN_MEMBER_LIMITED) &&
  96			member_data->isInRole(role_id) )
  97	{
  98		return true;
  99	}
 100
 101	// 'assign members' can add to non-owner roles.
 102	if ( gAgent.hasPowerInGroup(group_id, GP_ROLE_ASSIGN_MEMBER) &&
 103			 role_id != gdatap->mOwnerRole )
 104	{
 105		return true;
 106	}
 107
 108	return false;
 109}
 110
 111// static
 112
 113LLPanelGroupRoles::LLPanelGroupRoles()
 114:	LLPanelGroupTab(),
 115	mCurrentTab(NULL),
 116	mRequestedTab( NULL ),
 117	mSubTabContainer( NULL ),
 118	mFirstUse( TRUE )
 119{
 120}
 121
 122LLPanelGroupRoles::~LLPanelGroupRoles()
 123{
 124}
 125
 126BOOL LLPanelGroupRoles::postBuild()
 127{
 128	lldebugs << "LLPanelGroupRoles::postBuild()" << llendl;
 129
 130	mSubTabContainer = getChild<LLTabContainer>("roles_tab_container");
 131
 132	if (!mSubTabContainer) return FALSE;
 133
 134	// Hook up each sub-tabs callback and widgets.
 135	for (S32 i = 0; i < mSubTabContainer->getTabCount(); ++i)
 136	{
 137		LLPanel* panel = mSubTabContainer->getPanelByIndex(i);
 138		LLPanelGroupSubTab* subtabp = dynamic_cast<LLPanelGroupSubTab*>(panel);
 139		if (!subtabp)
 140		{
 141			llwarns << "Invalid subtab panel: " << panel->getName() << llendl;
 142			return FALSE;
 143		}
 144
 145		// Hand the subtab a pointer to this LLPanelGroupRoles, so that it can
 146		// look around for the widgets it is interested in.
 147		if (!subtabp->postBuildSubTab(this))
 148			return FALSE;
 149
 150		//subtabp->addObserver(this);
 151	}
 152	// Add click callbacks to tab switching.
 153	mSubTabContainer->setValidateBeforeCommit(boost::bind(&LLPanelGroupRoles::handleSubTabSwitch, this, _1));
 154
 155	// Set the current tab to whatever is currently being shown.
 156	mCurrentTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 157	if (!mCurrentTab)
 158	{
 159		// Need to select a tab.
 160		mSubTabContainer->selectFirstTab();
 161		mCurrentTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 162	}
 163
 164	if (!mCurrentTab) return FALSE;
 165
 166	// Act as though this tab was just activated.
 167	mCurrentTab->activate();
 168
 169	// Read apply text from the xml file.
 170	mDefaultNeedsApplyMesg = getString("default_needs_apply_text");
 171	mWantApplyMesg = getString("want_apply_text");
 172
 173	return LLPanelGroupTab::postBuild();
 174}
 175
 176BOOL LLPanelGroupRoles::isVisibleByAgent(LLAgent* agentp)
 177{
 178	/* This power was removed to make group roles simpler
 179	return agentp->hasPowerInGroup(mGroupID, 
 180								   GP_ROLE_CREATE |
 181								   GP_ROLE_DELETE |
 182								   GP_ROLE_PROPERTIES |
 183								   GP_ROLE_VIEW |
 184								   GP_ROLE_ASSIGN_MEMBER |
 185								   GP_ROLE_REMOVE_MEMBER |
 186								   GP_ROLE_CHANGE_ACTIONS |
 187								   GP_MEMBER_INVITE |
 188								   GP_MEMBER_EJECT |
 189								   GP_MEMBER_OPTIONS );
 190	*/
 191	return mAllowEdit && agentp->isInGroup(mGroupID);
 192								   
 193}
 194
 195bool LLPanelGroupRoles::handleSubTabSwitch(const LLSD& data)
 196{
 197	std::string panel_name = data.asString();
 198	
 199	if(mRequestedTab != NULL)//we already have tab change request
 200	{
 201		return false;
 202	}
 203
 204	mRequestedTab = static_cast<LLPanelGroupTab*>(mSubTabContainer->getPanelByName(panel_name));
 205
 206	std::string mesg;
 207	if (mCurrentTab && mCurrentTab->needsApply(mesg))
 208	{
 209		// If no message was provided, give a generic one.
 210		if (mesg.empty())
 211		{
 212			mesg = mDefaultNeedsApplyMesg;
 213		}
 214		// Create a notify box, telling the user about the unapplied tab.
 215		LLSD args;
 216		args["NEEDS_APPLY_MESSAGE"] = mesg;
 217		args["WANT_APPLY_MESSAGE"] = mWantApplyMesg;
 218		LLNotificationsUtil::add("PanelGroupApply", args, LLSD(),
 219			boost::bind(&LLPanelGroupRoles::handleNotifyCallback, this, _1, _2));
 220		mHasModal = TRUE;
 221		
 222		// Returning FALSE will block a close action from finishing until
 223		// we get a response back from the user.
 224		return false;
 225	}
 226
 227	transitionToTab();
 228	return true;
 229}
 230
 231void LLPanelGroupRoles::transitionToTab()
 232{
 233	// Tell the current panel that it is being deactivated.
 234	if (mCurrentTab)
 235	{
 236		mCurrentTab->deactivate();
 237	}
 238	
 239	// Tell the new panel that it is being activated.
 240	if (mRequestedTab)
 241	{
 242		// This is now the current tab;
 243		mCurrentTab = mRequestedTab;
 244		mCurrentTab->activate();
 245		mRequestedTab = 0;
 246	}
 247}
 248
 249bool LLPanelGroupRoles::handleNotifyCallback(const LLSD& notification, const LLSD& response)
 250{
 251	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 252	mHasModal = FALSE;
 253	LLPanelGroupTab* transition_tab = mRequestedTab;
 254	switch (option)
 255	{
 256	case 0: // "Apply Changes"
 257	{
 258		// Try to apply changes, and switch to the requested tab.
 259		std::string apply_mesg;
 260		if ( !apply( apply_mesg ) )
 261		{
 262			// There was a problem doing the apply.
 263			if ( !apply_mesg.empty() )
 264			{
 265				mHasModal = TRUE;
 266				LLSD args;
 267				args["MESSAGE"] = apply_mesg;
 268				LLNotificationsUtil::add("GenericAlert", args, LLSD(), boost::bind(&LLPanelGroupRoles::onModalClose, this, _1, _2));
 269			}
 270			// Skip switching tabs.
 271			break;
 272		}
 273		transitionToTab();
 274		mSubTabContainer->selectTabPanel( transition_tab );
 275		
 276		break;
 277	}
 278	case 1: // "Ignore Changes"
 279		// Switch to the requested panel without applying changes
 280		cancel();
 281		transitionToTab();
 282		mSubTabContainer->selectTabPanel( transition_tab );
 283		break;
 284	case 2: // "Cancel"
 285	default:
 286		mRequestedTab = NULL;
 287		// Do nothing.  The user is canceling the action.
 288		break;
 289	}
 290	return false;
 291}
 292
 293bool LLPanelGroupRoles::onModalClose(const LLSD& notification, const LLSD& response)
 294{
 295	mHasModal = FALSE;
 296	return false;
 297}
 298
 299
 300bool LLPanelGroupRoles::apply(std::string& mesg)
 301{
 302	// Pass this along to the currently visible sub tab.
 303	if (!mSubTabContainer) return false;
 304
 305	LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 306	if (!panelp) return false;
 307	
 308	// Ignore the needs apply message.
 309	std::string ignore_mesg;
 310	if ( !panelp->needsApply(ignore_mesg) )
 311	{
 312		// We don't need to apply anything.
 313		// We're done.
 314		return true;
 315	}
 316
 317	// Try to do the actual apply.
 318	return panelp->apply(mesg);
 319}
 320
 321void LLPanelGroupRoles::cancel()
 322{
 323	// Pass this along to the currently visible sub tab.
 324	if (!mSubTabContainer) return;
 325
 326	LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 327	if (!panelp) return;
 328
 329	panelp->cancel();
 330}
 331
 332void LLPanelGroupRoles::update(LLGroupChange gc)
 333{
 334	if (mGroupID.isNull()) return;
 335	
 336	
 337	LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 338	if (panelp)
 339	{
 340		panelp->update(gc);
 341	}
 342	else
 343	{
 344		llwarns << "LLPanelGroupRoles::update() -- No subtab to update!" << llendl;
 345	}
 346	
 347}
 348
 349void LLPanelGroupRoles::activate()
 350{
 351	// Start requesting member and role data if needed.
 352	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
 353	//if (!gdatap || mFirstUse)
 354	{
 355		// Check member data.
 356		
 357		if (!gdatap || !gdatap->isMemberDataComplete() )
 358		{
 359			LLGroupMgr::getInstance()->sendGroupMembersRequest(mGroupID);
 360		}
 361
 362		// Check role data.
 363		if (!gdatap || !gdatap->isRoleDataComplete() )
 364		{
 365			// Mildly hackish - clear all pending changes
 366			cancel();
 367
 368			LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
 369		}
 370
 371		// Check role-member mapping data.
 372		if (!gdatap || !gdatap->isRoleMemberDataComplete() )
 373		{
 374			LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
 375		}
 376
 377		// Need this to get base group member powers
 378		if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
 379		{
 380			LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
 381		}
 382
 383		mFirstUse = FALSE;
 384	}
 385
 386	LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 387	if (panelp) panelp->activate();
 388}
 389
 390void LLPanelGroupRoles::deactivate()
 391{
 392	LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 393	if (panelp) panelp->deactivate();
 394}
 395
 396bool LLPanelGroupRoles::needsApply(std::string& mesg)
 397{
 398	LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 399	if (!panelp) return false;
 400		
 401	return panelp->needsApply(mesg);
 402}
 403
 404BOOL LLPanelGroupRoles::hasModal()
 405{
 406	if (mHasModal) return TRUE;
 407
 408	LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
 409	if (!panelp) return FALSE;
 410		
 411	return panelp->hasModal();
 412}
 413
 414
 415////////////////////////////
 416// LLPanelGroupSubTab
 417////////////////////////////
 418LLPanelGroupSubTab::LLPanelGroupSubTab()
 419:	LLPanelGroupTab(),
 420	mHeader(NULL),
 421	mFooter(NULL),
 422	mActivated(false),
 423	mSearchEditor(NULL)
 424{
 425}
 426
 427LLPanelGroupSubTab::~LLPanelGroupSubTab()
 428{
 429}
 430
 431BOOL LLPanelGroupSubTab::postBuildSubTab(LLView* root) 
 432{ 
 433	// Get icons for later use.
 434	mActionIcons.clear();
 435
 436	if (hasString("power_folder_icon"))
 437	{
 438		mActionIcons["folder"] = getString("power_folder_icon");
 439	}
 440
 441	if (hasString("power_all_have_icon"))
 442	{
 443		mActionIcons["full"] = getString("power_all_have_icon");
 444	}
 445
 446	if (hasString("power_partial_icon"))
 447	{
 448		mActionIcons["partial"] = getString("power_partial_icon");
 449	}
 450	return TRUE; 
 451}
 452
 453BOOL LLPanelGroupSubTab::postBuild()
 454{
 455	// Hook up the search widgets.
 456	bool recurse = true;
 457	mSearchEditor = getChild<LLFilterEditor>("filter_input", recurse);
 458
 459	if (!mSearchEditor) 
 460		return FALSE;
 461
 462	mSearchEditor->setCommitCallback(boost::bind(&LLPanelGroupSubTab::setSearchFilter, this, _2));
 463
 464	return LLPanelGroupTab::postBuild();
 465}
 466
 467void LLPanelGroupSubTab::setGroupID(const LLUUID& id)
 468{
 469	LLPanelGroupTab::setGroupID(id);
 470	if(mSearchEditor)
 471	{
 472		mSearchEditor->clear();
 473		setSearchFilter("");
 474	}
 475
 476	mActivated = false;
 477}
 478
 479void LLPanelGroupSubTab::setSearchFilter(const std::string& filter)
 480{
 481	if(mSearchFilter == filter)
 482		return;
 483	mSearchFilter = filter;
 484	LLStringUtil::toLower(mSearchFilter);
 485	update(GC_ALL);
 486}
 487
 488void LLPanelGroupSubTab::activate()
 489{
 490	setOthersVisible(TRUE);
 491}
 492
 493void LLPanelGroupSubTab::deactivate()
 494{
 495	setOthersVisible(FALSE);
 496}
 497
 498void LLPanelGroupSubTab::setOthersVisible(BOOL b)
 499{
 500	if (mHeader)
 501	{
 502		mHeader->setVisible( b );
 503	}
 504
 505	if (mFooter)
 506	{
 507		mFooter->setVisible( b );
 508	}
 509}
 510
 511bool LLPanelGroupSubTab::matchesActionSearchFilter(std::string action)
 512{
 513	// If the search filter is empty, everything passes.
 514	if (mSearchFilter.empty()) return true;
 515
 516	LLStringUtil::toLower(action);
 517	std::string::size_type match = action.find(mSearchFilter);
 518
 519	if (std::string::npos == match)
 520	{
 521		// not found
 522		return false;
 523	}
 524	else
 525	{
 526		return true;
 527	}
 528}
 529
 530void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl, 
 531										  U64 allowed_by_some, 
 532										  U64 allowed_by_all,
 533										  LLUICtrl::commit_callback_t commit_callback,
 534										  BOOL show_all,
 535										  BOOL filter,
 536										  BOOL is_owner_role)
 537{
 538	if (LLGroupMgr::getInstance()->mRoleActionSets.empty())
 539	{
 540		llwarns << "Can't build action list - no actions found." << llendl;
 541		return;
 542	}
 543
 544	std::vector<LLRoleActionSet*>::iterator ras_it = LLGroupMgr::getInstance()->mRoleActionSets.begin();
 545	std::vector<LLRoleActionSet*>::iterator ras_end = LLGroupMgr::getInstance()->mRoleActionSets.end();
 546
 547	for ( ; ras_it != ras_end; ++ras_it)
 548	{
 549		buildActionCategory(ctrl,
 550							allowed_by_some,
 551							allowed_by_all,
 552							(*ras_it),
 553							commit_callback,
 554							show_all,
 555							filter,
 556							is_owner_role);
 557	}
 558}
 559
 560void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl,
 561											 U64 allowed_by_some,
 562											 U64 allowed_by_all,
 563											 LLRoleActionSet* action_set,
 564											 LLUICtrl::commit_callback_t commit_callback,
 565											 BOOL show_all,
 566											 BOOL filter,
 567											 BOOL is_owner_role)
 568{
 569	lldebugs << "Building role list for: " << action_set->mActionSetData->mName << llendl;
 570	// See if the allow mask matches anything in this category.
 571	if (show_all || (allowed_by_some & action_set->mActionSetData->mPowerBit))
 572	{
 573		// List all the actions in this category that at least some members have.
 574		LLSD row;
 575
 576		row["columns"][0]["column"] = "icon";
 577		row["columns"][0]["type"] = "icon";
 578		
 579		icon_map_t::iterator iter = mActionIcons.find("folder");
 580		if (iter != mActionIcons.end())
 581		{
 582			row["columns"][0]["value"] = (*iter).second;
 583		}
 584
 585		row["columns"][1]["column"] = "action";
 586		row["columns"][1]["type"] = "text";
 587		row["columns"][1]["value"] = LLTrans::getString(action_set->mActionSetData->mName);
 588		row["columns"][1]["font"]["name"] = "SANSSERIF_SMALL";
 589		
 590
 591		LLScrollListItem* title_row = ctrl->addElement(row, ADD_BOTTOM, action_set->mActionSetData);
 592		
 593		LLScrollListText* name_textp = dynamic_cast<LLScrollListText*>(title_row->getColumn(2)); //?? I have no idea fix getColumn(1) return column spacer...
 594		if (name_textp)
 595			name_textp->setFontStyle(LLFontGL::BOLD);
 596
 597		bool category_matches_filter = (filter) ? matchesActionSearchFilter(action_set->mActionSetData->mName) : true;
 598
 599		std::vector<LLRoleAction*>::iterator ra_it = action_set->mActions.begin();
 600		std::vector<LLRoleAction*>::iterator ra_end = action_set->mActions.end();
 601
 602		bool items_match_filter = false;
 603		BOOL can_change_actions = (!is_owner_role && gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CHANGE_ACTIONS));
 604
 605		for ( ; ra_it != ra_end; ++ra_it)
 606		{
 607			// See if anyone has these action.
 608			if (!show_all && !(allowed_by_some & (*ra_it)->mPowerBit))
 609			{
 610				continue;
 611			}
 612
 613			// See if we are filtering out these actions
 614			// If we aren't using filters, category_matches_filter will be true.
 615			if (!category_matches_filter
 616				&& !matchesActionSearchFilter((*ra_it)->mDescription))
 617			{
 618				continue;										
 619			}
 620
 621			items_match_filter = true;
 622
 623			// See if everyone has these actions.
 624			bool show_full_strength = false;
 625			if ( (allowed_by_some & (*ra_it)->mPowerBit) == (allowed_by_all & (*ra_it)->mPowerBit) )
 626			{
 627				show_full_strength = true;
 628			}
 629
 630			LLSD row;
 631
 632			S32 column_index = 0;
 633			row["columns"][column_index]["column"] = "icon";
 634			++column_index;
 635
 636			
 637			S32 check_box_index = -1;
 638			if (commit_callback)
 639			{
 640				row["columns"][column_index]["column"] = "checkbox";
 641				row["columns"][column_index]["type"] = "checkbox";
 642				check_box_index = column_index;
 643				++column_index;
 644			}
 645			else
 646			{
 647				if (show_full_strength)
 648				{
 649					icon_map_t::iterator iter = mActionIcons.find("full");
 650					if (iter != mActionIcons.end())
 651					{
 652						row["columns"][column_index]["column"] = "checkbox";
 653						row["columns"][column_index]["type"] = "icon";
 654						row["columns"][column_index]["value"] = (*iter).second;
 655						++column_index;
 656					}
 657				}
 658				else
 659				{
 660					icon_map_t::iterator iter = mActionIcons.find("partial");
 661					if (iter != mActionIcons.end())
 662					{
 663						row["columns"][column_index]["column"] = "checkbox";
 664						row["columns"][column_index]["type"] = "icon";
 665						row["columns"][column_index]["value"] = (*iter).second;
 666						++column_index;
 667					}
 668					row["enabled"] = false;
 669				}
 670			}
 671
 672			row["columns"][column_index]["column"] = "action";
 673			row["columns"][column_index]["value"] = (*ra_it)->mDescription;
 674			row["columns"][column_index]["font"] = "SANSSERIF_SMALL";
 675
 676			LLScrollListItem* item = ctrl->addElement(row, ADD_BOTTOM, (*ra_it));
 677
 678			if (-1 != check_box_index)
 679			{
 680				// Extract the checkbox that was created.
 681				LLScrollListCheck* check_cell = (LLScrollListCheck*) item->getColumn(check_box_index);
 682				LLCheckBoxCtrl* check = check_cell->getCheckBox();
 683				check->setEnabled(can_change_actions);
 684				check->setCommitCallback(commit_callback);
 685				check->setToolTip( check->getLabel() );
 686
 687				if (show_all)
 688				{
 689					check->setTentative(FALSE);
 690					if (allowed_by_some & (*ra_it)->mPowerBit)
 691					{
 692						check->set(TRUE);
 693					}
 694					else
 695					{
 696						check->set(FALSE);
 697					}
 698				}
 699				else
 700				{
 701					check->set(TRUE);
 702					if (show_full_strength)
 703					{
 704						check->setTentative(FALSE);
 705					}
 706					else
 707					{
 708						check->setTentative(TRUE);
 709					}
 710				}
 711			}
 712		}
 713
 714		if (!items_match_filter)
 715		{
 716			S32 title_index = ctrl->getItemIndex(title_row);
 717			ctrl->deleteSingleItem(title_index);
 718		}
 719	}
 720}
 721
 722void LLPanelGroupSubTab::setFooterEnabled(BOOL enable)
 723{
 724	if (mFooter)
 725	{
 726		mFooter->setAllChildrenEnabled(enable);
 727	}
 728}
 729
 730////////////////////////////
 731// LLPanelGroupMembersSubTab
 732////////////////////////////
 733
 734
 735static LLRegisterPanelClassWrapper<LLPanelGroupMembersSubTab> t_panel_group_members_subtab("panel_group_members_subtab");
 736
 737LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab()
 738: 	LLPanelGroupSubTab(),
 739	mMembersList(NULL),
 740	mAssignedRolesList(NULL),
 741	mAllowedActionsList(NULL),
 742	mChanged(FALSE),
 743	mPendingMemberUpdate(FALSE),
 744	mHasMatch(FALSE),
 745	mNumOwnerAdditions(0)
 746{
 747	mUdpateSessionID = LLUUID::null;
 748}
 749
 750LLPanelGroupMembersSubTab::~LLPanelGroupMembersSubTab()
 751{
 752	gSavedSettings.setString("GroupMembersSortOrder", mMembersList->getSortColumnName());
 753}
 754
 755BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
 756{
 757	LLPanelGroupSubTab::postBuildSubTab(root);
 758	
 759	// Upcast parent so we can ask it for sibling controls.
 760	LLPanelGroupRoles* parent = (LLPanelGroupRoles*) root;
 761
 762	// Look recursively from the parent to find all our widgets.
 763	bool recurse = true;
 764	mHeader = parent->getChild<LLPanel>("members_header", recurse);
 765	mFooter = parent->getChild<LLPanel>("members_footer", recurse);
 766
 767	mMembersList 		= parent->getChild<LLNameListCtrl>("member_list", recurse);
 768	mAssignedRolesList	= parent->getChild<LLScrollListCtrl>("member_assigned_roles", recurse);
 769	mAllowedActionsList	= parent->getChild<LLScrollListCtrl>("member_allowed_actions", recurse);
 770
 771	if (!mMembersList || !mAssignedRolesList || !mAllowedActionsList) return FALSE;
 772
 773	// We want to be notified whenever a member is selected.
 774	mMembersList->setCommitOnSelectionChange(TRUE);
 775	mMembersList->setCommitCallback(onMemberSelect, this);
 776	// Show the member's profile on double click.
 777	mMembersList->setDoubleClickCallback(onMemberDoubleClick, this);
 778	mMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
 779	
 780	LLSD row;
 781	row["columns"][0]["column"] = "name";
 782	row["columns"][1]["column"] = "donated";
 783	row["columns"][2]["column"] = "online";
 784	mMembersList->addElement(row);
 785	std::string order_by = gSavedSettings.getString("GroupMembersSortOrder");
 786	if(!order_by.empty())
 787	{
 788		mMembersList->sortByColumn(order_by, TRUE);
 789	}	
 790
 791	LLButton* button = parent->getChild<LLButton>("member_invite", recurse);
 792	if ( button )
 793	{
 794		button->setClickedCallback(onInviteMember, this);
 795		button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE));
 796	}
 797
 798	mEjectBtn = parent->getChild<LLButton>("member_eject", recurse);
 799	if ( mEjectBtn )
 800	{
 801		mEjectBtn->setClickedCallback(onEjectMembers, this);
 802		mEjectBtn->setEnabled(FALSE);
 803	}
 804
 805	return TRUE;
 806}
 807
 808void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id)
 809{
 810	//clear members list
 811	if(mMembersList) mMembersList->deleteAllItems();
 812	if(mAssignedRolesList) mAssignedRolesList->deleteAllItems();
 813	if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
 814
 815	LLPanelGroupSubTab::setGroupID(id);
 816}
 817
 818void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id)
 819{
 820	if(mRolesList) mRolesList->deleteAllItems();
 821	if(mAssignedMembersList) mAssignedMembersList->deleteAllItems();
 822	if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
 823
 824	if(mRoleName) mRoleName->clear();
 825	if(mRoleDescription) mRoleDescription->clear();
 826	if(mRoleTitle) mRoleTitle->clear();
 827
 828	mHasRoleChange = FALSE;
 829
 830	setFooterEnabled(FALSE);
 831
 832	LLPanelGroupSubTab::setGroupID(id);
 833}
 834void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id)
 835{
 836	if(mActionList) mActionList->deleteAllItems();
 837	if(mActionRoles) mActionRoles->deleteAllItems();
 838	if(mActionMembers) mActionMembers->deleteAllItems();
 839
 840	if(mActionDescription) mActionDescription->clear();
 841
 842	LLPanelGroupSubTab::setGroupID(id);
 843}
 844
 845
 846// static
 847void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data)
 848{
 849	LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
 850	self->handleMemberSelect();
 851}
 852
 853void LLPanelGroupMembersSubTab::handleMemberSelect()
 854{
 855	lldebugs << "LLPanelGroupMembersSubTab::handleMemberSelect" << llendl;
 856
 857	mAssignedRolesList->deleteAllItems();
 858	mAllowedActionsList->deleteAllItems();
 859	
 860	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
 861	if (!gdatap) 
 862	{
 863		llwarns << "LLPanelGroupMembersSubTab::handleMemberSelect() "
 864				<< "-- No group data!" << llendl;
 865		return;
 866	}
 867
 868	// Check if there is anything selected.
 869	std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
 870	if (selection.empty()) return;
 871
 872	// Build a vector of all selected members, and gather allowed actions.
 873	uuid_vec_t selected_members;
 874	U64 allowed_by_all = 0xffffffffffffLL;
 875	U64 allowed_by_some = 0;
 876
 877	std::vector<LLScrollListItem*>::iterator itor;
 878	for (itor = selection.begin();
 879		 itor != selection.end(); ++itor)
 880	{
 881		LLUUID member_id = (*itor)->getUUID();
 882
 883		selected_members.push_back( member_id );
 884		// Get this member's power mask including any unsaved changes
 885
 886		U64 powers = getAgentPowersBasedOnRoleChanges( member_id );
 887
 888		allowed_by_all &= powers;
 889		allowed_by_some |= powers;
 890	}
 891	std::sort(selected_members.begin(), selected_members.end());
 892
 893	//////////////////////////////////
 894	// Build the allowed actions list.
 895	//////////////////////////////////
 896	buildActionsList(mAllowedActionsList,
 897					 allowed_by_some,
 898					 allowed_by_all,
 899					 NULL,
 900					 FALSE,
 901					 FALSE,
 902					 FALSE);
 903
 904	//////////////////////////////////
 905	// Build the assigned roles list.
 906	//////////////////////////////////
 907	// Add each role to the assigned roles list.
 908	LLGroupMgrGroupData::role_list_t::iterator iter = gdatap->mRoles.begin();
 909	LLGroupMgrGroupData::role_list_t::iterator end  = gdatap->mRoles.end();
 910
 911	BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID,
 912													GP_MEMBER_EJECT);
 913	BOOL member_is_owner = FALSE;
 914	
 915	for( ; iter != end; ++iter)
 916	{
 917		// Count how many selected users are in this role.
 918		const LLUUID& role_id = iter->first;
 919		LLGroupRoleData* group_role_data = iter->second;
 920
 921		if (group_role_data)
 922		{
 923			const BOOL needs_sort = FALSE;
 924			S32 count = group_role_data->getMembersInRole(
 925											selected_members, needs_sort);
 926			//check if the user has permissions to assign/remove
 927			//members to/from the role (but the ability to add/remove
 928			//should only be based on the "saved" changes to the role
 929			//not in the temp/meta data. -jwolk
 930			BOOL cb_enable = ( (count > 0) ?
 931							   agentCanRemoveFromRole(mGroupID, role_id) :
 932							   agentCanAddToRole(mGroupID, role_id) );
 933
 934
 935			// Owner role has special enabling permissions for removal.
 936			if (cb_enable && (count > 0) && role_id == gdatap->mOwnerRole)
 937			{
 938				// Check if any owners besides this agent are selected.
 939				uuid_vec_t::const_iterator member_iter;
 940				uuid_vec_t::const_iterator member_end =
 941												selected_members.end();
 942				for (member_iter = selected_members.begin();
 943					 member_iter != member_end;	
 944					 ++member_iter)
 945				{
 946					// Don't count the agent.
 947					if ((*member_iter) == gAgent.getID()) continue;
 948					
 949					// Look up the member data.
 950					LLGroupMgrGroupData::member_list_t::iterator mi = 
 951									gdatap->mMembers.find((*member_iter));
 952					if (mi == gdatap->mMembers.end()) continue;
 953					LLGroupMemberData* member_data = (*mi).second;
 954					// Is the member an owner?
 955					if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
 956					{
 957						// Can't remove other owners.
 958						cb_enable = FALSE;
 959						break;
 960					}
 961				}
 962			}
 963
 964			//now see if there are any role changes for the selected
 965			//members and remember to include them
 966			uuid_vec_t::iterator sel_mem_iter = selected_members.begin();
 967			for (; sel_mem_iter != selected_members.end(); sel_mem_iter++)
 968			{
 969				LLRoleMemberChangeType type;
 970				if ( getRoleChangeType(*sel_mem_iter, role_id, type) )
 971				{
 972					if ( type == RMC_ADD ) count++;
 973					else if ( type == RMC_REMOVE ) count--;
 974				}
 975			}
 976			
 977			// If anyone selected is in any role besides 'Everyone' then they can't be ejected.
 978			if (role_id.notNull() && (count > 0))
 979			{
 980				can_eject_members = FALSE;
 981				if (role_id == gdatap->mOwnerRole)
 982				{
 983					member_is_owner = TRUE;
 984				}
 985			}
 986
 987			LLRoleData rd;
 988			if (gdatap->getRoleData(role_id,rd))
 989			{
 990				std::ostringstream label;
 991				label << rd.mRoleName;
 992				// Don't bother showing a count, if there is only 0 or 1.
 993				if (count > 1)
 994				{
 995					label << ": " << count ;
 996				}
 997	
 998				LLSD row;
 999				row["id"] = role_id;
1000
1001				row["columns"][0]["column"] = "checkbox";
1002				row["columns"][0]["type"] = "checkbox";
1003
1004				row["columns"][1]["column"] = "role";
1005				row["columns"][1]["value"] = label.str();
1006
1007				if (row["id"].asUUID().isNull())
1008				{
1009					// This is the everyone role, you can't take people out of the everyone role!
1010					row["enabled"] = false;
1011				}
1012
1013				LLScrollListItem* item = mAssignedRolesList->addElement(row);
1014
1015				// Extract the checkbox that was created.
1016				LLScrollListCheck* check_cell = (LLScrollListCheck*) item->getColumn(0);
1017				LLCheckBoxCtrl* check = check_cell->getCheckBox();
1018				check->setCommitCallback(onRoleCheck, this);
1019				check->set( count > 0 );
1020				check->setTentative(
1021					(0 != count)
1022					&& (selected_members.size() !=
1023						(uuid_vec_t::size_type)count));
1024
1025				//NOTE: as of right now a user can break the group
1026				//by removing himself from a role if he is the
1027				//last owner.  We should check for this special case
1028				// -jwolk
1029				check->setEnabled(cb_enable);
1030				item->setEnabled(cb_enable);
1031			}
1032		}
1033		else
1034		{
1035			// This could happen if changes are not synced right on sub-panel change.
1036			llwarns << "No group role data for " << iter->second << llendl;
1037		}
1038	}
1039	mAssignedRolesList->setEnabled(TRUE);
1040
1041	if (gAgent.isGodlike())
1042		can_eject_members = TRUE;
1043
1044	if (!can_eject_members && !member_is_owner)
1045	{
1046		// Maybe we can eject them because we are an owner...
1047		LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(gAgent.getID());
1048		if (mi != gdatap->mMembers.end())
1049		{
1050			LLGroupMemberData* member_data = (*mi).second;
1051
1052			if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
1053			{
1054				can_eject_members = TRUE;
1055			}
1056		}
1057	}
1058
1059	mEjectBtn->setEnabled(can_eject_members);
1060}
1061
1062// static
1063void LLPanelGroupMembersSubTab::onMemberDoubleClick(void* user_data)
1064{
1065	LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
1066	self->handleMemberDoubleClick();
1067}
1068
1069//static
1070void LLPanelGroupMembersSubTab::onInviteMember(void *userdata)
1071{
1072	LLPanelGroupMembersSubTab* selfp = (LLPanelGroupMembersSubTab*) userdata;
1073
1074	if ( selfp )
1075	{
1076		selfp->handleInviteMember();
1077	}
1078}
1079
1080void LLPanelGroupMembersSubTab::handleInviteMember()
1081{
1082	LLFloaterGroupInvite::showForGroup(mGroupID);
1083}
1084
1085void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata)
1086{
1087	LLPanelGroupMembersSubTab* selfp = (LLPanelGroupMembersSubTab*) userdata;
1088
1089	if ( selfp )
1090	{
1091		selfp->handleEjectMembers();
1092	}
1093}
1094
1095void LLPanelGroupMembersSubTab::handleEjectMembers()
1096{
1097	//send down an eject message
1098	uuid_vec_t selected_members;
1099
1100	std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
1101	if (selection.empty()) return;
1102
1103	std::vector<LLScrollListItem*>::iterator itor;
1104	for (itor = selection.begin() ; 
1105		 itor != selection.end(); ++itor)
1106	{
1107		LLUUID member_id = (*itor)->getUUID();
1108		selected_members.push_back( member_id );
1109	}
1110
1111	mMembersList->deleteSelectedItems();
1112
1113	sendEjectNotifications(mGroupID, selected_members);
1114
1115	LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID,
1116									 selected_members);
1117}
1118
1119void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members)
1120{
1121	LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id);
1122
1123	if (group_data)
1124	{
1125		for (uuid_vec_t::const_iterator i = selected_members.begin(); i != selected_members.end(); ++i)
1126		{
1127			LLSD args;
1128			args["AVATAR_NAME"] = LLSLURL("agent", *i, "displayname").getSLURLString();
1129			args["GROUP_NAME"] = group_data->mName;
1130			
1131			LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
1132		}
1133	}
1134}
1135
1136void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
1137												LLRoleMemberChangeType type)
1138{
1139	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1140	if (!gdatap) return;
1141
1142	//add that the user is requesting to change the roles for selected
1143	//members
1144	U64 powers_all_have  = 0xffffffffffffLL;
1145	U64 powers_some_have = 0;
1146
1147	BOOL   is_owner_role = ( gdatap->mOwnerRole == role_id );
1148	LLUUID member_id;
1149	
1150
1151	std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
1152	if (selection.empty())
1153	{
1154		return;
1155	}
1156	
1157	for (std::vector<LLScrollListItem*>::iterator itor = selection.begin() ; 
1158		 itor != selection.end(); ++itor)
1159	{
1160
1161		member_id = (*itor)->getUUID();
1162
1163		//see if we requested a change for this member before
1164		if ( mMemberRoleChangeData.find(member_id) == mMemberRoleChangeData.end() )
1165		{
1166			mMemberRoleChangeData[member_id] = new role_change_data_map_t;
1167		}
1168		role_change_data_map_t* role_change_datap = mMemberRoleChangeData[member_id];
1169
1170		//now check to see if the selected group member
1171		//had changed his association with the selected role before
1172
1173		role_change_data_map_t::iterator  role = role_change_datap->find(role_id);
1174		if ( role != role_change_datap->end() )
1175		{
1176			//see if the new change type cancels out the previous change
1177			if (role->second != type)
1178			{
1179				role_change_datap->erase(role_id);
1180				if ( is_owner_role ) mNumOwnerAdditions--;
1181			}
1182			//else do nothing
1183
1184			if ( role_change_datap->empty() )
1185			{
1186				//the current member now has no role changes
1187				//so erase the role change and erase the member's entry
1188				delete role_change_datap;
1189                role_change_datap = NULL;
1190
1191				mMemberRoleChangeData.erase(member_id);
1192			}
1193		}
1194		else
1195		{
1196			//a previously unchanged role is being changed
1197			(*role_change_datap)[role_id] = type;
1198			if ( is_owner_role && type == RMC_ADD ) mNumOwnerAdditions++;
1199		}
1200
1201		//we need to calculate what powers the selected members
1202		//have (including the role changes we're making)
1203		//so that we can rebuild the action list
1204		U64 new_powers = getAgentPowersBasedOnRoleChanges(member_id);
1205
1206		powers_all_have  &= new_powers;
1207		powers_some_have |= new_powers;
1208	}
1209
1210	
1211	mChanged = !mMemberRoleChangeData.empty();
1212	notifyObservers();
1213
1214	//alrighty now we need to update the actions list
1215	//to reflect the changes
1216	mAllowedActionsList->deleteAllItems();
1217	buildActionsList(mAllowedActionsList,
1218					 powers_some_have,
1219					 powers_all_have,
1220					 NULL,
1221					 FALSE,
1222					 FALSE,
1223					 FALSE);
1224}
1225
1226
1227// static 
1228void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data)
1229{
1230	LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
1231	LLCheckBoxCtrl* check_box = static_cast<LLCheckBoxCtrl*>(ctrl);
1232	if (!check_box || !self) return;
1233
1234	LLScrollListItem* first_selected =
1235		self->mAssignedRolesList->getFirstSelected();
1236	if (first_selected)
1237	{
1238		LLUUID role_id = first_selected->getUUID();
1239		LLRoleMemberChangeType change_type = (check_box->get() ? 
1240						      RMC_ADD : 
1241						      RMC_REMOVE);
1242		
1243		self->handleRoleCheck(role_id, change_type);
1244	}
1245}
1246
1247void LLPanelGroupMembersSubTab::handleMemberDoubleClick()
1248{
1249	LLScrollListItem* selected = mMembersList->getFirstSelected();
1250	if (selected)
1251	{
1252		LLUUID member_id = selected->getUUID();
1253		LLAvatarActions::showProfile( member_id );
1254	}
1255}
1256
1257void LLPanelGroupMembersSubTab::activate()
1258{
1259	LLPanelGroupSubTab::activate();
1260	if(!mActivated)
1261	{
1262		update(GC_ALL);
1263		mActivated = true;
1264	}
1265}
1266
1267void LLPanelGroupMembersSubTab::deactivate()
1268{
1269	LLPanelGroupSubTab::deactivate();
1270}
1271
1272bool LLPanelGroupMembersSubTab::needsApply(std::string& mesg)
1273{
1274	return mChanged;
1275}
1276
1277void LLPanelGroupMembersSubTab::cancel()
1278{
1279	if ( mChanged )
1280	{
1281		std::for_each(mMemberRoleChangeData.begin(),
1282					  mMemberRoleChangeData.end(),
1283					  DeletePairedPointer());
1284		mMemberRoleChangeData.clear();
1285
1286		mChanged = FALSE;
1287		notifyObservers();
1288	}
1289}
1290
1291bool LLPanelGroupMembersSubTab::apply(std::string& mesg)
1292{
1293	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1294	if (!gdatap)
1295	{
1296		llwarns << "Unable to get group data for group " << mGroupID << llendl;
1297
1298		mesg.assign("Unable to save member data.  Try again later.");
1299		return false;
1300	}
1301
1302	if (mChanged)
1303	{
1304		//figure out if we are somehow adding an owner or not and alert
1305		//the user...possibly make it ignorable
1306		if ( mNumOwnerAdditions > 0 )
1307		{
1308			LLRoleData rd;
1309			LLSD args;
1310
1311			if ( gdatap->getRoleData(gdatap->mOwnerRole, rd) )
1312			{
1313				mHasModal = TRUE;
1314				args["ROLE_NAME"] = rd.mRoleName;
1315				LLNotificationsUtil::add("AddGroupOwnerWarning",
1316										args,
1317										LLSD(),
1318										boost::bind(&LLPanelGroupMembersSubTab::addOwnerCB, this, _1, _2));
1319			}
1320			else
1321			{
1322				llwarns << "Unable to get role information for the owner role in group " << mGroupID << llendl;
1323
1324				mesg.assign("Unable to retried specific group information.  Try again later");
1325				return false;
1326			}
1327				 
1328		}
1329		else
1330		{
1331			applyMemberChanges();
1332		}
1333	}
1334
1335	return true;
1336}
1337
1338bool LLPanelGroupMembersSubTab::addOwnerCB(const LLSD& notification, const LLSD& response)
1339{
1340	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
1341	mHasModal = FALSE;
1342
1343	if (0 == option)
1344	{
1345		// User clicked "Yes"
1346		applyMemberChanges();
1347	}
1348	return false;
1349}
1350
1351void LLPanelGroupMembersSubTab::applyMemberChanges()
1352{
1353	//sucks to do a find again here, but it is in constant time, so, could
1354	//be worse
1355	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1356	if (!gdatap)
1357	{
1358		llwarns << "Unable to get group data for group " << mGroupID << llendl;
1359		return;
1360	}
1361
1362	//we need to add all of the changed roles data
1363	//for each member whose role changed
1364	for (member_role_changes_map_t::iterator member = mMemberRoleChangeData.begin();
1365		 member != mMemberRoleChangeData.end(); ++member)
1366	{
1367		for (role_change_data_map_t::iterator role = member->second->begin();
1368			 role != member->second->end(); ++role)
1369		{
1370			gdatap->changeRoleMember(role->first, //role_id
1371									 member->first, //member_id
1372									 role->second); //add/remove
1373		}
1374
1375		member->second->clear();
1376		delete member->second;
1377	}
1378	mMemberRoleChangeData.clear();
1379
1380	LLGroupMgr::getInstance()->sendGroupRoleMemberChanges(mGroupID);	
1381	//force a UI update
1382	handleMemberSelect();
1383
1384	mChanged = FALSE;
1385	mNumOwnerAdditions = 0;
1386	notifyObservers();
1387}
1388
1389bool LLPanelGroupMembersSubTab::matchesSearchFilter(const std::string& fullname)
1390{
1391	// If the search filter is empty, everything passes.
1392	if (mSearchFilter.empty()) return true;
1393
1394	// Create a full name, and compare it to the search filter.
1395	std::string fullname_lc(fullname);
1396	LLStringUtil::toLower(fullname_lc);
1397
1398	std::string::size_type match = fullname_lc.find(mSearchFilter);
1399
1400	if (std::string::npos == match)
1401	{
1402		// not found
1403		return false;
1404	}
1405	else
1406	{
1407		return true;
1408	}
1409}
1410
1411U64 LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges(const LLUUID& agent_id)
1412{
1413	//we loop over all of the changes
1414	//if we are adding a role, then we simply add the role's powers
1415	//if we are removing a role, we store that role id away
1416	//and then we have to build the powers up bases on the roles the agent
1417	//is in
1418
1419	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1420	if (!gdatap) 
1421	{
1422		llwarns << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No group data!" << llendl;
1423		return GP_NO_POWERS;
1424	}
1425
1426	LLGroupMemberData* member_data = gdatap->mMembers[agent_id];
1427	if ( !member_data )
1428	{
1429		llwarns << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No member data for member with UUID " << agent_id << llendl;
1430		return GP_NO_POWERS;
1431	}
1432
1433	//see if there are unsaved role changes for this agent
1434	role_change_data_map_t* role_change_datap = NULL;
1435	member_role_changes_map_t::iterator member = mMemberRoleChangeData.find(agent_id);
1436	if ( member != mMemberRoleChangeData.end() )
1437	{
1438		//this member has unsaved role changes
1439		//so grab them
1440		role_change_datap = (*member).second;
1441	}
1442
1443	U64 new_powers = GP_NO_POWERS;
1444
1445	if ( role_change_datap )
1446	{
1447		uuid_vec_t roles_to_be_removed;
1448
1449		for (role_change_data_map_t::iterator role = role_change_datap->begin();
1450			 role != role_change_datap->end(); ++ role)
1451		{
1452			if ( role->second == RMC_ADD )
1453			{
1454				new_powers |= gdatap->getRolePowers(role->first);
1455			}
1456			else
1457			{
1458				roles_to_be_removed.push_back(role->first);
1459			}
1460		}
1461
1462		//loop over the member's current roles, summing up
1463		//the powers (not including the role we are removing)
1464		for (LLGroupMemberData::role_list_t::iterator current_role = member_data->roleBegin();
1465			 current_role != member_data->roleEnd(); ++current_role)
1466		{
1467			bool role_in_remove_list =
1468				(std::find(roles_to_be_removed.begin(),
1469						   roles_to_be_removed.end(),
1470						   current_role->second->getID()) !=
1471				 roles_to_be_removed.end());
1472
1473			if ( !role_in_remove_list )
1474			{
1475				new_powers |= 
1476					current_role->second->getRoleData().mRolePowers;
1477			}
1478		}
1479	}
1480	else
1481	{
1482		//there are no changes for this member
1483		//the member's powers are just the ones stored in the group
1484		//manager
1485		new_powers = member_data->getAgentPowers();
1486	}
1487
1488	return new_powers;
1489}
1490
1491//If there is no change, returns false be sure to verify
1492//that there is a role change before attempting to get it or else
1493//the data will make no sense.  Stores the role change type
1494bool LLPanelGroupMembersSubTab::getRoleChangeType(const LLUUID& member_id,
1495												  const LLUUID& role_id,
1496												  LLRoleMemberChangeType& type)
1497{
1498	member_role_changes_map_t::iterator member_changes_iter = mMemberRoleChangeData.find(member_id);
1499	if ( member_changes_iter != mMemberRoleChangeData.end() )
1500	{
1501		role_change_data_map_t::iterator role_changes_iter = member_changes_iter->second->find(role_id);
1502		if ( role_changes_iter != member_changes_iter->second->end() )
1503		{
1504			type = role_changes_iter->second;
1505			return true;
1506		}
1507	}
1508
1509	return false;
1510}
1511
1512void LLPanelGroupMembersSubTab::draw()
1513{
1514	LLPanelGroupSubTab::draw();
1515
1516	if (mPendingMemberUpdate)
1517	{
1518		updateMembers();
1519	}
1520}
1521
1522void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
1523{
1524	if (mGroupID.isNull()) return;
1525
1526	if ( GC_TITLES == gc || GC_PROPERTIES == gc )
1527	{
1528		// Don't care about title or general group properties updates.
1529		return;
1530	}
1531
1532	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1533	if (!gdatap) 
1534	{
1535		llwarns << "LLPanelGroupMembersSubTab::update() -- No group data!" << llendl;
1536		return;
1537	}
1538
1539	// Wait for both all data to be retrieved before displaying anything.
1540	if (   gdatap->isMemberDataComplete() 
1541		&& gdatap->isRoleDataComplete()
1542		&& gdatap->isRoleMemberDataComplete())
1543	{
1544		mMemberProgress = gdatap->mMembers.begin();
1545		mPendingMemberUpdate = TRUE;
1546		mHasMatch = FALSE;
1547		// Generate unique ID for current updateMembers()- see onNameCache for details.
1548		// Using unique UUID is perhaps an overkill but this way we are perfectly safe
1549		// from coincidences.
1550		mUdpateSessionID.generate();
1551	}
1552	else
1553	{
1554		// Build a string with info on retrieval progress.
1555		std::ostringstream retrieved;
1556		if ( !gdatap->isMemberDataComplete() )
1557		{
1558			// Still busy retreiving member list.
1559			retrieved << "Retrieving member list (" << gdatap->mMembers.size()
1560					  << " / " << gdatap->mMemberCount << ")...";
1561		}
1562		else if( !gdatap->isRoleDataComplete() )
1563		{
1564			// Still busy retreiving role list.
1565			retrieved << "Retrieving role list (" << gdatap->mRoles.size()
1566					  << " / " << gdatap->mRoleCount << ")...";
1567		}
1568		else // (!gdatap->isRoleMemberDataComplete())
1569		{
1570			// Still busy retreiving role/member mappings.
1571			retrieved << "Retrieving role member mappings...";
1572		}
1573		mMembersList->setEnabled(FALSE);
1574		mMembersList->setCommentText(retrieved.str());
1575	}
1576}
1577
1578void LLPanelGroupMembersSubTab::addMemberToList(LLUUID id, LLGroupMemberData* data)
1579{
1580	if (!data) return;
1581	LLUIString donated = getString("donation_area");
1582	donated.setArg("[AREA]", llformat("%d", data->getContribution()));
1583
1584	LLSD row;
1585	row["id"] = id;
1586
1587	row["columns"][0]["column"] = "name";
1588	// value is filled in by name list control
1589
1590	row["columns"][1]["column"] = "donated";
1591	row["columns"][1]["value"] = donated.getString();
1592
1593	row["columns"][2]["column"] = "online";
1594	row["columns"][2]["value"] = data->getOnlineStatus();
1595	row["columns"][2]["font"] = "SANSSERIF_SMALL";
1596
1597	mMembersList->addElement(row);
1598
1599	mHasMatch = TRUE;
1600}
1601
1602void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, const LLUUID& id)
1603{
1604	// Update ID is used to determine whether member whose id is passed
1605	// into onNameCache() was passed after current or previous user-initiated update.
1606	// This is needed to avoid probable duplication of members in list after changing filter
1607	// or adding of members of another group if gets for their names were called on
1608	// previous update. If this id is from get() called from older update,
1609	// we do nothing.
1610	if (mUdpateSessionID != update_id) return;
1611	
1612	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1613		if (!gdatap) 
1614	{
1615		llwarns << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << llendl;
1616		return;
1617	}
1618	
1619	std::string fullname;
1620	gCacheName->getFullName(id, fullname);
1621
1622	LLGroupMemberData* data;
1623	// trying to avoid unnecessary hash lookups
1624	if (matchesSearchFilter(fullname) && ((data = gdatap->mMembers[id]) != NULL))
1625	{
1626		addMemberToList(id, data);
1627		if(!mMembersList->getEnabled())
1628		{
1629			mMembersList->setEnabled(TRUE);
1630		}
1631	}
1632	
1633}
1634
1635void LLPanelGroupMembersSubTab::updateMembers()
1636{
1637	mPendingMemberUpdate = FALSE;
1638
1639	// Rebuild the members list.
1640
1641	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1642	if (!gdatap) 
1643	{
1644		llwarns << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << llendl;
1645		return;
1646	}
1647
1648	// Make sure all data is still complete.  Incomplete data
1649	// may occur if we refresh.
1650	if (   !gdatap->isMemberDataComplete() 
1651		|| !gdatap->isRoleDataComplete()
1652		|| !gdatap->isRoleMemberDataComplete())
1653	{
1654		return;
1655	}
1656
1657	//cleanup list only for first iretation
1658	if(mMemberProgress == gdatap->mMembers.begin())
1659	{
1660		mMembersList->deleteAllItems();
1661	}
1662
1663
1664	LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
1665	
1666	S32 i = 0;
1667	for( ; mMemberProgress != end && i<UPDATE_MEMBERS_PER_FRAME; 
1668			++mMemberProgress, ++i)
1669	{
1670		if (!mMemberProgress->second)
1671			continue;
1672		// Do filtering on name if it is already in the cache.
1673		std::string fullname;
1674		if (gCacheName->getFullName(mMemberProgress->first, fullname))
1675		{
1676			if (matchesSearchFilter(fullname))
1677			{
1678				addMemberToList(mMemberProgress->first, mMemberProgress->second);
1679			}
1680		}
1681		else
1682		{
1683			// If name is not cached, onNameCache() should be called when it is cached and add this member to list.
1684			gCacheName->get(mMemberProgress->first, FALSE, boost::bind(&LLPanelGroupMembersSubTab::onNameCache,
1685																	   this, mUdpateSessionID, _1));
1686		}
1687	}
1688
1689	if (mMemberProgress == end)
1690	{
1691		if (mHasMatch)
1692		{
1693			mMembersList->setEnabled(TRUE);
1694		}
1695		else
1696		{
1697			mMembersList->setEnabled(FALSE);
1698			mMembersList->setCommentText(std::string("No match."));
1699		}
1700	}
1701	else
1702	{
1703		mPendingMemberUpdate = TRUE;
1704	}
1705
1706	// This should clear the other two lists, since nothing is selected.
1707	handleMemberSelect();
1708}
1709
1710
1711
1712////////////////////////////
1713// LLPanelGroupRolesSubTab
1714////////////////////////////
1715
1716static LLRegisterPanelClassWrapper<LLPanelGroupRolesSubTab> t_panel_group_roles_subtab("panel_group_roles_subtab");
1717
1718LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab()
1719  : LLPanelGroupSubTab(),
1720	mRolesList(NULL),
1721	mAssignedMembersList(NULL),
1722	mAllowedActionsList(NULL),
1723	mRoleName(NULL),
1724	mRoleTitle(NULL),
1725	mRoleDescription(NULL),
1726	mMemberVisibleCheck(NULL),
1727	mDeleteRoleButton(NULL),
1728	mCreateRoleButton(NULL),
1729
1730	mHasRoleChange(FALSE)
1731{
1732}
1733
1734LLPanelGroupRolesSubTab::~LLPanelGroupRolesSubTab()
1735{
1736}
1737
1738BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root)
1739{
1740	LLPanelGroupSubTab::postBuildSubTab(root);
1741
1742	// Upcast parent so we can ask it for sibling controls.
1743	LLPanelGroupRoles* parent = (LLPanelGroupRoles*) root;
1744
1745	// Look recursively from the parent to find all our widgets.
1746	bool recurse = true;
1747	mHeader = parent->getChild<LLPanel>("roles_header", recurse);
1748	mFooter = parent->getChild<LLPanel>("roles_footer", recurse);
1749
1750
1751	mRolesList 		= parent->getChild<LLScrollListCtrl>("role_list", recurse);
1752	mAssignedMembersList	= parent->getChild<LLNameListCtrl>("role_assigned_members", recurse);
1753	mAllowedActionsList	= parent->getChild<LLScrollListCtrl>("role_allowed_actions", recurse);
1754
1755	mRoleName = parent->getChild<LLLineEditor>("role_name", recurse);
1756	mRoleTitle = parent->getChild<LLLineEditor>("role_title", recurse);
1757	mRoleDescription = parent->getChild<LLTextEditor>("role_description", recurse);
1758
1759	mMemberVisibleCheck = parent->getChild<LLCheckBoxCtrl>("role_visible_in_list", recurse);
1760
1761	if (!mRolesList || !mAssignedMembersList || !mAllowedActionsList
1762		|| !mRoleName || !mRoleTitle || !mRoleDescription || !mMemberVisibleCheck)
1763	{
1764		llwarns << "ARG! element not found." << llendl;
1765		return FALSE;
1766	}
1767
1768	mRemoveEveryoneTxt = getString("cant_delete_role");
1769
1770	mCreateRoleButton = 
1771		parent->getChild<LLButton>("role_create", recurse);
1772	if ( mCreateRoleButton )
1773	{
1774		mCreateRoleButton->setClickedCallback(onCreateRole, this);
1775		mCreateRoleButton->setEnabled(FALSE);
1776	}
1777	
1778	mDeleteRoleButton =  
1779		parent->getChild<LLButton>("role_delete", recurse);
1780	if ( mDeleteRoleButton )
1781	{
1782		mDeleteRoleButton->setClickedCallback(onDeleteRole, this);
1783		mDeleteRoleButton->setEnabled(FALSE);
1784	}
1785
1786	mRolesList->setCommitOnSelectionChange(TRUE);
1787	mRolesList->setCommitCallback(onRoleSelect, this);
1788
1789	mAssignedMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
1790
1791	mMemberVisibleCheck->setCommitCallback(onMemberVisibilityChange, this);
1792
1793	mAllowedActionsList->setCommitOnSelectionChange(TRUE);
1794
1795	mRoleName->setCommitOnFocusLost(TRUE);
1796	mRoleName->setKeystrokeCallback(onPropertiesKey, this);
1797
1798	mRoleTitle->setCommitOnFocusLost(TRUE);
1799	mRoleTitle->setKeystrokeCallback(onPropertiesKey, this);
1800
1801	mRoleDescription->setCommitOnFocusLost(TRUE);
1802	mRoleDescription->setKeystrokeCallback(boost::bind(&LLPanelGroupRolesSubTab::onDescriptionKeyStroke, this, _1));
1803
1804	setFooterEnabled(FALSE);
1805
1806	return TRUE;
1807}
1808
1809void LLPanelGroupRolesSubTab::activate()
1810{
1811	LLPanelGroupSubTab::activate();
1812
1813	mRolesList->deselectAllItems();
1814	mAssignedMembersList->deleteAllItems();
1815	mAllowedActionsList->deleteAllItems();
1816	mRoleName->clear();
1817	mRoleDescription->clear();
1818	mRoleTitle->clear();
1819
1820	setFooterEnabled(FALSE);
1821
1822	mHasRoleChange = FALSE;
1823	update(GC_ALL);
1824}
1825
1826void LLPanelGroupRolesSubTab::deactivate()
1827{
1828	lldebugs << "LLPanelGroupRolesSubTab::deactivate()" << llendl;
1829
1830	LLPanelGroupSubTab::deactivate();
1831}
1832
1833bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg)
1834{
1835	lldebugs << "LLPanelGroupRolesSubTab::needsApply()" << llendl;
1836
1837	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
1838
1839	return (mHasRoleChange								// Text changed in current role
1840			|| (gdatap && gdatap->pendingRoleChanges()));	// Pending role changes in the group
1841}
1842
1843bool LLPanelGroupRolesSubTab::apply(std::string& mesg)
1844{
1845	lldebugs << "LLPanelGroupRolesSubTab::apply()" << llendl;
1846
1847	saveRoleChanges(true);
1848
1849	LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID);
1850
1851	notifyObservers();
1852
1853	return true;
1854}
1855
1856void LLPanelGroupRolesSubTab::cancel()
1857{
1858	mHasRoleChange = FALSE;
1859	LLGroupMgr::getInstance()->cancelGroupRoleChanges(mGroupID);
1860
1861	notifyObservers();
1862}
1863
1864LLSD LLPanelGroupRolesSubTab::createRoleItem(const LLUUID& role_id, 
1865								 std::string name, 
1866								 std::string title, 
1867								 S32 members)
1868{
1869	LLSD row;
1870	row["id"] = role_id;
1871
1872	row["columns"][0]["column"] = "name";
1873	row["columns"][0]["value"] = name;
1874
1875	row["columns"][1]["column"] = "title";
1876	row[

Large files files are truncated, but you can click here to view the full file