PageRenderTime 711ms CodeModel.GetById 181ms app.highlight 384ms RepoModel.GetById 139ms app.codeStats 1ms

/indra/newview/llpanelgroupinvite.cpp

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