summaryrefslogtreecommitdiff
path: root/indra/newview/llpanelgroupinvite.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llpanelgroupinvite.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/newview/llpanelgroupinvite.cpp')
-rw-r--r--indra/newview/llpanelgroupinvite.cpp1400
1 files changed, 700 insertions, 700 deletions
diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp
index 34307c9951..b169bfb623 100644
--- a/indra/newview/llpanelgroupinvite.cpp
+++ b/indra/newview/llpanelgroupinvite.cpp
@@ -1,700 +1,700 @@
-/**
- * @file llpanelgroupinvite.cpp
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanelgroupinvite.h"
-
-#include "llagent.h"
-#include "llavatarnamecache.h"
-#include "llfloateravatarpicker.h"
-#include "llbutton.h"
-#include "llcallingcard.h"
-#include "llcombobox.h"
-#include "llgroupactions.h"
-#include "llgroupmgr.h"
-#include "llnamelistctrl.h"
-#include "llnotificationsutil.h"
-#include "llscrolllistitem.h"
-#include "llspinctrl.h"
-#include "lltextbox.h"
-#include "llviewerobject.h"
-#include "llviewerobjectlist.h"
-#include "lluictrlfactory.h"
-#include "llviewerwindow.h"
-
-class LLPanelGroupInvite::impl
-{
-public:
- impl(const LLUUID& group_id);
- ~impl();
-
- void addUsers(const std::vector<std::string>& names,
- const uuid_vec_t& agent_ids);
- void submitInvitations();
- void addRoleNames(LLGroupMgrGroupData* gdatap);
- void handleRemove();
- void handleSelection();
-
- static void callbackClickCancel(void* userdata);
- static void callbackClickOK(void* userdata);
- static void callbackClickAdd(void* userdata);
- static void callbackClickRemove(void* userdata);
- static void callbackSelect(LLUICtrl* ctrl, void* userdata);
- static void callbackAddUsers(const uuid_vec_t& agent_ids,
- void* user_data);
-
- static void onAvatarNameCache(const LLUUID& agent_id,
- const LLAvatarName& av_name,
- void* user_data);
-
- bool inviteOwnerCallback(const LLSD& notification, const LLSD& response);
-
-public:
- LLUUID mGroupID;
-
- std::string mLoadingText;
- LLNameListCtrl *mInvitees;
- LLComboBox *mRoleNames;
- LLButton *mOKButton;
- LLButton *mRemoveButton;
- LLTextBox *mGroupName;
- std::string mOwnerWarning;
- std::string mAlreadyInGroup;
- std::string mTooManySelected;
- bool mConfirmedOwnerInvite;
- std::set<LLUUID> mInviteeIDs;
-
- void (*mCloseCallback)(void* data);
-
- void* mCloseCallbackUserData;
-
- boost::signals2::connection mAvatarNameCacheConnection;
-};
-
-
-LLPanelGroupInvite::impl::impl(const LLUUID& group_id):
- mGroupID( group_id ),
- mLoadingText (),
- mInvitees ( NULL ),
- mRoleNames( NULL ),
- mOKButton ( NULL ),
- mRemoveButton( NULL ),
- mGroupName( NULL ),
- mConfirmedOwnerInvite( false ),
- mCloseCallback( NULL ),
- mCloseCallbackUserData( NULL ),
- mAvatarNameCacheConnection()
-{
-}
-
-LLPanelGroupInvite::impl::~impl()
-{
- if (mAvatarNameCacheConnection.connected())
- {
- mAvatarNameCacheConnection.disconnect();
- }
-}
-
-const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap.
-
-void LLPanelGroupInvite::impl::addUsers(const std::vector<std::string>& names,
- const uuid_vec_t& agent_ids)
-{
- std::string name;
- LLUUID id;
-
- if (names.size() + mInviteeIDs.size() > MAX_GROUP_INVITES)
- {
- // Fail! Show a warning and don't add any names.
- LLSD msg;
- msg["MESSAGE"] = mTooManySelected;
- LLNotificationsUtil::add("GenericAlert", msg);
- return;
- }
-
- for (S32 i = 0; i < (S32)names.size(); i++)
- {
- name = names[i];
- id = agent_ids[i];
-
- // Make sure this agent isn't already in the list.
- if (mInviteeIDs.find(id) != mInviteeIDs.end())
- {
- continue;
- }
-
- //add the name to the names list
- LLSD row;
- row["id"] = id;
- row["columns"][0]["value"] = name;
-
- mInvitees->addElement(row);
- mInviteeIDs.insert(id);
- }
-}
-
-void LLPanelGroupInvite::impl::submitInvitations()
-{
- std::map<LLUUID, LLUUID> role_member_pairs;
-
- LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
-
- // Default to everyone role.
- LLUUID role_id = LLUUID::null;
-
- if (mRoleNames)
- {
- role_id = mRoleNames->getCurrentID();
-
- // owner role: display confirmation and wait for callback
- if ((role_id == gdatap->mOwnerRole) && (!mConfirmedOwnerInvite))
- {
- LLSD args;
- args["MESSAGE"] = mOwnerWarning;
- LLNotificationsUtil::add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupInvite::impl::inviteOwnerCallback, this, _1, _2));
- return; // we'll be called again if user confirms
- }
- }
-
- bool already_in_group = false;
- //loop over the users
- std::vector<LLScrollListItem*> items = mInvitees->getAllData();
- for (std::vector<LLScrollListItem*>::iterator iter = items.begin();
- iter != items.end(); ++iter)
- {
- LLScrollListItem* item = *iter;
- if(LLGroupActions::isAvatarMemberOfGroup(mGroupID, item->getUUID()))
- {
- already_in_group = true;
- continue;
- }
- role_member_pairs[item->getUUID()] = role_id;
- }
-
- if (role_member_pairs.size() > MAX_GROUP_INVITES)
- {
- // Fail!
- LLSD msg;
- msg["MESSAGE"] = mTooManySelected;
- LLNotificationsUtil::add("GenericAlert", msg);
- (*mCloseCallback)(mCloseCallbackUserData);
- return;
- }
-
- LLGroupMgr::getInstance()->sendGroupMemberInvites(mGroupID, role_member_pairs);
-
- if(already_in_group)
- {
- LLSD msg;
- msg["MESSAGE"] = mAlreadyInGroup;
- LLNotificationsUtil::add("GenericAlert", msg);
- }
-
- //then close
- (*mCloseCallback)(mCloseCallbackUserData);
-}
-
-bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-
- switch(option)
- {
- case 0:
- // user confirmed that they really want a new group owner
- mConfirmedOwnerInvite = true;
- submitInvitations();
- break;
- case 1:
- // fall through
- default:
- break;
- }
- return false;
-}
-
-
-
-void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
-{
- LLGroupMgrGroupData::member_list_t::iterator agent_iter =
- gdatap->mMembers.find(gAgent.getID());
-
- //loop over the agent's roles in the group
- //then add those roles to the list of roles that the agent
- //can invite people to be.
- //if the user is the owner then we add
- //all of the roles in the group,
- //else if they have the add to roles power
- //we add every role but owner,
- //else if they have the limited add to roles power
- //we add every role the user is in,
- //else we just add to everyone
- bool is_owner = false;
- bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER);
- bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER_LIMITED);
- LLGroupMemberData* member_data = NULL;
- //get the member data for the agent if it exists
- if (agent_iter != gdatap->mMembers.end())
- {
- member_data = (*agent_iter).second;
- if (member_data && mRoleNames)
- {
- is_owner = member_data->isOwner();
- }//end if member data is not null
- }//end if agent is in the group
-
-
-
- LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
- LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
-
- //populate the role list:
- for ( ; rit != end; ++rit)
- {
- LLUUID role_id = (*rit).first;
- LLRoleData rd;
- if ( gdatap->getRoleData(role_id,rd) )
- {
- // Owners can add any role.
- if ( is_owner
- // Even 'can_assign_any' can't add owner role.
- || (can_assign_any && role_id != gdatap->mOwnerRole)
- // Add all roles user is in
- || (can_assign_limited && member_data && member_data->isInRole(role_id))
- // Everyone role.
- || role_id == LLUUID::null )
- {
- mRoleNames->add(rd.mRoleName,
- role_id,
- ADD_BOTTOM);
- }
- }
- }
-}
-
-//static
-void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata)
-{
- LLPanelGroupInvite* panelp = (LLPanelGroupInvite*) userdata;
-
- if ( panelp )
- {
- //Right now this is hard coded with some knowledge that it is part
- //of a floater since the avatar picker needs to be added as a dependent
- //floater to the parent floater.
- //Soon the avatar picker will be embedded into this panel
- //instead of being it's own separate floater. But that is next week.
- //This will do for now. -jwolk May 10, 2006
- LLView * button = panelp->findChild<LLButton>("add_button");
- LLFloater * root_floater = gFloaterView->getParentFloater(panelp);
- LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(
- boost::bind(impl::callbackAddUsers, _1, panelp->mImplementation), true, false, false, root_floater->getName(), button);
- if (picker)
- {
- root_floater->addDependentFloater(picker);
- }
- }
-}
-
-//static
-void LLPanelGroupInvite::impl::callbackClickRemove(void* userdata)
-{
- impl* selfp = (impl*) userdata;
-
- if ( selfp ) selfp->handleRemove();
-}
-
-void LLPanelGroupInvite::impl::handleRemove()
-{
- // Check if there is anything selected.
- std::vector<LLScrollListItem*> selection =
- mInvitees->getAllSelected();
- if (selection.empty()) return;
-
- std::vector<LLScrollListItem*>::iterator iter;
- for(iter = selection.begin(); iter != selection.end(); ++iter)
- {
- mInviteeIDs.erase( (*iter)->getUUID() );
- }
-
- // Remove all selected invitees.
- mInvitees->deleteSelectedItems();
- mRemoveButton->setEnabled(false);
-}
-
-// static
-void LLPanelGroupInvite::impl::callbackSelect(
- LLUICtrl* ctrl, void* userdata)
-{
- impl* selfp = (impl*) userdata;
- if ( selfp ) selfp->handleSelection();
-}
-
-void LLPanelGroupInvite::impl::handleSelection()
-{
- // Check if there is anything selected.
- std::vector<LLScrollListItem*> selection =
- mInvitees->getAllSelected();
- if (selection.empty())
- {
- mRemoveButton->setEnabled(false);
- }
- else
- {
- mRemoveButton->setEnabled(true);
- }
-}
-
-void LLPanelGroupInvite::impl::callbackClickCancel(void* userdata)
-{
- impl* selfp = (impl*) userdata;
-
- if ( selfp )
- {
- (*(selfp->mCloseCallback))(selfp->mCloseCallbackUserData);
- }
-}
-
-void LLPanelGroupInvite::impl::callbackClickOK(void* userdata)
-{
- impl* selfp = (impl*) userdata;
-
- if ( selfp ) selfp->submitInvitations();
-}
-
-
-
-//static
-void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data)
-{
- std::vector<std::string> names;
- for (S32 i = 0; i < (S32)agent_ids.size(); i++)
- {
- LLAvatarName av_name;
- if (LLAvatarNameCache::get(agent_ids[i], &av_name))
- {
- LLPanelGroupInvite::impl::onAvatarNameCache(agent_ids[i], av_name, user_data);
- }
- else
- {
- impl* selfp = (impl*) user_data;
- if (selfp)
- {
- if (selfp->mAvatarNameCacheConnection.connected())
- {
- selfp->mAvatarNameCacheConnection.disconnect();
- }
- // *TODO : Add a callback per avatar name being fetched.
- selfp->mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_ids[i],boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, _1, _2, user_data));
- }
- }
- }
-
-}
-
-void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id,
- const LLAvatarName& av_name,
- void* user_data)
-{
- impl* selfp = (impl*) user_data;
-
- if (selfp)
- {
- if (selfp->mAvatarNameCacheConnection.connected())
- {
- selfp->mAvatarNameCacheConnection.disconnect();
- }
- std::vector<std::string> names;
- uuid_vec_t agent_ids;
- agent_ids.push_back(agent_id);
- names.push_back(av_name.getCompleteName());
-
- selfp->addUsers(names, agent_ids);
- }
-}
-
-
-LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id)
- : LLPanel(),
- mImplementation(new impl(group_id)),
- mPendingUpdate(false)
-{
- // Pass on construction of this panel to the control factory.
- buildFromFile( "panel_group_invite.xml");
-}
-
-LLPanelGroupInvite::~LLPanelGroupInvite()
-{
- delete mImplementation;
-}
-
-void LLPanelGroupInvite::setCloseCallback(void (*close_callback)(void*),
- void* data)
-{
- mImplementation->mCloseCallback = close_callback;
- mImplementation->mCloseCallbackUserData = data;
-}
-
-void LLPanelGroupInvite::clear()
-{
- mStoreSelected = LLUUID::null;
- mImplementation->mInvitees->deleteAllItems();
- mImplementation->mRoleNames->clear();
- mImplementation->mRoleNames->removeall();
- mImplementation->mOKButton->setEnabled(false);
- mImplementation->mInviteeIDs.clear();
-}
-
-void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
-{
- std::vector<std::string> names;
- for (S32 i = 0; i < (S32)agent_ids.size(); i++)
- {
- std::string fullname;
- LLUUID agent_id = agent_ids[i];
- LLViewerObject* dest = gObjectList.findObject(agent_id);
- if(dest && dest->isAvatar())
- {
- LLNameValue* nvfirst = dest->getNVPair("FirstName");
- LLNameValue* nvlast = dest->getNVPair("LastName");
- if(nvfirst && nvlast)
- {
- fullname = LLCacheName::buildFullName(
- nvfirst->getString(), nvlast->getString());
-
- }
- if (!fullname.empty())
- {
- names.push_back(fullname);
- }
- else
- {
- LL_WARNS() << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << LL_ENDL;
- names.push_back("(Unknown)");
- }
- }
- else
- {
- //looks like user try to invite offline avatar (or the avatar from the other region)
- //for offline avatar_id gObjectList.findObject() will return null
- //so we need to do this additional search in avatar tracker, see EXT-4732
- LLAvatarName av_name;
- if (!LLAvatarNameCache::get(agent_id, &av_name))
- {
- // actually it should happen, just in case
- //LLAvatarNameCache::get(LLUUID(agent_id), boost::bind(&LLPanelGroupInvite::addUserCallback, this, _1, _2));
- // for this special case!
- //when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence
- // removed id will be added in callback
- agent_ids.erase(agent_ids.begin() + i);
- }
- else
- {
- names.push_back(av_name.getAccountName());
- }
- }
- }
- mImplementation->addUsers(names, agent_ids);
-}
-
-void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const LLAvatarName& av_name)
-{
- std::vector<std::string> names;
- uuid_vec_t agent_ids;
- agent_ids.push_back(id);
- names.push_back(av_name.getAccountName());
-
- mImplementation->addUsers(names, agent_ids);
-}
-
-void LLPanelGroupInvite::draw()
-{
- LLPanel::draw();
- if (mPendingUpdate)
- {
- updateLists();
- }
-}
-
-void LLPanelGroupInvite::update()
-{
- mPendingUpdate = false;
- if (mImplementation->mGroupName)
- {
- mImplementation->mGroupName->setText(mImplementation->mLoadingText);
- }
- if ( mImplementation->mRoleNames )
- {
- mStoreSelected = mImplementation->mRoleNames->getCurrentID();
- mImplementation->mRoleNames->clear();
- mImplementation->mRoleNames->removeall();
- mImplementation->mRoleNames->add(mImplementation->mLoadingText, LLUUID::null, ADD_BOTTOM);
- mImplementation->mRoleNames->setCurrentByID(LLUUID::null);
- }
-
- updateLists();
-}
-
-void LLPanelGroupInvite::updateLists()
-{
- LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
- bool waiting = false;
-
- if (gdatap)
- {
- if (gdatap->isGroupPropertiesDataComplete())
- {
- if (mImplementation->mGroupName)
- {
- mImplementation->mGroupName->setText(gdatap->mName);
- }
- }
- else
- {
- waiting = true;
- }
- if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()
- && (gdatap->isRoleMemberDataComplete() || !gdatap->mMembers.size())) // MAINT-5270: large groups receives an empty members list without some powers, so RoleMemberData wouldn't be complete for them
- {
- if ( mImplementation->mRoleNames )
- {
- mImplementation->mRoleNames->clear();
- mImplementation->mRoleNames->removeall();
-
- //add the role names and select the everybody role by default
- mImplementation->addRoleNames(gdatap);
- mImplementation->mRoleNames->setCurrentByID(mStoreSelected);
- }
- }
- else
- {
- waiting = true;
- }
- }
- else
- {
- waiting = true;
- }
-
- if (waiting)
- {
- if (!mPendingUpdate)
- {
- // Note: this will partially fail if some requests are already in progress
- LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID);
- LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mImplementation->mGroupID);
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID);
- }
- else if (gdatap)
- {
- // restart requests that were interrupted/dropped/failed to start
- if (!gdatap->isRoleDataPending() && !gdatap->isRoleDataComplete())
- {
- LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
- }
- if (!gdatap->isRoleMemberDataPending() && !gdatap->isRoleMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mImplementation->mGroupID);
- }
- // sendCapGroupMembersRequest has a per frame send limitation that could have
- // interrupted previous request
- if (!gdatap->isMemberDataPending() && !gdatap->isMemberDataComplete())
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID);
- }
- }
- mPendingUpdate = true;
- }
- else
- {
- mPendingUpdate = false;
- if (mImplementation->mOKButton && mImplementation->mRoleNames->getItemCount())
- {
- mImplementation->mOKButton->setEnabled(true);
- }
- }
-}
-
-bool LLPanelGroupInvite::postBuild()
-{
- constexpr bool recurse = true;
-
- mImplementation->mLoadingText = getString("loading");
- mImplementation->mRoleNames = getChild<LLComboBox>("role_name",
- recurse);
- mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse);
- mImplementation->mInvitees =
- getChild<LLNameListCtrl>("invitee_list", recurse);
- if ( mImplementation->mInvitees )
- {
- mImplementation->mInvitees->setCommitOnSelectionChange(true);
- mImplementation->mInvitees->setCommitCallback(impl::callbackSelect, mImplementation);
- }
-
- LLButton* button = getChild<LLButton>("add_button", recurse);
- if ( button )
- {
- // default to opening avatarpicker automatically
- // (*impl::callbackClickAdd)((void*)this);
- button->setClickedCallback(impl::callbackClickAdd, this);
- }
-
- mImplementation->mRemoveButton =
- getChild<LLButton>("remove_button", recurse);
- if ( mImplementation->mRemoveButton )
- {
- mImplementation->mRemoveButton->setClickedCallback(impl::callbackClickRemove, mImplementation);
- mImplementation->mRemoveButton->setEnabled(false);
- }
-
- mImplementation->mOKButton =
- getChild<LLButton>("invite_button", recurse);
- if ( mImplementation->mOKButton )
- {
- mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation);
- mImplementation->mOKButton->setEnabled(false);
- }
-
- button = getChild<LLButton>("cancel_button", recurse);
- if ( button )
- {
- button->setClickedCallback(impl::callbackClickCancel, mImplementation);
- }
-
- mImplementation->mOwnerWarning = getString("confirm_invite_owner_str");
- mImplementation->mAlreadyInGroup = getString("already_in_group");
- mImplementation->mTooManySelected = getString("invite_selection_too_large");
-
- update();
-
- return (mImplementation->mRoleNames &&
- mImplementation->mInvitees &&
- mImplementation->mRemoveButton);
-}
+/**
+ * @file llpanelgroupinvite.cpp
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanelgroupinvite.h"
+
+#include "llagent.h"
+#include "llavatarnamecache.h"
+#include "llfloateravatarpicker.h"
+#include "llbutton.h"
+#include "llcallingcard.h"
+#include "llcombobox.h"
+#include "llgroupactions.h"
+#include "llgroupmgr.h"
+#include "llnamelistctrl.h"
+#include "llnotificationsutil.h"
+#include "llscrolllistitem.h"
+#include "llspinctrl.h"
+#include "lltextbox.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "lluictrlfactory.h"
+#include "llviewerwindow.h"
+
+class LLPanelGroupInvite::impl
+{
+public:
+ impl(const LLUUID& group_id);
+ ~impl();
+
+ void addUsers(const std::vector<std::string>& names,
+ const uuid_vec_t& agent_ids);
+ void submitInvitations();
+ void addRoleNames(LLGroupMgrGroupData* gdatap);
+ void handleRemove();
+ void handleSelection();
+
+ static void callbackClickCancel(void* userdata);
+ static void callbackClickOK(void* userdata);
+ static void callbackClickAdd(void* userdata);
+ static void callbackClickRemove(void* userdata);
+ static void callbackSelect(LLUICtrl* ctrl, void* userdata);
+ static void callbackAddUsers(const uuid_vec_t& agent_ids,
+ void* user_data);
+
+ static void onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ void* user_data);
+
+ bool inviteOwnerCallback(const LLSD& notification, const LLSD& response);
+
+public:
+ LLUUID mGroupID;
+
+ std::string mLoadingText;
+ LLNameListCtrl *mInvitees;
+ LLComboBox *mRoleNames;
+ LLButton *mOKButton;
+ LLButton *mRemoveButton;
+ LLTextBox *mGroupName;
+ std::string mOwnerWarning;
+ std::string mAlreadyInGroup;
+ std::string mTooManySelected;
+ bool mConfirmedOwnerInvite;
+ std::set<LLUUID> mInviteeIDs;
+
+ void (*mCloseCallback)(void* data);
+
+ void* mCloseCallbackUserData;
+
+ boost::signals2::connection mAvatarNameCacheConnection;
+};
+
+
+LLPanelGroupInvite::impl::impl(const LLUUID& group_id):
+ mGroupID( group_id ),
+ mLoadingText (),
+ mInvitees ( NULL ),
+ mRoleNames( NULL ),
+ mOKButton ( NULL ),
+ mRemoveButton( NULL ),
+ mGroupName( NULL ),
+ mConfirmedOwnerInvite( false ),
+ mCloseCallback( NULL ),
+ mCloseCallbackUserData( NULL ),
+ mAvatarNameCacheConnection()
+{
+}
+
+LLPanelGroupInvite::impl::~impl()
+{
+ if (mAvatarNameCacheConnection.connected())
+ {
+ mAvatarNameCacheConnection.disconnect();
+ }
+}
+
+const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap.
+
+void LLPanelGroupInvite::impl::addUsers(const std::vector<std::string>& names,
+ const uuid_vec_t& agent_ids)
+{
+ std::string name;
+ LLUUID id;
+
+ if (names.size() + mInviteeIDs.size() > MAX_GROUP_INVITES)
+ {
+ // Fail! Show a warning and don't add any names.
+ LLSD msg;
+ msg["MESSAGE"] = mTooManySelected;
+ LLNotificationsUtil::add("GenericAlert", msg);
+ return;
+ }
+
+ for (S32 i = 0; i < (S32)names.size(); i++)
+ {
+ name = names[i];
+ id = agent_ids[i];
+
+ // Make sure this agent isn't already in the list.
+ if (mInviteeIDs.find(id) != mInviteeIDs.end())
+ {
+ continue;
+ }
+
+ //add the name to the names list
+ LLSD row;
+ row["id"] = id;
+ row["columns"][0]["value"] = name;
+
+ mInvitees->addElement(row);
+ mInviteeIDs.insert(id);
+ }
+}
+
+void LLPanelGroupInvite::impl::submitInvitations()
+{
+ std::map<LLUUID, LLUUID> role_member_pairs;
+
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+
+ // Default to everyone role.
+ LLUUID role_id = LLUUID::null;
+
+ if (mRoleNames)
+ {
+ role_id = mRoleNames->getCurrentID();
+
+ // owner role: display confirmation and wait for callback
+ if ((role_id == gdatap->mOwnerRole) && (!mConfirmedOwnerInvite))
+ {
+ LLSD args;
+ args["MESSAGE"] = mOwnerWarning;
+ LLNotificationsUtil::add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupInvite::impl::inviteOwnerCallback, this, _1, _2));
+ return; // we'll be called again if user confirms
+ }
+ }
+
+ bool already_in_group = false;
+ //loop over the users
+ std::vector<LLScrollListItem*> items = mInvitees->getAllData();
+ for (std::vector<LLScrollListItem*>::iterator iter = items.begin();
+ iter != items.end(); ++iter)
+ {
+ LLScrollListItem* item = *iter;
+ if(LLGroupActions::isAvatarMemberOfGroup(mGroupID, item->getUUID()))
+ {
+ already_in_group = true;
+ continue;
+ }
+ role_member_pairs[item->getUUID()] = role_id;
+ }
+
+ if (role_member_pairs.size() > MAX_GROUP_INVITES)
+ {
+ // Fail!
+ LLSD msg;
+ msg["MESSAGE"] = mTooManySelected;
+ LLNotificationsUtil::add("GenericAlert", msg);
+ (*mCloseCallback)(mCloseCallbackUserData);
+ return;
+ }
+
+ LLGroupMgr::getInstance()->sendGroupMemberInvites(mGroupID, role_member_pairs);
+
+ if(already_in_group)
+ {
+ LLSD msg;
+ msg["MESSAGE"] = mAlreadyInGroup;
+ LLNotificationsUtil::add("GenericAlert", msg);
+ }
+
+ //then close
+ (*mCloseCallback)(mCloseCallbackUserData);
+}
+
+bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ switch(option)
+ {
+ case 0:
+ // user confirmed that they really want a new group owner
+ mConfirmedOwnerInvite = true;
+ submitInvitations();
+ break;
+ case 1:
+ // fall through
+ default:
+ break;
+ }
+ return false;
+}
+
+
+
+void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
+{
+ LLGroupMgrGroupData::member_list_t::iterator agent_iter =
+ gdatap->mMembers.find(gAgent.getID());
+
+ //loop over the agent's roles in the group
+ //then add those roles to the list of roles that the agent
+ //can invite people to be.
+ //if the user is the owner then we add
+ //all of the roles in the group,
+ //else if they have the add to roles power
+ //we add every role but owner,
+ //else if they have the limited add to roles power
+ //we add every role the user is in,
+ //else we just add to everyone
+ bool is_owner = false;
+ bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER);
+ bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
+ GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ LLGroupMemberData* member_data = NULL;
+ //get the member data for the agent if it exists
+ if (agent_iter != gdatap->mMembers.end())
+ {
+ member_data = (*agent_iter).second;
+ if (member_data && mRoleNames)
+ {
+ is_owner = member_data->isOwner();
+ }//end if member data is not null
+ }//end if agent is in the group
+
+
+
+ LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
+ LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
+
+ //populate the role list:
+ for ( ; rit != end; ++rit)
+ {
+ LLUUID role_id = (*rit).first;
+ LLRoleData rd;
+ if ( gdatap->getRoleData(role_id,rd) )
+ {
+ // Owners can add any role.
+ if ( is_owner
+ // Even 'can_assign_any' can't add owner role.
+ || (can_assign_any && role_id != gdatap->mOwnerRole)
+ // Add all roles user is in
+ || (can_assign_limited && member_data && member_data->isInRole(role_id))
+ // Everyone role.
+ || role_id == LLUUID::null )
+ {
+ mRoleNames->add(rd.mRoleName,
+ role_id,
+ ADD_BOTTOM);
+ }
+ }
+ }
+}
+
+//static
+void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata)
+{
+ LLPanelGroupInvite* panelp = (LLPanelGroupInvite*) userdata;
+
+ if ( panelp )
+ {
+ //Right now this is hard coded with some knowledge that it is part
+ //of a floater since the avatar picker needs to be added as a dependent
+ //floater to the parent floater.
+ //Soon the avatar picker will be embedded into this panel
+ //instead of being it's own separate floater. But that is next week.
+ //This will do for now. -jwolk May 10, 2006
+ LLView * button = panelp->findChild<LLButton>("add_button");
+ LLFloater * root_floater = gFloaterView->getParentFloater(panelp);
+ LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(
+ boost::bind(impl::callbackAddUsers, _1, panelp->mImplementation), true, false, false, root_floater->getName(), button);
+ if (picker)
+ {
+ root_floater->addDependentFloater(picker);
+ }
+ }
+}
+
+//static
+void LLPanelGroupInvite::impl::callbackClickRemove(void* userdata)
+{
+ impl* selfp = (impl*) userdata;
+
+ if ( selfp ) selfp->handleRemove();
+}
+
+void LLPanelGroupInvite::impl::handleRemove()
+{
+ // Check if there is anything selected.
+ std::vector<LLScrollListItem*> selection =
+ mInvitees->getAllSelected();
+ if (selection.empty()) return;
+
+ std::vector<LLScrollListItem*>::iterator iter;
+ for(iter = selection.begin(); iter != selection.end(); ++iter)
+ {
+ mInviteeIDs.erase( (*iter)->getUUID() );
+ }
+
+ // Remove all selected invitees.
+ mInvitees->deleteSelectedItems();
+ mRemoveButton->setEnabled(false);
+}
+
+// static
+void LLPanelGroupInvite::impl::callbackSelect(
+ LLUICtrl* ctrl, void* userdata)
+{
+ impl* selfp = (impl*) userdata;
+ if ( selfp ) selfp->handleSelection();
+}
+
+void LLPanelGroupInvite::impl::handleSelection()
+{
+ // Check if there is anything selected.
+ std::vector<LLScrollListItem*> selection =
+ mInvitees->getAllSelected();
+ if (selection.empty())
+ {
+ mRemoveButton->setEnabled(false);
+ }
+ else
+ {
+ mRemoveButton->setEnabled(true);
+ }
+}
+
+void LLPanelGroupInvite::impl::callbackClickCancel(void* userdata)
+{
+ impl* selfp = (impl*) userdata;
+
+ if ( selfp )
+ {
+ (*(selfp->mCloseCallback))(selfp->mCloseCallbackUserData);
+ }
+}
+
+void LLPanelGroupInvite::impl::callbackClickOK(void* userdata)
+{
+ impl* selfp = (impl*) userdata;
+
+ if ( selfp ) selfp->submitInvitations();
+}
+
+
+
+//static
+void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data)
+{
+ std::vector<std::string> names;
+ for (S32 i = 0; i < (S32)agent_ids.size(); i++)
+ {
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(agent_ids[i], &av_name))
+ {
+ LLPanelGroupInvite::impl::onAvatarNameCache(agent_ids[i], av_name, user_data);
+ }
+ else
+ {
+ impl* selfp = (impl*) user_data;
+ if (selfp)
+ {
+ if (selfp->mAvatarNameCacheConnection.connected())
+ {
+ selfp->mAvatarNameCacheConnection.disconnect();
+ }
+ // *TODO : Add a callback per avatar name being fetched.
+ selfp->mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_ids[i],boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, _1, _2, user_data));
+ }
+ }
+ }
+
+}
+
+void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ void* user_data)
+{
+ impl* selfp = (impl*) user_data;
+
+ if (selfp)
+ {
+ if (selfp->mAvatarNameCacheConnection.connected())
+ {
+ selfp->mAvatarNameCacheConnection.disconnect();
+ }
+ std::vector<std::string> names;
+ uuid_vec_t agent_ids;
+ agent_ids.push_back(agent_id);
+ names.push_back(av_name.getCompleteName());
+
+ selfp->addUsers(names, agent_ids);
+ }
+}
+
+
+LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id)
+ : LLPanel(),
+ mImplementation(new impl(group_id)),
+ mPendingUpdate(false)
+{
+ // Pass on construction of this panel to the control factory.
+ buildFromFile( "panel_group_invite.xml");
+}
+
+LLPanelGroupInvite::~LLPanelGroupInvite()
+{
+ delete mImplementation;
+}
+
+void LLPanelGroupInvite::setCloseCallback(void (*close_callback)(void*),
+ void* data)
+{
+ mImplementation->mCloseCallback = close_callback;
+ mImplementation->mCloseCallbackUserData = data;
+}
+
+void LLPanelGroupInvite::clear()
+{
+ mStoreSelected = LLUUID::null;
+ mImplementation->mInvitees->deleteAllItems();
+ mImplementation->mRoleNames->clear();
+ mImplementation->mRoleNames->removeall();
+ mImplementation->mOKButton->setEnabled(false);
+ mImplementation->mInviteeIDs.clear();
+}
+
+void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
+{
+ std::vector<std::string> names;
+ for (S32 i = 0; i < (S32)agent_ids.size(); i++)
+ {
+ std::string fullname;
+ LLUUID agent_id = agent_ids[i];
+ LLViewerObject* dest = gObjectList.findObject(agent_id);
+ if(dest && dest->isAvatar())
+ {
+ LLNameValue* nvfirst = dest->getNVPair("FirstName");
+ LLNameValue* nvlast = dest->getNVPair("LastName");
+ if(nvfirst && nvlast)
+ {
+ fullname = LLCacheName::buildFullName(
+ nvfirst->getString(), nvlast->getString());
+
+ }
+ if (!fullname.empty())
+ {
+ names.push_back(fullname);
+ }
+ else
+ {
+ LL_WARNS() << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << LL_ENDL;
+ names.push_back("(Unknown)");
+ }
+ }
+ else
+ {
+ //looks like user try to invite offline avatar (or the avatar from the other region)
+ //for offline avatar_id gObjectList.findObject() will return null
+ //so we need to do this additional search in avatar tracker, see EXT-4732
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get(agent_id, &av_name))
+ {
+ // actually it should happen, just in case
+ //LLAvatarNameCache::get(LLUUID(agent_id), boost::bind(&LLPanelGroupInvite::addUserCallback, this, _1, _2));
+ // for this special case!
+ //when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence
+ // removed id will be added in callback
+ agent_ids.erase(agent_ids.begin() + i);
+ }
+ else
+ {
+ names.push_back(av_name.getAccountName());
+ }
+ }
+ }
+ mImplementation->addUsers(names, agent_ids);
+}
+
+void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const LLAvatarName& av_name)
+{
+ std::vector<std::string> names;
+ uuid_vec_t agent_ids;
+ agent_ids.push_back(id);
+ names.push_back(av_name.getAccountName());
+
+ mImplementation->addUsers(names, agent_ids);
+}
+
+void LLPanelGroupInvite::draw()
+{
+ LLPanel::draw();
+ if (mPendingUpdate)
+ {
+ updateLists();
+ }
+}
+
+void LLPanelGroupInvite::update()
+{
+ mPendingUpdate = false;
+ if (mImplementation->mGroupName)
+ {
+ mImplementation->mGroupName->setText(mImplementation->mLoadingText);
+ }
+ if ( mImplementation->mRoleNames )
+ {
+ mStoreSelected = mImplementation->mRoleNames->getCurrentID();
+ mImplementation->mRoleNames->clear();
+ mImplementation->mRoleNames->removeall();
+ mImplementation->mRoleNames->add(mImplementation->mLoadingText, LLUUID::null, ADD_BOTTOM);
+ mImplementation->mRoleNames->setCurrentByID(LLUUID::null);
+ }
+
+ updateLists();
+}
+
+void LLPanelGroupInvite::updateLists()
+{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
+ bool waiting = false;
+
+ if (gdatap)
+ {
+ if (gdatap->isGroupPropertiesDataComplete())
+ {
+ if (mImplementation->mGroupName)
+ {
+ mImplementation->mGroupName->setText(gdatap->mName);
+ }
+ }
+ else
+ {
+ waiting = true;
+ }
+ if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()
+ && (gdatap->isRoleMemberDataComplete() || !gdatap->mMembers.size())) // MAINT-5270: large groups receives an empty members list without some powers, so RoleMemberData wouldn't be complete for them
+ {
+ if ( mImplementation->mRoleNames )
+ {
+ mImplementation->mRoleNames->clear();
+ mImplementation->mRoleNames->removeall();
+
+ //add the role names and select the everybody role by default
+ mImplementation->addRoleNames(gdatap);
+ mImplementation->mRoleNames->setCurrentByID(mStoreSelected);
+ }
+ }
+ else
+ {
+ waiting = true;
+ }
+ }
+ else
+ {
+ waiting = true;
+ }
+
+ if (waiting)
+ {
+ if (!mPendingUpdate)
+ {
+ // Note: this will partially fail if some requests are already in progress
+ LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID);
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mImplementation->mGroupID);
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID);
+ }
+ else if (gdatap)
+ {
+ // restart requests that were interrupted/dropped/failed to start
+ if (!gdatap->isRoleDataPending() && !gdatap->isRoleDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
+ }
+ if (!gdatap->isRoleMemberDataPending() && !gdatap->isRoleMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mImplementation->mGroupID);
+ }
+ // sendCapGroupMembersRequest has a per frame send limitation that could have
+ // interrupted previous request
+ if (!gdatap->isMemberDataPending() && !gdatap->isMemberDataComplete())
+ {
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID);
+ }
+ }
+ mPendingUpdate = true;
+ }
+ else
+ {
+ mPendingUpdate = false;
+ if (mImplementation->mOKButton && mImplementation->mRoleNames->getItemCount())
+ {
+ mImplementation->mOKButton->setEnabled(true);
+ }
+ }
+}
+
+bool LLPanelGroupInvite::postBuild()
+{
+ constexpr bool recurse = true;
+
+ mImplementation->mLoadingText = getString("loading");
+ mImplementation->mRoleNames = getChild<LLComboBox>("role_name",
+ recurse);
+ mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse);
+ mImplementation->mInvitees =
+ getChild<LLNameListCtrl>("invitee_list", recurse);
+ if ( mImplementation->mInvitees )
+ {
+ mImplementation->mInvitees->setCommitOnSelectionChange(true);
+ mImplementation->mInvitees->setCommitCallback(impl::callbackSelect, mImplementation);
+ }
+
+ LLButton* button = getChild<LLButton>("add_button", recurse);
+ if ( button )
+ {
+ // default to opening avatarpicker automatically
+ // (*impl::callbackClickAdd)((void*)this);
+ button->setClickedCallback(impl::callbackClickAdd, this);
+ }
+
+ mImplementation->mRemoveButton =
+ getChild<LLButton>("remove_button", recurse);
+ if ( mImplementation->mRemoveButton )
+ {
+ mImplementation->mRemoveButton->setClickedCallback(impl::callbackClickRemove, mImplementation);
+ mImplementation->mRemoveButton->setEnabled(false);
+ }
+
+ mImplementation->mOKButton =
+ getChild<LLButton>("invite_button", recurse);
+ if ( mImplementation->mOKButton )
+ {
+ mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation);
+ mImplementation->mOKButton->setEnabled(false);
+ }
+
+ button = getChild<LLButton>("cancel_button", recurse);
+ if ( button )
+ {
+ button->setClickedCallback(impl::callbackClickCancel, mImplementation);
+ }
+
+ mImplementation->mOwnerWarning = getString("confirm_invite_owner_str");
+ mImplementation->mAlreadyInGroup = getString("already_in_group");
+ mImplementation->mTooManySelected = getString("invite_selection_too_large");
+
+ update();
+
+ return (mImplementation->mRoleNames &&
+ mImplementation->mInvitees &&
+ mImplementation->mRemoveButton);
+}