123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758 |
- /**
- * @file llfloatergroupinvite.cpp
- * @brief Floater to invite new members into a group.
- *
- * $LicenseInfo:firstyear=2006&license=viewergpl$
- *
- * Copyright (c) 2006-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llfloatergroupinvite.h"
- #include "llbutton.h"
- #include "llcombobox.h"
- #include "llnamelistctrl.h"
- #include "lltextbox.h"
- #include "lluictrlfactory.h"
- #include "llagent.h"
- #include "llfloateravatarpicker.h"
- #include "llgroupmgr.h"
- #include "llviewerobjectlist.h"
- #include "llvoavatar.h"
- //
- // Globals
- //
- LLFloaterGroupInvite::instances_map_t LLFloaterGroupInvite::sInstances;
- class LLFloaterGroupInviteData
- {
- public:
- LLFloaterGroupInviteData(LLFloater* self, const LLUUID& group_id)
- : mSelf(self),
- mGroupId(group_id),
- mPanel(NULL)
- {
- }
- ~LLFloaterGroupInviteData()
- {
- }
- LLFloater* mSelf;
- LLUUID mGroupId;
- LLPanelGroupInvite* mPanel;
- };
- //////////////////////////////////////////////////////////////////////
- // LLPanelGroupInvite (forward declaration)
- //////////////////////////////////////////////////////////////////////
- class LLPanelGroupInvite final : public LLPanel
- {
- protected:
- LOG_CLASS(LLPanelGroupInvite);
- void updateLists();
- public:
- LLPanelGroupInvite(const LLUUID& group_id, LLFloater* parent);
- ~LLPanelGroupInvite() override;
- void draw() override;
- bool postBuild() override;
- void clear() override;
-
- void addUsers(uuid_vec_t& agent_ids);
- void update();
- protected:
- class impl;
- impl* mImplementation;
- bool mPendingUpdate;
- LLUUID mStoreSelected;
- };
- //////////////////////////////////////////////////////////////////////
- // LLPanelGroupInvite::impl (*TODO: use LLPanelGroupBulk instead)
- //////////////////////////////////////////////////////////////////////
- class LLPanelGroupInvite::impl
- {
- public:
- impl(const LLUUID& group_id, LLFloater* parent);
- 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 std::vector<std::string>& names,
- const uuid_vec_t& agent_ids,
- void* user_data);
- bool inviteOwnerCallback(const LLSD& notification, const LLSD& response);
- public:
- LLFloater* mParentFloater;
- LLUUID mGroupID;
- LLNameListCtrl* mInvitees;
- LLComboBox* mRoleNames;
- LLButton* mOKButton;
- LLButton* mRemoveButton;
- LLTextBox* mGroupName;
- std::string mLoadingText;
- std::string mOwnerWarning;
- std::string mTooManySelected;
- bool mConfirmedOwnerInvite;
- uuid_list_t mInviteeIDs;
- };
- LLPanelGroupInvite::impl::impl(const LLUUID& group_id, LLFloater* parent)
- : mGroupID(group_id),
- mParentFloater(parent),
- mLoadingText(),
- mInvitees(NULL),
- mRoleNames(NULL),
- mOKButton(NULL),
- mRemoveButton(NULL),
- mGroupName(NULL),
- mConfirmedOwnerInvite(false)
- {
- }
- void LLPanelGroupInvite::impl::addUsers(const std::vector<std::string>& names,
- const uuid_vec_t& agent_ids)
- {
- if ((U32)(names.size() + mInviteeIDs.size()) > MAX_GROUP_INVITES)
- {
- // Fail !... Show a warning and don't add any names.
- LLSD msg;
- msg["MESSAGE"] = mTooManySelected;
- gNotifications.add("GenericAlert", msg);
- return;
- }
- for (S32 i = 0, count = names.size(); i < count; ++i)
- {
- const std::string& name = names[i];
- const LLUUID& id = agent_ids[i];
- if (mInviteeIDs.count(id))
- {
- continue; // Already in list, skip...
- }
- // add the name to the names list
- LLSD row;
- row["id"] = id;
- row["columns"][0]["value"] = name;
- mInvitees->addElement(row);
- mInviteeIDs.emplace(id);
- }
- }
- void LLPanelGroupInvite::impl::submitInvitations()
- {
- LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupID);
- if (!gdatap) return;
- // Default to everyone role.
- LLUUID role_id;
- 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;
- gNotifications.add("GenericAlertYesCancel", args, LLSD(),
- boost::bind(&LLPanelGroupInvite::impl::inviteOwnerCallback,
- this, _1, _2));
- return; // We will be called again if user confirms
- }
- }
- // Loop over the users
- LLGroupMgr::role_member_pairs_t role_member_pairs;
- std::vector<LLScrollListItem*> items = mInvitees->getAllData();
- for (S32 i = 0, count = items.size(); i < count; ++i)
- {
- LLScrollListItem* item = items[i];
- role_member_pairs[item->getUUID()] = role_id;
- }
- if ((U32)role_member_pairs.size() > MAX_GROUP_INVITES)
- {
- // Fail !
- LLSD msg;
- msg["MESSAGE"] = mTooManySelected;
- gNotifications.add("GenericAlert", msg);
- if (mParentFloater) // Paranoia
- {
- mParentFloater->close();
- }
- return;
- }
- gGroupMgr.sendGroupMemberInvites(mGroupID, role_member_pairs);
- // Then close
- if (mParentFloater) // Paranoia
- {
- mParentFloater->close();
- }
- }
- bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification,
- const LLSD& response)
- {
- if (LLNotification::getSelectedOption(notification, response) == 0)
- {
- // User confirmed that they really want a new group owner
- mConfirmedOwnerInvite = true;
- submitInvitations();
- }
- return false;
- }
- void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
- {
- if (!gdatap) return;
- // 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
- LLGroupMgrGroupData::member_list_t::iterator agent_iter =
- gdatap->mMembers.find(gAgentID);
- if (agent_iter != gdatap->mMembers.end())
- {
- member_data = agent_iter->second;
- if (member_data && mRoleNames)
- {
- is_owner = member_data->isOwner();
- }
- }
- // Populate the role list
- for (LLGroupMgrGroupData::role_list_t::iterator
- it = gdatap->mRoles.begin(), end = gdatap->mRoles.end();
- it != end; ++it)
- {
- const LLUUID& role_id = it->first;
- LLRoleData rd;
- if (gdatap->getRoleData(role_id, rd))
- {
- // Owners can add any role.
- if (is_owner ||
- // Even 'can_assign_any' cannot 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.isNull())
- {
- mRoleNames->add(rd.mRoleName, role_id, ADD_BOTTOM);
- }
- }
- }
- }
- //static
- void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata)
- {
- LLPanelGroupInvite* self = (LLPanelGroupInvite*)userdata;
- if (self)
- {
- LLFloater* childp = LLFloaterAvatarPicker::show(callbackAddUsers,
- self->mImplementation);
- if (gFloaterViewp)
- {
- LLFloater* parentp = gFloaterViewp->getParentFloater(self);
- if (parentp)
- {
- parentp->addDependentFloater(childp);
- }
- }
- }
- }
- //static
- void LLPanelGroupInvite::impl::callbackClickRemove(void* userdata)
- {
- impl* self = (impl*)userdata;
- if (self)
- {
- self->handleRemove();
- }
- }
- void LLPanelGroupInvite::impl::handleRemove()
- {
- // Check if there is anything selected.
- std::vector<LLScrollListItem*> selection = mInvitees->getAllSelected();
- if (selection.empty()) return;
- for (S32 i = 0, count = selection.size(); i < count; ++i)
- {
- mInviteeIDs.erase(selection[i]->getUUID());
- }
- // Remove all selected invitees.
- mInvitees->deleteSelectedItems();
- mRemoveButton->setEnabled(false);
- mInviteeIDs.clear();
- }
- // static
- void LLPanelGroupInvite::impl::callbackSelect(LLUICtrl* ctrl, void* userdata)
- {
- impl* self = (impl*)userdata;
- if (self)
- {
- self->handleSelection();
- }
- }
- void LLPanelGroupInvite::impl::handleSelection()
- {
- // Check if there is anything selected.
- mRemoveButton->setEnabled(mInvitees->getFirstSelected() != NULL);
- }
- void LLPanelGroupInvite::impl::callbackClickCancel(void* userdata)
- {
- impl* self = (impl*)userdata;
- if (self && self->mParentFloater)
- {
- self->mParentFloater->close();
- }
- }
- void LLPanelGroupInvite::impl::callbackClickOK(void* userdata)
- {
- impl* self = (impl*)userdata;
- if (self)
- {
- self->submitInvitations();
- }
- }
- //static
- void LLPanelGroupInvite::impl::callbackAddUsers(const std::vector<std::string>& names,
- const uuid_vec_t& ids,
- void* user_data)
- {
- impl* self = (impl*)user_data;
- if (self)
- {
- self->addUsers(names, ids);
- }
- }
- //////////////////////////////////////////////////////////////////////
- // LLPanelGroupInvite
- //////////////////////////////////////////////////////////////////////
- LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id,
- LLFloater* parent)
- : LLPanel(group_id.asString()),
- mImplementation(new impl(group_id, parent)),
- mPendingUpdate(false),
- mStoreSelected()
- {
- }
- LLPanelGroupInvite::~LLPanelGroupInvite()
- {
- if (mImplementation)
- {
- delete mImplementation;
- mImplementation = NULL;
- }
- }
- bool LLPanelGroupInvite::postBuild()
- {
- if (!mImplementation) return false;
- mImplementation->mLoadingText = getString("loading");
- mImplementation->mRoleNames = getChild<LLComboBox>("role_name",
- true, false);
- mImplementation->mGroupName = getChild<LLTextBox>("group_name_text",
- true, false);
- LLNameListCtrl* list = getChild<LLNameListCtrl>("invitee_list",
- true, false);
- mImplementation->mInvitees = list;
- if (list)
- {
- list->setCallbackUserData(mImplementation);
- list->setCommitOnSelectionChange(true);
- list->setCommitCallback(impl::callbackSelect);
- }
- LLButton* button = getChild<LLButton>("add_button");
- // Default to opening avatarpicker automatically
- // (*impl::callbackClickAdd)((void*)this);
- button->setClickedCallback(impl::callbackClickAdd);
- button->setCallbackUserData(this);
- button = getChild<LLButton>("cancel_button");
- button->setClickedCallback(impl::callbackClickCancel);
- button->setCallbackUserData(mImplementation);
- button = getChild<LLButton>("remove_button", true, false);
- mImplementation->mRemoveButton = button;
- if (button)
- {
- button->setClickedCallback(impl::callbackClickRemove);
- button->setCallbackUserData(mImplementation);
- button->setEnabled(false);
- }
- button = getChild<LLButton>("invite_button", true, false);
- mImplementation->mOKButton = button;
- if (button)
- {
- button->setClickedCallback(impl::callbackClickOK);
- button->setCallbackUserData(mImplementation);
- button->setEnabled(false);
- }
- mImplementation->mOwnerWarning = getString("confirm_invite_owner_str");
- mImplementation->mTooManySelected =
- getString("invite_selection_too_large");
- update();
- return true;
- }
- void LLPanelGroupInvite::clear()
- {
- mStoreSelected.setNull();
- if (!mImplementation) return;
- if (mImplementation->mInvitees)
- {
- mImplementation->mInvitees->deleteAllItems();
- }
- if (mImplementation->mRoleNames)
- {
- mImplementation->mRoleNames->clear();
- mImplementation->mRoleNames->removeall();
- }
- if (mImplementation->mOKButton)
- {
- mImplementation->mOKButton->setEnabled(false);
- }
- }
- void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
- {
- std::vector<std::string> names;
- for (S32 i = 0, count = agent_ids.size(); i < count; ++i)
- {
- LLUUID agent_id = agent_ids[i];
- LLVOAvatar* avatarp = gObjectList.findAvatar(agent_id);
- if (avatarp)
- {
- std::string fullname;
- LLSD args;
- LLNameValue* nvfirst = avatarp->getNVPair("FirstName");
- LLNameValue* nvlast = avatarp->getNVPair("LastName");
- if (nvfirst && nvlast)
- {
- args["FIRST"] = std::string(nvfirst->getString());
- args["LAST"] = std::string(nvlast->getString());
- fullname = std::string(nvfirst->getString()) + " " +
- std::string(nvlast->getString());
- }
- if (!fullname.empty())
- {
- names.emplace_back(fullname);
- }
- else
- {
- llwarns << "Selected avatar has no name: " << avatarp->getID()
- << llendl;
- names.emplace_back("(Unknown)");
- }
- }
- }
- mImplementation->addUsers(names, agent_ids);
- }
- void LLPanelGroupInvite::draw()
- {
- if (mPendingUpdate)
- {
- updateLists();
- }
- LLPanel::draw();
- }
- void LLPanelGroupInvite::update()
- {
- mPendingUpdate = false;
- if (!mImplementation) return;
- 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()
- {
- if (!mImplementation) return;
- bool waiting = false;
- LLGroupMgrGroupData* gdatap =
- gGroupMgr.getGroupData(mImplementation->mGroupID);
- if (gdatap)
- {
- if (gdatap->isGroupPropertiesDataComplete())
- {
- if (mImplementation->mGroupName)
- {
- mImplementation->mGroupName->setText(gdatap->mName);
- }
- }
- else
- {
- waiting = true;
- }
- if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() &&
- (gdatap->isRoleMemberDataComplete() ||
- // MAINT-5270: large groups receives an empty members list
- // without some powers, so RoleMemberData would not be complete
- // for them.
- !gdatap->mMembers.size()))
- {
- 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
- gGroupMgr.sendGroupPropertiesRequest(mImplementation->mGroupID);
- gGroupMgr.sendGroupRoleDataRequest(mImplementation->mGroupID);
- gGroupMgr.sendGroupRoleMembersRequest(mImplementation->mGroupID);
- gGroupMgr.sendCapGroupMembersRequest(mImplementation->mGroupID);
- }
- else if (gdatap)
- {
- // Restart requests that were interrupted/dropped/failed to start
- if (!gdatap->isRoleDataPending() && !gdatap->isRoleDataComplete())
- {
- gGroupMgr.sendGroupRoleDataRequest(mImplementation->mGroupID);
- }
- if (!gdatap->isRoleMemberDataPending() &&
- !gdatap->isRoleMemberDataComplete())
- {
- gGroupMgr.sendGroupRoleMembersRequest(mImplementation->mGroupID);
- }
- // sendCapGroupMembersRequest() has a per frame send limitation
- // that could have interrupted previous request
- if (!gdatap->isMemberDataPending() && !gdatap->isMemberDataComplete())
- {
- gGroupMgr.sendCapGroupMembersRequest(mImplementation->mGroupID);
- }
- }
- mPendingUpdate = true;
- }
- else
- {
- mPendingUpdate = false;
- if (mImplementation->mOKButton &&
- mImplementation->mRoleNames->getItemCount())
- {
- mImplementation->mOKButton->setEnabled(true);
- }
- }
- }
- //////////////////////////////////////////////////////////////////////
- // LLFloaterGroupInvite
- //////////////////////////////////////////////////////////////////////
- // static
- void* LLFloaterGroupInvite::createPanel(void* userdata)
- {
- LLFloaterGroupInviteData* data = (LLFloaterGroupInviteData*)userdata;
- if (data)
- {
- data->mPanel = new LLPanelGroupInvite(data->mGroupId, data->mSelf);
- return data->mPanel;
- }
- else
- {
- return NULL;
- }
- }
- LLFloaterGroupInvite::LLFloaterGroupInvite(const LLUUID& group_id)
- : LLFloater(group_id.asString()),
- mGroupID(group_id),
- mInvitePanelp(NULL)
- {
- // Create the group bulk ban panel together with this floater
- LLFloaterGroupInviteData* data;
- data = new LLFloaterGroupInviteData(this, group_id);
- LLCallbackMap::map_t factory_map;
- factory_map["invite_panel"] = LLCallbackMap(createPanel, data);
- LLUICtrlFactory::getInstance()->buildFloater(this,
- "floater_group_invite.xml",
- &factory_map);
- mInvitePanelp = data->mPanel;
- delete data;
- }
- //virtual
- LLFloaterGroupInvite::~LLFloaterGroupInvite()
- {
- if (mGroupID.notNull())
- {
- sInstances.erase(mGroupID);
- }
- if (mInvitePanelp)
- {
- delete mInvitePanelp;
- mInvitePanelp = NULL;
- }
- }
- //static
- void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id,
- uuid_vec_t* agent_ids,
- LLView* parent)
- {
- if (group_id.isNull())
- {
- llwarns << "Null group_id passed ! Aborting." << llendl;
- return;
- }
- // If we do not have a floater for this group, create one.
- LLFloaterGroupInvite* fgi = get_ptr_in_map(sInstances, group_id);
- if (!fgi)
- {
- fgi = new LLFloaterGroupInvite(group_id);
- if (!fgi || !fgi->mInvitePanelp)
- {
- llwarns << "Could not create the floater ! Aborting." << llendl;
- return;
- }
- if (parent && gFloaterViewp && gFloaterViewp->getParentFloater(parent))
- {
- gFloaterViewp->getParentFloater(parent)->addDependentFloater(fgi);
- }
- sInstances[group_id] = fgi;
- fgi->mInvitePanelp->clear();
- }
- if (!fgi->mInvitePanelp) // Paranoia
- {
- llwarns << "NULL panel in floater ! Aborting." << llendl;
- return;
- }
- if (agent_ids)
- {
- fgi->mInvitePanelp->addUsers(*agent_ids);
- }
- fgi->open();
- fgi->mInvitePanelp->update();
- }
|