summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rwxr-xr-xindra/llcommon/roles_constants.h100
-rwxr-xr-xindra/llcommon/stdenums.h1
-rwxr-xr-xindra/newview/CMakeLists.txt7
-rw-r--r--indra/newview/llfloatergroupbulkban.cpp134
-rw-r--r--indra/newview/llfloatergroupbulkban.h48
-rwxr-xr-xindra/newview/llgroupmgr.cpp167
-rwxr-xr-xindra/newview/llgroupmgr.h75
-rwxr-xr-xindra/newview/llnamelistctrl.cpp35
-rwxr-xr-xindra/newview/llnamelistctrl.h13
-rw-r--r--indra/newview/llpanelgroupbulk.cpp412
-rw-r--r--indra/newview/llpanelgroupbulk.h74
-rw-r--r--indra/newview/llpanelgroupbulkban.cpp143
-rw-r--r--indra/newview/llpanelgroupbulkban.h47
-rw-r--r--indra/newview/llpanelgroupbulkimpl.h94
-rwxr-xr-xindra/newview/llpanelgroupinvite.cpp678
-rwxr-xr-xindra/newview/llpanelgroupinvite.h29
-rwxr-xr-xindra/newview/llpanelgrouproles.cpp533
-rwxr-xr-xindra/newview/llpanelgrouproles.h53
-rwxr-xr-xindra/newview/llviewerregion.cpp1
-rw-r--r--indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml78
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_group_invite.xml2
-rwxr-xr-xindra/newview/skins/default/xui/en/panel_group_roles.xml1175
-rwxr-xr-xindra/newview/skins/default/xui/en/role_actions.xml7
-rwxr-xr-xindra/newview/skins/default/xui/en/strings.xml1
24 files changed, 2578 insertions, 1329 deletions
diff --git a/indra/llcommon/roles_constants.h b/indra/llcommon/roles_constants.h
index effd15ea72..598cd48e22 100755
--- a/indra/llcommon/roles_constants.h
+++ b/indra/llcommon/roles_constants.h
@@ -53,7 +53,7 @@ enum LLRoleChangeType
// KNOWN HOLES: use these for any single bit powers you need
// bit 0x1 << 46
-// bit 0x1 << 49 and above
+// bit 0x1 << 52 and above
// These powers were removed to make group roles simpler
// bit 0x1 << 41 (GP_ACCOUNTING_VIEW)
@@ -63,88 +63,90 @@ const U64 GP_NO_POWERS = 0x0;
const U64 GP_ALL_POWERS = 0xFFFFFFFFFFFFFFFFLL;
// Membership
-const U64 GP_MEMBER_INVITE = 0x1 << 1; // Invite member
-const U64 GP_MEMBER_EJECT = 0x1 << 2; // Eject member from group
-const U64 GP_MEMBER_OPTIONS = 0x1 << 3; // Toggle "Open enrollment" and change "Signup Fee"
-const U64 GP_MEMBER_VISIBLE_IN_DIR = 0x1LL << 47;
+const U64 GP_MEMBER_INVITE = 0x1LL << 1; // Invite member
+const U64 GP_MEMBER_EJECT = 0x1LL << 2; // Eject member from group
+const U64 GP_MEMBER_OPTIONS = 0x1LL << 3; // Toggle "Open enrollment" and change "Signup Fee"
+const U64 GP_MEMBER_VISIBLE_IN_DIR = 0x1LL << 47;
// Roles
-const U64 GP_ROLE_CREATE = 0x1 << 4; // Create new roles
-const U64 GP_ROLE_DELETE = 0x1 << 5; // Delete roles
-const U64 GP_ROLE_PROPERTIES = 0x1 << 6; // Change Role Names, Titles, and Descriptions (Of roles the user is in, only, or any role in group?)
-const U64 GP_ROLE_ASSIGN_MEMBER_LIMITED = 0x1 << 7; // Assign Member to a Role that the assigner is in
-const U64 GP_ROLE_ASSIGN_MEMBER = 0x1 << 8; // Assign Member to Role
-const U64 GP_ROLE_REMOVE_MEMBER = 0x1 << 9; // Remove Member from Role
-const U64 GP_ROLE_CHANGE_ACTIONS = 0x1 << 10; // Change actions a role can perform
+const U64 GP_ROLE_CREATE = 0x1LL << 4; // Create new roles
+const U64 GP_ROLE_DELETE = 0x1LL << 5; // Delete roles
+const U64 GP_ROLE_PROPERTIES = 0x1LL << 6; // Change Role Names, Titles, and Descriptions (Of roles the user is in, only, or any role in group?)
+const U64 GP_ROLE_ASSIGN_MEMBER_LIMITED = 0x1LL << 7; // Assign Member to a Role that the assigner is in
+const U64 GP_ROLE_ASSIGN_MEMBER = 0x1LL << 8; // Assign Member to Role
+const U64 GP_ROLE_REMOVE_MEMBER = 0x1LL << 9; // Remove Member from Role
+const U64 GP_ROLE_CHANGE_ACTIONS = 0x1LL << 10; // Change actions a role can perform
// Group Identity
-const U64 GP_GROUP_CHANGE_IDENTITY = 0x1 << 11; // Charter, insignia, 'Show In Group List', 'Publish on the web', 'Mature', all 'Show Member In Group Profile' checkboxes
+const U64 GP_GROUP_CHANGE_IDENTITY = 0x1LL << 11; // Charter, insignia, 'Show In Group List', 'Publish on the web', 'Mature', all 'Show Member In Group Profile' checkboxes
// Parcel Management
-const U64 GP_LAND_DEED = 0x1 << 12; // Deed Land and Buy Land for Group
-const U64 GP_LAND_RELEASE = 0x1 << 13; // Release Land (to Gov. Linden)
-const U64 GP_LAND_SET_SALE_INFO = 0x1 << 14; // Set for sale info (Toggle "For Sale", Set Price, Set Target, Toggle "Sell objects with the land")
-const U64 GP_LAND_DIVIDE_JOIN = 0x1 << 15; // Divide and Join Parcels
+const U64 GP_LAND_DEED = 0x1LL << 12; // Deed Land and Buy Land for Group
+const U64 GP_LAND_RELEASE = 0x1LL << 13; // Release Land (to Gov. Linden)
+const U64 GP_LAND_SET_SALE_INFO = 0x1LL << 14; // Set for sale info (Toggle "For Sale", Set Price, Set Target, Toggle "Sell objects with the land")
+const U64 GP_LAND_DIVIDE_JOIN = 0x1LL << 15; // Divide and Join Parcels
// Parcel Identity
-const U64 GP_LAND_FIND_PLACES = 0x1 << 17; // Toggle "Show in Find Places" and Set Category.
-const U64 GP_LAND_CHANGE_IDENTITY = 0x1 << 18; // Change Parcel Identity: Parcel Name, Parcel Description, Snapshot, 'Publish on the web', and 'Mature' checkbox
-const U64 GP_LAND_SET_LANDING_POINT = 0x1 << 19; // Set Landing Point
+const U64 GP_LAND_FIND_PLACES = 0x1LL << 17; // Toggle "Show in Find Places" and Set Category.
+const U64 GP_LAND_CHANGE_IDENTITY = 0x1LL << 18; // Change Parcel Identity: Parcel Name, Parcel Description, Snapshot, 'Publish on the web', and 'Mature' checkbox
+const U64 GP_LAND_SET_LANDING_POINT = 0x1LL << 19; // Set Landing Point
// Parcel Settings
-const U64 GP_LAND_CHANGE_MEDIA = 0x1 << 20; // Change Media Settings
-const U64 GP_LAND_EDIT = 0x1 << 21; // Toggle Edit Land
-const U64 GP_LAND_OPTIONS = 0x1 << 22; // Toggle Set Home Point, Fly, Outside Scripts, Create/Edit Objects, Landmark, and Damage checkboxes
+const U64 GP_LAND_CHANGE_MEDIA = 0x1LL << 20; // Change Media Settings
+const U64 GP_LAND_EDIT = 0x1LL << 21; // Toggle Edit Land
+const U64 GP_LAND_OPTIONS = 0x1LL << 22; // Toggle Set Home Point, Fly, Outside Scripts, Create/Edit Objects, Landmark, and Damage checkboxes
// Parcel Powers
-const U64 GP_LAND_ALLOW_EDIT_LAND = 0x1 << 23; // Bypass Edit Land Restriction
-const U64 GP_LAND_ALLOW_FLY = 0x1 << 24; // Bypass Fly Restriction
-const U64 GP_LAND_ALLOW_CREATE = 0x1 << 25; // Bypass Create/Edit Objects Restriction
-const U64 GP_LAND_ALLOW_LANDMARK = 0x1 << 26; // Bypass Landmark Restriction
-const U64 GP_LAND_ALLOW_SET_HOME = 0x1 << 28; // Bypass Set Home Point Restriction
-const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land
-
+const U64 GP_LAND_ALLOW_EDIT_LAND = 0x1LL << 23; // Bypass Edit Land Restriction
+const U64 GP_LAND_ALLOW_FLY = 0x1LL << 24; // Bypass Fly Restriction
+const U64 GP_LAND_ALLOW_CREATE = 0x1LL << 25; // Bypass Create/Edit Objects Restriction
+const U64 GP_LAND_ALLOW_LANDMARK = 0x1LL << 26; // Bypass Landmark Restriction
+const U64 GP_LAND_ALLOW_SET_HOME = 0x1LL << 28; // Bypass Set Home Point Restriction
+const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land
// Parcel Access
-const U64 GP_LAND_MANAGE_ALLOWED = 0x1 << 29; // Manage Allowed List
-const U64 GP_LAND_MANAGE_BANNED = 0x1 << 30; // Manage Banned List
-const U64 GP_LAND_MANAGE_PASSES = 0x1LL << 31; // Change Sell Pass Settings
-const U64 GP_LAND_ADMIN = 0x1LL << 32; // Eject and Freeze Users on the land
+const U64 GP_LAND_MANAGE_ALLOWED = 0x1LL << 29; // Manage Allowed List
+const U64 GP_LAND_MANAGE_BANNED = 0x1LL << 30; // Manage Banned List
+const U64 GP_LAND_MANAGE_PASSES = 0x1LL << 31; // Change Sell Pass Settings
+const U64 GP_LAND_ADMIN = 0x1LL << 32; // Eject and Freeze Users on the land
// Parcel Content
-const U64 GP_LAND_RETURN_GROUP_SET = 0x1LL << 33; // Return objects on parcel that are set to group
-const U64 GP_LAND_RETURN_NON_GROUP = 0x1LL << 34; // Return objects on parcel that are not set to group
-const U64 GP_LAND_RETURN_GROUP_OWNED= 0x1LL << 48; // Return objects on parcel that are owned by the group
+const U64 GP_LAND_RETURN_GROUP_SET = 0x1LL << 33; // Return objects on parcel that are set to group
+const U64 GP_LAND_RETURN_NON_GROUP = 0x1LL << 34; // Return objects on parcel that are not set to group
+const U64 GP_LAND_RETURN_GROUP_OWNED = 0x1LL << 48; // Return objects on parcel that are owned by the group
// Select a power-bit based on an object's relationship to a parcel.
const U64 GP_LAND_RETURN = GP_LAND_RETURN_GROUP_OWNED
| GP_LAND_RETURN_GROUP_SET
| GP_LAND_RETURN_NON_GROUP;
-const U64 GP_LAND_GARDENING = 0x1LL << 35; // Parcel Gardening - plant and move linden trees
+const U64 GP_LAND_GARDENING = 0x1LL << 35; // Parcel Gardening - plant and move linden trees
// Object Management
-const U64 GP_OBJECT_DEED = 0x1LL << 36; // Deed Object
-const U64 GP_OBJECT_MANIPULATE = 0x1LL << 38; // Manipulate Group Owned Objects (Move, Copy, Mod)
-const U64 GP_OBJECT_SET_SALE = 0x1LL << 39; // Set Group Owned Object for Sale
+const U64 GP_OBJECT_DEED = 0x1LL << 36; // Deed Object
+const U64 GP_OBJECT_MANIPULATE = 0x1LL << 38; // Manipulate Group Owned Objects (Move, Copy, Mod)
+const U64 GP_OBJECT_SET_SALE = 0x1LL << 39; // Set Group Owned Object for Sale
// Accounting
-const U64 GP_ACCOUNTING_ACCOUNTABLE = 0x1LL << 40; // Pay Group Liabilities and Receive Group Dividends
+const U64 GP_ACCOUNTING_ACCOUNTABLE = 0x1LL << 40; // Pay Group Liabilities and Receive Group Dividends
// Notices
-const U64 GP_NOTICES_SEND = 0x1LL << 42; // Send Notices
-const U64 GP_NOTICES_RECEIVE = 0x1LL << 43; // Receive Notices and View Notice History
+const U64 GP_NOTICES_SEND = 0x1LL << 42; // Send Notices
+const U64 GP_NOTICES_RECEIVE = 0x1LL << 43; // Receive Notices and View Notice History
// Proposals
// TODO: _DEPRECATED suffix as part of vote removal - DEV-24856:
-const U64 GP_PROPOSAL_START = 0x1LL << 44; // Start Proposal
+const U64 GP_PROPOSAL_START = 0x1LL << 44; // Start Proposal
// TODO: _DEPRECATED suffix as part of vote removal - DEV-24856:
-const U64 GP_PROPOSAL_VOTE = 0x1LL << 45; // Vote on Proposal
+const U64 GP_PROPOSAL_VOTE = 0x1LL << 45; // Vote on Proposal
// Group chat moderation related
-const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session
-const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk
-const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session
+const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session
+const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk
+const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session
+
+// Group Banning
+const U64 GP_GROUP_BAN_ACCESS = 0x1LL << 51; // Allows access to ban / un-ban agents from a group.
const U64 GP_DEFAULT_MEMBER = GP_ACCOUNTING_ACCOUNTABLE
| GP_LAND_ALLOW_SET_HOME
diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h
index efcbe76795..b505ef0b4b 100755
--- a/indra/llcommon/stdenums.h
+++ b/indra/llcommon/stdenums.h
@@ -127,6 +127,7 @@ enum LLGroupChange
GC_ROLE_DATA,
GC_ROLE_MEMBER_DATA,
GC_TITLES,
+ GC_BANLIST,
GC_ALL
};
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c5e1cde4e6..9c284beec8 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -232,6 +232,7 @@ set(viewer_SOURCE_FILES
llfloatergesture.cpp
llfloatergodtools.cpp
llfloatergotoline.cpp
+ llfloatergroupbulkban.cpp
llfloatergroupinvite.cpp
llfloatergroups.cpp
llfloaterhandler.cpp
@@ -402,6 +403,8 @@ set(viewer_SOURCE_FILES
llpanelface.cpp
llpanelgenerictip.cpp
llpanelgroup.cpp
+ llpanelgroupbulk.cpp
+ llpanelgroupbulkban.cpp
llpanelgroupgeneral.cpp
llpanelgroupinvite.cpp
llpanelgrouplandmoney.cpp
@@ -820,6 +823,7 @@ set(viewer_HEADER_FILES
llfloatergesture.h
llfloatergodtools.h
llfloatergotoline.h
+ llfloatergroupbulkban.h
llfloatergroupinvite.h
llfloatergroups.h
llfloaterhandler.h
@@ -983,6 +987,9 @@ set(viewer_HEADER_FILES
llpanelface.h
llpanelgenerictip.h
llpanelgroup.h
+ llpanelgroupbulk.h
+ llpanelgroupbulkimpl.h
+ llpanelgroupbulkban.h
llpanelgroupgeneral.h
llpanelgroupinvite.h
llpanelgrouplandmoney.h
diff --git a/indra/newview/llfloatergroupbulkban.cpp b/indra/newview/llfloatergroupbulkban.cpp
new file mode 100644
index 0000000000..54a2283b13
--- /dev/null
+++ b/indra/newview/llfloatergroupbulkban.cpp
@@ -0,0 +1,134 @@
+/**
+* @file llfloatergroupbulkban.cpp
+* @brief Floater to ban Residents from a group.
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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 "llfloatergroupbulkban.h"
+#include "llpanelgroupbulkban.h"
+#include "lltrans.h"
+#include "lldraghandle.h"
+
+
+class LLFloaterGroupBulkBan::impl
+{
+public:
+ impl(const LLUUID& group_id) : mGroupID(group_id), mBulkBanPanelp(NULL) {}
+ ~impl() {}
+
+ static void closeFloater(void* data);
+
+public:
+ LLUUID mGroupID;
+ LLPanelGroupBulkBan* mBulkBanPanelp;
+
+ static std::map<LLUUID, LLFloaterGroupBulkBan*> sInstances;
+};
+
+//
+// Globals
+//
+std::map<LLUUID, LLFloaterGroupBulkBan*> LLFloaterGroupBulkBan::impl::sInstances;
+
+void LLFloaterGroupBulkBan::impl::closeFloater(void* data)
+{
+ LLFloaterGroupBulkBan* floaterp = (LLFloaterGroupBulkBan*)data;
+ if(floaterp)
+ floaterp->closeFloater();
+}
+
+//-----------------------------------------------------------------------------
+// Implementation
+//-----------------------------------------------------------------------------
+LLFloaterGroupBulkBan::LLFloaterGroupBulkBan(const LLUUID& group_id/*=LLUUID::null*/)
+ : LLFloater(group_id)
+{
+ S32 floater_header_size = getHeaderHeight();
+ LLRect contents;
+
+ mImpl = new impl(group_id);
+ mImpl->mBulkBanPanelp = new LLPanelGroupBulkBan(group_id);
+
+ contents = mImpl->mBulkBanPanelp->getRect();
+ contents.mTop -= floater_header_size;
+
+ setTitle(mImpl->mBulkBanPanelp->getString("GroupBulkBan"));
+ mImpl->mBulkBanPanelp->setCloseCallback(impl::closeFloater, this);
+ mImpl->mBulkBanPanelp->setRect(contents);
+
+ addChild(mImpl->mBulkBanPanelp);
+}
+
+LLFloaterGroupBulkBan::~LLFloaterGroupBulkBan()
+{
+ if(mImpl->mGroupID.notNull())
+ {
+ impl::sInstances.erase(mImpl->mGroupID);
+ }
+
+ delete mImpl->mBulkBanPanelp;
+ delete mImpl;
+}
+
+void LLFloaterGroupBulkBan::showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids)
+{
+ const LLFloater::Params& floater_params = LLFloater::getDefaultParams();
+ S32 floater_header_size = floater_params.header_height;
+ LLRect contents;
+
+ // Make sure group_id isn't null
+ if (group_id.isNull())
+ {
+ llwarns << "LLFloaterGroupInvite::showForGroup with null group_id!" << llendl;
+ return;
+ }
+
+ // If we don't have a floater for this group, create one.
+ LLFloaterGroupBulkBan* fgb = get_if_there(impl::sInstances,
+ group_id,
+ (LLFloaterGroupBulkBan*)NULL);
+ if (!fgb)
+ {
+ fgb = new LLFloaterGroupBulkBan(group_id);
+ contents = fgb->mImpl->mBulkBanPanelp->getRect();
+ contents.mTop += floater_header_size;
+ fgb->setRect(contents);
+ fgb->getDragHandle()->setRect(contents);
+ fgb->getDragHandle()->setTitle(fgb->mImpl->mBulkBanPanelp->getString("GroupBulkBan"));
+
+ impl::sInstances[group_id] = fgb;
+
+ fgb->mImpl->mBulkBanPanelp->clear();
+ }
+
+ if (agent_ids != NULL)
+ {
+ fgb->mImpl->mBulkBanPanelp->addUsers(*agent_ids);
+ }
+
+ fgb->center();
+ fgb->openFloater();
+ fgb->mImpl->mBulkBanPanelp->update();
+}
diff --git a/indra/newview/llfloatergroupbulkban.h b/indra/newview/llfloatergroupbulkban.h
new file mode 100644
index 0000000000..5b680a1ba4
--- /dev/null
+++ b/indra/newview/llfloatergroupbulkban.h
@@ -0,0 +1,48 @@
+/**
+* @file llfloatergroupbulkban.h
+* @brief This floater is a wrapper for LLPanelGroupBulkBan, which
+* is used to ban Residents from a specific group.
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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$
+*/
+
+#ifndef LL_LLFLOATERGROUPBULKBAN_H
+#define LL_LLFLOATERGROUPBULKBAN_H
+
+#include "llfloater.h"
+#include "lluuid.h"
+
+class LLFloaterGroupBulkBan : public LLFloater
+{
+public:
+ virtual ~LLFloaterGroupBulkBan();
+
+ static void showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids = NULL);
+
+protected:
+ LLFloaterGroupBulkBan(const LLUUID& group_id = LLUUID::null);
+
+ class impl;
+ impl* mImpl;
+};
+
+#endif // LL_LLFLOATERGROUPBULKBAN_H
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index cbd844cdac..1e5c43dcdf 100755
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -231,11 +231,11 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) :
mMemberCount(0),
mRoleCount(0),
mReceivedRoleMemberPairs(0),
- mMemberDataComplete(FALSE),
- mRoleDataComplete(FALSE),
- mRoleMemberDataComplete(FALSE),
- mGroupPropertiesDataComplete(FALSE),
- mPendingRoleMemberRequest(FALSE),
+ mMemberDataComplete(false),
+ mRoleDataComplete(false),
+ mRoleMemberDataComplete(false),
+ mGroupPropertiesDataComplete(false),
+ mPendingRoleMemberRequest(false),
mAccessTime(0.0f)
{
mMemberVersion.generate();
@@ -424,7 +424,7 @@ void LLGroupMgrGroupData::removeMemberData()
delete mi->second;
}
mMembers.clear();
- mMemberDataComplete = FALSE;
+ mMemberDataComplete = false;
mMemberVersion.generate();
}
@@ -446,8 +446,8 @@ void LLGroupMgrGroupData::removeRoleData()
}
mRoles.clear();
mReceivedRoleMemberPairs = 0;
- mRoleDataComplete = FALSE;
- mRoleMemberDataComplete = FALSE;
+ mRoleDataComplete = false;
+ mRoleMemberDataComplete= false;
}
void LLGroupMgrGroupData::removeRoleMemberData()
@@ -471,7 +471,7 @@ void LLGroupMgrGroupData::removeRoleMemberData()
}
mReceivedRoleMemberPairs = 0;
- mRoleMemberDataComplete = FALSE;
+ mRoleMemberDataComplete= false;
}
LLGroupMgrGroupData::~LLGroupMgrGroupData()
@@ -742,6 +742,20 @@ void LLGroupMgrGroupData::cancelRoleChanges()
// Clear out all changes!
mRoleChanges.clear();
}
+
+void LLGroupMgrGroupData::createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data)
+{
+ mBanList[ban_id] = ban_data;
+}
+
+void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)
+{
+ mBanList.erase(ban_id);
+}
+
+
+
+
//
// LLGroupMgr
//
@@ -951,12 +965,12 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
if (group_datap->mMembers.size() == (U32)group_datap->mMemberCount)
{
- group_datap->mMemberDataComplete = TRUE;
+ group_datap->mMemberDataComplete = true;
group_datap->mMemberRequestID.setNull();
// We don't want to make role-member data requests until we have all the members
if (group_datap->mPendingRoleMemberRequest)
{
- group_datap->mPendingRoleMemberRequest = FALSE;
+ group_datap->mPendingRoleMemberRequest = false;
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID);
}
}
@@ -1026,7 +1040,7 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data)
group_datap->mMemberCount = num_group_members;
group_datap->mRoleCount = num_group_roles + 1; // Add the everyone role.
- group_datap->mGroupPropertiesDataComplete = TRUE;
+ group_datap->mGroupPropertiesDataComplete = true;
group_datap->mChanged = TRUE;
LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES);
@@ -1103,12 +1117,12 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data)
if (group_datap->mRoles.size() == (U32)group_datap->mRoleCount)
{
- group_datap->mRoleDataComplete = TRUE;
+ group_datap->mRoleDataComplete = true;
group_datap->mRoleDataRequestID.setNull();
// We don't want to make role-member data requests until we have all the role data
if (group_datap->mPendingRoleMemberRequest)
{
- group_datap->mPendingRoleMemberRequest = FALSE;
+ group_datap->mPendingRoleMemberRequest = false;
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID);
}
}
@@ -1217,7 +1231,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
}
}
- group_datap->mRoleMemberDataComplete = TRUE;
+ group_datap->mRoleMemberDataComplete= true;
group_datap->mRoleMembersRequestID.setNull();
}
@@ -1543,7 +1557,7 @@ void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id)
llinfos << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N")
<< " MemberDataComplete: " << (group_datap->mMemberDataComplete ? "Y" : "N")
<< " RoleDataComplete: " << (group_datap->mRoleDataComplete ? "Y" : "N") << llendl;
- group_datap->mPendingRoleMemberRequest = TRUE;
+ group_datap->mPendingRoleMemberRequest = true;
return;
}
@@ -1841,6 +1855,121 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
// Responder class for capability group management
+class GroupBanDataResponder : public LLHTTPClient::Responder
+{
+public:
+ GroupBanDataResponder() {}
+ virtual ~GroupBanDataResponder() {}
+ virtual void result(const LLSD& pContent);
+ virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent);
+};
+
+void GroupBanDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent)
+{
+ LL_WARNS("GrpMgr") << "Error receiving group member data [status:"
+ << pStatus << "]: " << pContent << LL_ENDL;
+}
+
+void GroupBanDataResponder::result(const LLSD& content)
+{
+ LLGroupMgr::processGroupBanRequest(content);
+}
+
+void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type,
+ const LLUUID& group_id,
+ EBanRequestAction ban_action, /* = BAN_NO_ACTION */
+ const std::vector<LLUUID> ban_list) /* = std::vector<LLUUID>() */
+{
+ LLViewerRegion* currentRegion = gAgent.getRegion();
+ if(!currentRegion)
+ {
+ LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL;
+ return;
+ }
+
+ // Check to make sure we have our capabilities
+ if(!currentRegion->capabilitiesReceived())
+ {
+ LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL;
+ return;
+ }
+
+ // Get our capability
+ std::string cap_url = currentRegion->getCapability("GroupBan");
+ if(cap_url.empty())
+ {
+ return;
+ }
+ cap_url += "?group_id=" + group_id.asString();
+
+ LLSD body = LLSD::emptyMap();
+ body["ban_action"] = ban_action;
+ // Add our list of potential banned agents to the list
+ body["ban_ids"] = LLSD::emptyArray();
+ LLSD ban_entry;
+
+ uuid_vec_t::const_iterator iter = ban_list.begin();
+ for(;iter != ban_list.end(); ++iter)
+ {
+ ban_entry = (*iter);
+ body["ban_ids"].append(ban_entry);
+ }
+
+ LLHTTPClient::ResponderPtr grp_ban_responder = new GroupBanDataResponder();
+ switch(request_type)
+ {
+ case REQUEST_GET:
+ LLHTTPClient::get(cap_url, grp_ban_responder);
+ break;
+ case REQUEST_POST:
+ LLHTTPClient::post(cap_url, body, grp_ban_responder);
+ break;
+ case REQUEST_PUT:
+ case REQUEST_DEL:
+ break;
+ }
+}
+
+
+void LLGroupMgr::processGroupBanRequest(const LLSD& content)
+{
+ // Did we get anything in content?
+ if(!content.size())
+ {
+ LL_WARNS("GrpMgr") << "No group member data received." << LL_ENDL;
+ return;
+ }
+
+ LLUUID group_id = content["group_id"].asUUID();
+
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ if (!gdatap)
+ return;
+
+ LLSD::map_const_iterator i = content["ban_list"].beginMap();
+ LLSD::map_const_iterator iEnd = content["ban_list"].endMap();
+ for(;i != iEnd; ++i)
+ {
+ const LLUUID ban_id(i->first);
+ LLSD ban_entry(i->second);
+
+ LLGroupBanData ban_data;
+ if(ban_entry.has("ban_date"))
+ {
+ ban_data.mBanDate = ban_entry["ban_date"].asDate();
+ // TODO: Ban Reason
+ }
+
+ gdatap->createBanEntry(ban_id, ban_data);
+ }
+
+ gdatap->mChanged = TRUE;
+ LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST);
+}
+
+
+
+// Responder class for capability group management
class GroupMemberDataResponder : public LLHTTPClient::Responder
{
public:
@@ -1925,7 +2054,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
if(num_members < 1)
return;
- LLUUID group_id = content["group_id"].asUUID();
+ LLUUID group_id = content["group_id"].asUUID();
LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
if(!group_datap)
@@ -2008,12 +2137,12 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id);
- group_datap->mMemberDataComplete = TRUE;
+ group_datap->mMemberDataComplete = true;
group_datap->mMemberRequestID.setNull();
// Make the role-member data request
if (group_datap->mPendingRoleMemberRequest)
{
- group_datap->mPendingRoleMemberRequest = FALSE;
+ group_datap->mPendingRoleMemberRequest = false;
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id);
}
diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h
index d8c1ab7ef5..3cbeda18dc 100755
--- a/indra/newview/llgroupmgr.h
+++ b/indra/newview/llgroupmgr.h
@@ -33,7 +33,11 @@
#include <string>
#include <map>
+// Forward Declarations
class LLMessageSystem;
+class LLGroupRoleData;
+class LLGroupMgr;
+
class LLGroupMgrObserver
{
@@ -54,8 +58,6 @@ public:
virtual void changed(const LLUUID& group_id, LLGroupChange gc) = 0;
};
-class LLGroupRoleData;
-
class LLGroupMemberData
{
friend class LLGroupMgrGroupData;
@@ -190,6 +192,17 @@ struct lluuid_pair_less
}
};
+
+struct LLGroupBanData
+{
+ LLGroupBanData(): mBanDate() {}
+ ~LLGroupBanData() {}
+
+ LLDate mBanDate;
+ // TODO: std:string ban_reason;
+};
+
+
struct LLGroupTitle
{
std::string mTitle;
@@ -197,8 +210,6 @@ struct LLGroupTitle
BOOL mSelected;
};
-class LLGroupMgr;
-
class LLGroupMgrGroupData
{
friend class LLGroupMgr;
@@ -228,27 +239,36 @@ public:
void recalcAllAgentPowers();
void recalcAgentPowers(const LLUUID& agent_id);
- BOOL isMemberDataComplete() { return mMemberDataComplete; }
- BOOL isRoleDataComplete() { return mRoleDataComplete; }
- BOOL isRoleMemberDataComplete() { return mRoleMemberDataComplete; }
- BOOL isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; }
+ bool isMemberDataComplete() { return mMemberDataComplete; }
+ bool isRoleDataComplete() { return mRoleDataComplete; }
+ bool isRoleMemberDataComplete() { return mRoleMemberDataComplete; }
+ bool isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; }
F32 getAccessTime() const { return mAccessTime; }
void setAccessed();
const LLUUID& getMemberVersion() const { return mMemberVersion; }
+ void clearBanList() { mBanList.clear(); }
+ void getBanList(const LLUUID& group_id, LLGroupBanData& ban_data);
+ const LLGroupBanData& getBanEntry(const LLUUID& ban_id) { return mBanList[ban_id]; }
+
+ void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData());
+ void removeBanEntry(const LLUUID& ban_id);
+
+
public:
typedef std::map<LLUUID,LLGroupMemberData*> member_list_t;
typedef std::map<LLUUID,LLGroupRoleData*> role_list_t;
typedef std::map<lluuid_pair,LLRoleMemberChange,lluuid_pair_less> change_map_t;
typedef std::map<LLUUID,LLRoleData> role_data_map_t;
+ typedef std::map<LLUUID,LLGroupBanData> ban_list_t;
+
member_list_t mMembers;
role_list_t mRoles;
-
-
change_map_t mRoleMemberChanges;
role_data_map_t mRoleChanges;
+ ban_list_t mBanList;
std::vector<LLGroupTitle> mTitles;
@@ -279,12 +299,12 @@ private:
LLUUID mTitlesRequestID;
U32 mReceivedRoleMemberPairs;
- BOOL mMemberDataComplete;
- BOOL mRoleDataComplete;
- BOOL mRoleMemberDataComplete;
- BOOL mGroupPropertiesDataComplete;
+ bool mMemberDataComplete;
+ bool mRoleDataComplete;
+ bool mRoleMemberDataComplete;
+ bool mGroupPropertiesDataComplete;
- BOOL mPendingRoleMemberRequest;
+ bool mPendingRoleMemberRequest;
F32 mAccessTime;
// Generate a new ID every time mMembers
@@ -312,6 +332,22 @@ class LLGroupMgr : public LLSingleton<LLGroupMgr>
LOG_CLASS(LLGroupMgr);
public:
+ enum EBanRequestType
+ {
+ REQUEST_GET = 0,
+ REQUEST_POST,
+ REQUEST_PUT,
+ REQUEST_DEL
+ };
+
+ enum EBanRequestAction
+ {
+ BAN_NO_ACTION = 0,
+ BAN_CREATE = 1,
+ BAN_DELETE = 2
+ };
+
+public:
LLGroupMgr();
~LLGroupMgr();
@@ -344,8 +380,14 @@ public:
static void sendGroupMemberInvites(const LLUUID& group_id, std::map<LLUUID,LLUUID>& role_member_pairs);
static void sendGroupMemberEjects(const LLUUID& group_id,
uuid_vec_t& member_ids);
+
+ static void sendGroupBanRequest(EBanRequestType request_type,
+ const LLUUID& group_id,
+ EBanRequestAction ban_action = BAN_NO_ACTION,
+ const uuid_vec_t ban_list = uuid_vec_t());
+
+ static void processGroupBanRequest(const LLSD& content);
- // BAKER
void sendCapGroupMembersRequest(const LLUUID& group_id);
static void processCapGroupMembersRequest(const LLSD& content);
@@ -390,4 +432,3 @@ private:
#endif
-
diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp
index 7ddd04fed0..385d3e8ad2 100755
--- a/indra/newview/llnamelistctrl.cpp
+++ b/indra/newview/llnamelistctrl.cpp
@@ -65,15 +65,14 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p)
mNameColumn(p.name_column.column_name),
mAllowCallingCardDrop(p.allow_calling_card_drop),
mShortNames(p.short_names),
- mAvatarNameCacheConnection()
+ mAvatarNameCacheConnection(),
+ mPendingLookupsRemaining(0)
{}
// public
LLScrollListItem* LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos,
BOOL enabled, const std::string& suffix)
{
- //llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl;
-
NameItem item;
item.value = agent_id;
item.enabled = enabled;
@@ -335,6 +334,17 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
mAvatarNameCacheConnection.disconnect();
}
mAvatarNameCacheConnection = LLAvatarNameCache::get(id,boost::bind(&LLNameListCtrl::onAvatarNameCache,this, _1, _2, item->getHandle()));
+
+ if(mPendingLookupsRemaining <= 0)
+ {
+ // BAKER TODO:
+ // We might get into a state where mPendingLookupsRemaining might
+ // go negative. So just reset it right now and figure out if it's
+ // possible later :)
+ mPendingLookupsRemaining = 0;
+ mNameListCompleteSignal(false);
+ }
+ mPendingLookupsRemaining++;
}
break;
}
@@ -386,6 +396,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id)
{
selectNthItem(idx); // not sure whether this is needed, taken from previous implementation
deleteSingleItem(idx);
+
+ mPendingLookupsRemaining--;
}
}
@@ -412,6 +424,23 @@ void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id,
}
}
+ //////////////////////////////////////////////////////////////////////////
+ // BAKER - FIX NameListCtrl
+ //if (mPendingLookupsRemaining <= 0)
+ {
+ // We might get into a state where mPendingLookupsRemaining might
+ // go negative. So just reset it right now and figure out if it's
+ // possible later :)
+ //mPendingLookupsRemaining = 0;
+
+ mNameListCompleteSignal(true);
+ }
+ //else
+ {
+ // mPendingLookupsRemaining--;
+ }
+ //////////////////////////////////////////////////////////////////////////
+
dirtyColumns();
}
diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h
index 92e82b672d..a3e17eb6df 100755
--- a/indra/newview/llnamelistctrl.h
+++ b/indra/newview/llnamelistctrl.h
@@ -67,6 +67,7 @@ class LLNameListCtrl
: public LLScrollListCtrl, public LLInstanceTracker<LLNameListCtrl>
{
public:
+ typedef boost::signals2::signal<void(bool)> namelist_complete_signal_t;
typedef enum e_name_type
{
@@ -152,7 +153,7 @@ public:
/*virtual*/ void updateColumns(bool force_update);
- /*virtual*/ void mouseOverHighlightNthItem( S32 index );
+ /*virtual*/ void mouseOverHighlightNthItem( S32 index );
private:
void showInspector(const LLUUID& avatar_id, bool is_group);
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, LLHandle<LLNameListItem> item);
@@ -163,6 +164,16 @@ private:
BOOL mAllowCallingCardDrop;
bool mShortNames; // display name only, no SLID
boost::signals2::connection mAvatarNameCacheConnection;
+
+ S32 mPendingLookupsRemaining;
+ namelist_complete_signal_t mNameListCompleteSignal;
+
+public:
+ boost::signals2::connection setOnNameListCompleteCallback(boost::function<void(bool)> onNameListCompleteCallback)
+ {
+ return mNameListCompleteSignal.connect(onNameListCompleteCallback);
+ }
+
};
diff --git a/indra/newview/llpanelgroupbulk.cpp b/indra/newview/llpanelgroupbulk.cpp
new file mode 100644
index 0000000000..86ac1867df
--- /dev/null
+++ b/indra/newview/llpanelgroupbulk.cpp
@@ -0,0 +1,412 @@
+/**
+* @file llpanelgroupbulk.cpp
+* @brief Implementation of llpanelgroupbulk
+* @author Baker@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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 "llpanelgroupbulk.h"
+#include "llpanelgroupbulkimpl.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"
+
+
+//////////////////////////////////////////////////////////////////////////
+// Implementation of llpanelgroupbulkimpl.h functions
+//////////////////////////////////////////////////////////////////////////
+LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) :
+ mGroupID(group_id),
+ mBulkAgentList(NULL),
+ mOKButton(NULL),
+ mRemoveButton(NULL),
+ mGroupName(NULL),
+ mLoadingText(),
+ mTooManySelected(),
+ mCloseCallback(NULL),
+ mCloseCallbackUserData(NULL),
+ mAvatarNameCacheConnection(),
+ mRoleNames(NULL),
+ mOwnerWarning(),
+ mAlreadyInGroup(),
+ mConfirmedOwnerInvite(false)
+{}
+
+LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl()
+{
+ if(mAvatarNameCacheConnection.connected())
+ {
+ mAvatarNameCacheConnection.disconnect();
+ }
+}
+
+void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata)
+{
+ LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)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(callbackAddUsers, _1, panelp->mImplementation), TRUE, FALSE, FALSE, root_floater->getName(), button);
+ if(picker)
+ {
+ root_floater->addDependentFloater(picker);
+ }
+ }
+}
+
+void LLPanelGroupBulkImpl::callbackClickRemove(void* userdata)
+{
+ LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata;
+ if (selfp)
+ selfp->handleRemove();
+}
+
+void LLPanelGroupBulkImpl::callbackClickCancel(void* userdata)
+{
+ LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata;
+ if(selfp)
+ (*(selfp->mCloseCallback))(selfp->mCloseCallbackUserData);
+}
+
+void LLPanelGroupBulkImpl::callbackSelect(LLUICtrl* ctrl, void* userdata)
+{
+ LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata;
+ if (selfp)
+ selfp->handleSelection();
+}
+
+void LLPanelGroupBulkImpl::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))
+ {
+ onAvatarNameCache(agent_ids[i], av_name, user_data);
+ }
+ else
+ {
+ LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*) 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(onAvatarNameCache, _1, _2, user_data));
+ }
+ }
+ }
+}
+
+void LLPanelGroupBulkImpl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, void* user_data)
+{
+ LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*) 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);
+ }
+}
+
+void LLPanelGroupBulkImpl::handleRemove()
+{
+ std::vector<LLScrollListItem*> selection = mBulkAgentList->getAllSelected();
+ if (selection.empty())
+ return;
+
+ std::vector<LLScrollListItem*>::iterator iter;
+ for(iter = selection.begin(); iter != selection.end(); ++iter)
+ {
+ mInviteeIDs.erase((*iter)->getUUID());
+ }
+
+ mBulkAgentList->deleteSelectedItems();
+ mRemoveButton->setEnabled(FALSE);
+
+ if( mOKButton && mOKButton->getEnabled() &&
+ mBulkAgentList->isEmpty())
+ {
+ mOKButton->setEnabled(FALSE);
+ }
+}
+
+void LLPanelGroupBulkImpl::handleSelection()
+{
+ std::vector<LLScrollListItem*> selection = mBulkAgentList->getAllSelected();
+ if (selection.empty())
+ mRemoveButton->setEnabled(FALSE);
+ else
+ mRemoveButton->setEnabled(TRUE);
+}
+
+void LLPanelGroupBulkImpl::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];
+
+ if(mInviteeIDs.find(id) != mInviteeIDs.end())
+ {
+ continue;
+ }
+
+ //add the name to the names list
+ LLSD row;
+ row["id"] = id;
+ row["columns"][0]["value"] = name;
+
+ mBulkAgentList->addElement(row);
+ mInviteeIDs.insert(id);
+
+ // We've successfully added someone to the list.
+ if(mOKButton && !mOKButton->getEnabled())
+ mOKButton->setEnabled(TRUE);
+ }
+}
+
+void LLPanelGroupBulkImpl::setGroupName(std::string name)
+{
+ if(mGroupName)
+ mGroupName->setText(name);
+}
+
+
+LLPanelGroupBulk::LLPanelGroupBulk(const LLUUID& group_id) :
+ LLPanel(),
+ mImplementation(new LLPanelGroupBulkImpl(group_id)),
+ mPendingGroupPropertiesUpdate(false),
+ mPendingRoleDataUpdate(false),
+ mPendingMemberDataUpdate(false)
+{}
+
+LLPanelGroupBulk::~LLPanelGroupBulk()
+{
+ delete mImplementation;
+}
+
+void LLPanelGroupBulk::clear()
+{
+ mImplementation->mInviteeIDs.clear();
+
+ if(mImplementation->mBulkAgentList)
+ mImplementation->mBulkAgentList->deleteAllItems();
+
+ if(mImplementation->mOKButton)
+ mImplementation->mOKButton->setEnabled(FALSE);
+}
+
+void LLPanelGroupBulk::update()
+{
+ updateGroupName();
+ updateGroupData();
+}
+
+void LLPanelGroupBulk::draw()
+{
+ LLPanel::draw();
+ update();
+}
+
+void LLPanelGroupBulk::updateGroupName()
+{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
+
+ if( gdatap &&
+ gdatap->isGroupPropertiesDataComplete())
+ {
+ // Only do work if the current group name differs
+ if(mImplementation->mGroupName->getText().compare(gdatap->mName) != 0)
+ mImplementation->setGroupName(gdatap->mName);
+ }
+ else
+ {
+ mImplementation->setGroupName(mImplementation->mLoadingText);
+ }
+}
+
+void LLPanelGroupBulk::updateGroupData()
+{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
+ if(!gdatap)
+ {
+ LL_WARNS("Groups") << "Unable to get group data for group " << mImplementation->mGroupID << LL_ENDL;
+ return;
+ }
+
+ if(gdatap->isGroupPropertiesDataComplete())
+ mPendingGroupPropertiesUpdate = false;
+ else
+ {
+ if(!mPendingGroupPropertiesUpdate)
+ {
+ mPendingGroupPropertiesUpdate = true;
+ LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID);
+ }
+ }
+
+ if(gdatap->isRoleDataComplete())
+ mPendingRoleDataUpdate = false;
+ else
+ {
+ if(!mPendingRoleDataUpdate)
+ {
+ mPendingRoleDataUpdate = true;
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
+ }
+ }
+
+ if(gdatap->isMemberDataComplete())
+ mPendingMemberDataUpdate = false;
+ else
+ {
+ if(!mPendingMemberDataUpdate)
+ {
+ mPendingMemberDataUpdate = true;
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID);
+ }
+ }
+}
+
+void LLPanelGroupBulk::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 LLPanelGroupBulk::setCloseCallback(void (*close_callback)(void*), void* data)
+{
+ mImplementation->mCloseCallback = close_callback;
+ mImplementation->mCloseCallbackUserData = data;
+}
+
+void LLPanelGroupBulk::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
+ {
+ llwarns << "llPanelGroupBulk: Selected avatar has no name: " << dest->getID() << llendl;
+ names.push_back("(Unknown)");
+ }
+ }
+ else
+ {
+ //looks like user try to invite offline friend
+ //for offline avatar_id gObjectList.findObject() will return null
+ //so we need to do this additional search in avatar tracker, see EXT-4732
+ if (LLAvatarTracker::instance().isBuddy(agent_id))
+ {
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get(agent_id, &av_name))
+ {
+ // actually it should happen, just in case
+ LLAvatarNameCache::get(LLUUID(agent_id), boost::bind(&LLPanelGroupBulk::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);
+}
+
diff --git a/indra/newview/llpanelgroupbulk.h b/indra/newview/llpanelgroupbulk.h
new file mode 100644
index 0000000000..222931eabc
--- /dev/null
+++ b/indra/newview/llpanelgroupbulk.h
@@ -0,0 +1,74 @@
+/**
+* @file llpanelgroupbulk.h
+* @brief Header file for llpanelgroupbulk
+* @author Baker@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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$
+*/
+#ifndef LL_LLPANELGROUPBULK_H
+#define LL_LLPANELGROUPBULK_H
+
+#include "llpanel.h"
+#include "lluuid.h"
+
+class LLAvatarName;
+class LLGroupMgrGroupData;
+class LLPanelGroupBulkImpl;
+
+// Base panel class for bulk group invite / ban floaters
+class LLPanelGroupBulk : public LLPanel
+{
+public:
+ LLPanelGroupBulk(const LLUUID& group_id);
+ ~LLPanelGroupBulk();
+
+public:
+ static void callbackClickSubmit(void* userdata) {}
+ virtual void submit() = 0;
+
+public:
+ virtual void clear();
+ virtual void update();
+ virtual void draw();
+
+protected:
+ virtual void updateGroupName();
+ virtual void updateGroupData();
+
+public:
+ // this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers().
+ virtual void addUserCallback(const LLUUID& id, const LLAvatarName& av_name);
+ virtual void setCloseCallback(void (*close_callback)(void*), void* data);
+
+ virtual void addUsers(uuid_vec_t& agent_ids);
+
+public:
+ LLPanelGroupBulkImpl* mImplementation;
+
+protected:
+ bool mPendingGroupPropertiesUpdate;
+ bool mPendingRoleDataUpdate;
+ bool mPendingMemberDataUpdate;
+};
+
+#endif // LL_LLPANELGROUPBULK_H
+
diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp
new file mode 100644
index 0000000000..3b442036fa
--- /dev/null
+++ b/indra/newview/llpanelgroupbulkban.cpp
@@ -0,0 +1,143 @@
+/**
+* @file llpanelgroupbulkban.cpp
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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 "llpanelgroupbulkban.h"
+#include "llpanelgroupbulk.h"
+#include "llpanelgroupbulkimpl.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"
+
+
+LLPanelGroupBulkBan::LLPanelGroupBulkBan(const LLUUID& group_id) : LLPanelGroupBulk(group_id)
+{
+ // Pass on construction of this panel to the control factory.
+ buildFromFile( "panel_group_bulk_ban.xml");
+}
+
+BOOL LLPanelGroupBulkBan::postBuild()
+{
+ BOOL recurse = TRUE;
+
+ mImplementation->mLoadingText = getString("loading");
+ mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse);
+ mImplementation->mBulkAgentList = getChild<LLNameListCtrl>("banned_agent_list", recurse);
+ if ( mImplementation->mBulkAgentList )
+ {
+ mImplementation->mBulkAgentList->setCommitOnSelectionChange(TRUE);
+ mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation);
+ }
+
+ LLButton* button = getChild<LLButton>("add_button", recurse);
+ if ( button )
+ {
+ // default to opening avatarpicker automatically
+ // (*impl::callbackClickAdd)((void*)this);
+ button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this);
+ }
+
+ mImplementation->mRemoveButton =
+ getChild<LLButton>("remove_button", recurse);
+ if ( mImplementation->mRemoveButton )
+ {
+ mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation);
+ mImplementation->mRemoveButton->setEnabled(FALSE);
+ }
+
+ mImplementation->mOKButton =
+ getChild<LLButton>("ban_button", recurse);
+ if ( mImplementation->mOKButton )
+ {
+ mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this);
+ mImplementation->mOKButton->setEnabled(FALSE);
+ }
+
+ button = getChild<LLButton>("cancel_button", recurse);
+ if ( button )
+ {
+ button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation);
+ }
+
+ mImplementation->mTooManySelected = getString("ban_selection_too_large");
+
+ update();
+ return TRUE;
+}
+
+// TODO: Refactor the shitty callback functions with void* -- just use boost::bind to call submit() instead.
+void LLPanelGroupBulkBan::callbackClickSubmit(void* userdata)
+{
+ LLPanelGroupBulkBan* selfp = (LLPanelGroupBulkBan*)userdata;
+
+ if(selfp)
+ selfp->submit();
+}
+
+
+void LLPanelGroupBulkBan::submit()
+{
+ std::vector<LLUUID> banned_agent_list;
+ std::vector<LLScrollListItem*> agents = mImplementation->mBulkAgentList->getAllData();
+ std::vector<LLScrollListItem*>::iterator iter = agents.begin();
+ for(;iter != agents.end(); ++iter)
+ {
+ LLScrollListItem* agent = *iter;
+ banned_agent_list.push_back(agent->getUUID());
+ }
+
+ const S32 MAX_GROUP_BANS = 100; // Max invites per request. 100 to match server cap.
+ if (banned_agent_list.size() > MAX_GROUP_BANS)
+ {
+ // Fail!
+ LLSD msg;
+ msg["MESSAGE"] = mImplementation->mTooManySelected;
+ LLNotificationsUtil::add("GenericAlert", msg);
+ (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
+ return;
+ }
+
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mImplementation->mGroupID, LLGroupMgr::BAN_CREATE, banned_agent_list);
+
+ //then close
+ (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
+}
+
diff --git a/indra/newview/llpanelgroupbulkban.h b/indra/newview/llpanelgroupbulkban.h
new file mode 100644
index 0000000000..0684f365a0
--- /dev/null
+++ b/indra/newview/llpanelgroupbulkban.h
@@ -0,0 +1,47 @@
+/**
+* @file llpanelgroupbulkban.h
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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$
+*/
+
+#ifndef LL_LLPANELGROUPBULKBAN_H
+#define LL_LLPANELGROUPBULKBAN_H
+
+#include "llpanel.h"
+#include "lluuid.h"
+#include "llpanelgroupbulk.h"
+
+class LLAvatarName;
+
+class LLPanelGroupBulkBan : public LLPanelGroupBulk
+{
+public:
+ LLPanelGroupBulkBan(const LLUUID& group_id);
+ ~LLPanelGroupBulkBan() {}
+
+ virtual BOOL postBuild();
+
+ static void callbackClickSubmit(void* userdata);
+ virtual void submit();
+};
+
+#endif // LL_LLPANELGROUPBULKBAN_H
diff --git a/indra/newview/llpanelgroupbulkimpl.h b/indra/newview/llpanelgroupbulkimpl.h
new file mode 100644
index 0000000000..3241c019de
--- /dev/null
+++ b/indra/newview/llpanelgroupbulkimpl.h
@@ -0,0 +1,94 @@
+/**
+* @file llpanelgroupbulkimpl.h
+* @brief Class definition for implementation class of LLPanelGroupBulk
+* @author Baker@lindenlab.com
+*
+* $LicenseInfo:firstyear=2013&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2013, 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$
+*/
+#ifndef LL_LLPANELGROUPBULKIMPL_H
+#define LL_LLPANELGROUPBULKIMPL_H
+
+#include "llpanel.h"
+#include "lluuid.h"
+
+class LLAvatarName;
+class LLNameListCtrl;
+class LLTextBox;
+class LLComboBox;
+
+//////////////////////////////////////////////////////////////////////////
+// Implementation found in llpanelgroupbulk.cpp
+//////////////////////////////////////////////////////////////////////////
+class LLPanelGroupBulkImpl
+{
+public:
+ LLPanelGroupBulkImpl(const LLUUID& group_id);
+ ~LLPanelGroupBulkImpl();
+
+ static void callbackClickAdd(void* userdata);
+ static void callbackClickRemove(void* userdata);
+
+ static void callbackClickCancel(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);
+
+ void handleRemove();
+ void handleSelection();
+
+ void addUsers(const std::vector<std::string>& names, const uuid_vec_t& agent_ids);
+ void setGroupName(std::string name);
+
+
+public:
+ static const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap.
+
+ LLUUID mGroupID;
+
+ LLNameListCtrl* mBulkAgentList;
+ LLButton* mOKButton;
+ LLButton* mRemoveButton;
+ LLTextBox* mGroupName;
+
+ std::string mLoadingText;
+ std::string mTooManySelected;
+
+ std::set<LLUUID> mInviteeIDs;
+
+ void (*mCloseCallback)(void* data);
+ void* mCloseCallbackUserData;
+ boost::signals2::connection mAvatarNameCacheConnection;
+
+ // The following are for the LLPanelGroupInvite subclass only.
+ // These aren't needed for LLPanelGroupBulkBan, but if we have to add another
+ // group bulk floater for some reason, we'll have these objects too.
+public:
+ LLComboBox* mRoleNames;
+ std::string mOwnerWarning;
+ std::string mAlreadyInGroup;
+ bool mConfirmedOwnerInvite;
+};
+
+#endif // LL_LLPANELGROUPBULKIMPL_H
+
diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp
index a9a3c686a6..19689e7f4b 100755
--- a/indra/newview/llpanelgroupinvite.cpp
+++ b/indra/newview/llpanelgroupinvite.cpp
@@ -26,6 +26,8 @@
#include "llviewerprecompiledheaders.h"
#include "llpanelgroupinvite.h"
+#include "llpanelgroupbulk.h"
+#include "llpanelgroupbulkimpl.h"
#include "llagent.h"
#include "llavatarnamecache.h"
@@ -45,203 +47,212 @@
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
-class LLPanelGroupInvite::impl
+
+bool invite_owner_callback(LLHandle<LLPanel> panel_handle, const LLSD& notification, const LLSD& response)
{
-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* panel = dynamic_cast<LLPanelGroupInvite*>(panel_handle.get());
+ if(!panel)
+ return false;
+
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch(option)
+ {
+ case 0:
+ // user confirmed that they really want a new group owner
+ panel->mImplementation->mConfirmedOwnerInvite = true;
+ panel->submit();
+ break;
+ case 1:
+ // fall through
+ default:
+ break;
+ }
+ return false;
+}
+
+
+LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id) : LLPanelGroupBulk(group_id)
{
+ // Pass on construction of this panel to the control factory.
+ buildFromFile( "panel_group_invite.xml");
}
-LLPanelGroupInvite::impl::~impl()
+void LLPanelGroupInvite::clear()
{
- if (mAvatarNameCacheConnection.connected())
+ LLPanelGroupBulk::clear();
+
+ if(mImplementation->mRoleNames)
{
- mAvatarNameCacheConnection.disconnect();
+ mImplementation->mRoleNames->clear();
+ mImplementation->mRoleNames->removeall();
+ mImplementation->mRoleNames->setCurrentByID(LLUUID::null);
}
}
-const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap.
+void LLPanelGroupInvite::update()
+{
+ LLPanelGroupBulk::update();
-void LLPanelGroupInvite::impl::addUsers(const std::vector<std::string>& names,
- const uuid_vec_t& agent_ids)
+ if(mImplementation->mRoleNames)
+ {
+ LLUUID store_selected_role = mImplementation->mRoleNames->getCurrentID();
+ mImplementation->mRoleNames->clear();
+ mImplementation->mRoleNames->removeall();
+ mImplementation->mRoleNames->setCurrentByID(LLUUID::null);
+
+ if(!mPendingRoleDataUpdate && !mPendingMemberDataUpdate)
+ {
+ //////////////////////////////////////////////////////////////////////////
+ // Add role names
+ addRoleNames();
+ ////////////////////////////////////////////////////////////////////////////
+ mImplementation->mRoleNames->setCurrentByID(store_selected_role);
+ }
+ else
+ {
+ mImplementation->mRoleNames->add(mImplementation->mLoadingText, LLUUID::null, ADD_BOTTOM);
+ }
+
+ }
+}
+
+BOOL LLPanelGroupInvite::postBuild()
{
- std::string name;
- LLUUID id;
+ BOOL recurse = TRUE;
- if (names.size() + mInviteeIDs.size() > MAX_GROUP_INVITES)
+ mImplementation->mLoadingText = getString("loading");
+ mImplementation->mRoleNames = getChild<LLComboBox>("role_name",
+ recurse);
+ mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse);
+ mImplementation->mBulkAgentList = getChild<LLNameListCtrl>("invitee_list", recurse);
+ if ( mImplementation->mBulkAgentList )
{
- // Fail! Show a warning and don't add any names.
- LLSD msg;
- msg["MESSAGE"] = mTooManySelected;
- LLNotificationsUtil::add("GenericAlert", msg);
- return;
+ mImplementation->mBulkAgentList->setCommitOnSelectionChange(TRUE);
+ mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation);
}
- for (S32 i = 0; i < (S32)names.size(); i++)
+ LLButton* button = getChild<LLButton>("add_button", recurse);
+ if ( button )
{
- name = names[i];
- id = agent_ids[i];
+ // default to opening avatarpicker automatically
+ // (*impl::callbackClickAdd)((void*)this);
+ button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this);
+ }
- // Make sure this agent isn't already in the list.
- if (mInviteeIDs.find(id) != mInviteeIDs.end())
- {
- continue;
- }
+ mImplementation->mRemoveButton =
+ getChild<LLButton>("remove_button", recurse);
+ if ( mImplementation->mRemoveButton )
+ {
+ mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation);
+ mImplementation->mRemoveButton->setEnabled(FALSE);
+ }
- //add the name to the names list
- LLSD row;
- row["id"] = id;
- row["columns"][0]["value"] = name;
+ mImplementation->mOKButton = getChild<LLButton>("invite_button", recurse);
+ if ( mImplementation->mOKButton )
+ {
+ mImplementation->mOKButton->setClickedCallback(LLPanelGroupInvite::callbackClickSubmit, this);
+ mImplementation->mOKButton->setEnabled(FALSE);
+ }
- mInvitees->addElement(row);
- mInviteeIDs.insert(id);
+ button = getChild<LLButton>("cancel_button", recurse);
+ if ( button )
+ {
+ button->setClickedCallback(LLPanelGroupBulkImpl::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->mBulkAgentList &&
+ mImplementation->mRemoveButton);
+}
+
+void LLPanelGroupInvite::callbackClickSubmit(void* userdata)
+{
+ LLPanelGroupInvite* selfp = (LLPanelGroupInvite*)userdata;
+
+ if(selfp)
+ selfp->submit();
}
-void LLPanelGroupInvite::impl::submitInvitations()
+void LLPanelGroupInvite::submit()
{
std::map<LLUUID, LLUUID> role_member_pairs;
- LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
// Default to everyone role.
LLUUID role_id = LLUUID::null;
- if (mRoleNames)
+ if (mImplementation->mRoleNames)
{
- role_id = mRoleNames->getCurrentID();
-
+ role_id = mImplementation->mRoleNames->getCurrentID();
+
+ //LLUUID t_ownerUUID = gdatap->mOwnerRole;
+ //bool t_confirmInvite = mImplementation->mConfirmedOwnerInvite;
+
// owner role: display confirmation and wait for callback
- if ((role_id == gdatap->mOwnerRole) && (!mConfirmedOwnerInvite))
+ if ((role_id == gdatap->mOwnerRole) && (!mImplementation->mConfirmedOwnerInvite))
{
LLSD args;
- args["MESSAGE"] = mOwnerWarning;
- LLNotificationsUtil::add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupInvite::impl::inviteOwnerCallback, this, _1, _2));
+ args["MESSAGE"] = mImplementation->mOwnerWarning;
+ LLNotificationsUtil::add( "GenericAlertYesCancel",
+ args,
+ LLSD(),
+ boost::bind(invite_owner_callback,
+ this->getHandle(),
+ _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();
+ std::vector<LLScrollListItem*> items = mImplementation->mBulkAgentList->getAllData();
for (std::vector<LLScrollListItem*>::iterator iter = items.begin();
- iter != items.end(); ++iter)
+ iter != items.end(); ++iter)
{
LLScrollListItem* item = *iter;
- if(LLGroupActions::isAvatarMemberOfGroup(mGroupID, item->getUUID()))
+ if(LLGroupActions::isAvatarMemberOfGroup(mImplementation->mGroupID, item->getUUID()))
{
already_in_group = true;
continue;
}
role_member_pairs[item->getUUID()] = role_id;
}
-
- if (role_member_pairs.size() > MAX_GROUP_INVITES)
+
+ if (role_member_pairs.size() > LLPanelGroupBulkImpl::MAX_GROUP_INVITES)
{
// Fail!
LLSD msg;
- msg["MESSAGE"] = mTooManySelected;
+ msg["MESSAGE"] = mImplementation->mTooManySelected;
LLNotificationsUtil::add("GenericAlert", msg);
- (*mCloseCallback)(mCloseCallbackUserData);
+ (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
return;
}
- LLGroupMgr::getInstance()->sendGroupMemberInvites(mGroupID, role_member_pairs);
-
+ LLGroupMgr::getInstance()->sendGroupMemberInvites(mImplementation->mGroupID, role_member_pairs);
+
if(already_in_group)
{
LLSD msg;
- msg["MESSAGE"] = mAlreadyInGroup;
+ msg["MESSAGE"] = mImplementation->mAlreadyInGroup;
LLNotificationsUtil::add("GenericAlert", msg);
}
//then close
- (*mCloseCallback)(mCloseCallbackUserData);
+ (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
}
-bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification, const LLSD& response)
+void LLPanelGroupInvite::addRoleNames()
{
- 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;
-}
-
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
-
-void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
-{
- LLGroupMgrGroupData::member_list_t::iterator agent_iter =
- gdatap->mMembers.find(gAgent.getID());
+ LLGroupMgrGroupData::member_list_t::iterator agent_iter = gdatap->mMembers.find(gAgent.getID());
//get the member data for the agent if it exists
if ( agent_iter != gdatap->mMembers.end() )
@@ -251,7 +262,7 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
//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 ( member_data && mRoleNames)
+ if ( member_data && mImplementation->mRoleNames)
{
//if the user is the owner then we add
//all of the roles in the group
@@ -261,10 +272,10 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
//we add every role the user is in
//else we just add to everyone
bool is_owner = member_data->isInRole(gdatap->mOwnerRole);
- bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER);
- bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
- GP_ROLE_ASSIGN_MEMBER_LIMITED);
+ bool can_assign_any = gAgent.hasPowerInGroup(mImplementation->mGroupID,
+ GP_ROLE_ASSIGN_MEMBER);
+ bool can_assign_limited = gAgent.hasPowerInGroup(mImplementation->mGroupID,
+ GP_ROLE_ASSIGN_MEMBER_LIMITED);
LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
@@ -279,401 +290,18 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
// Owners can add any role.
if ( is_owner
// Even 'can_assign_any' can't add owner role.
- || (can_assign_any && role_id != gdatap->mOwnerRole)
+ || (can_assign_any && role_id != gdatap->mOwnerRole)
// Add all roles user is in
- || (can_assign_limited && member_data->isInRole(role_id))
+ || (can_assign_limited && member_data->isInRole(role_id))
// Everyone role.
- || role_id == LLUUID::null )
+ || role_id == LLUUID::null )
{
- mRoleNames->add(rd.mRoleName,
- role_id,
- ADD_BOTTOM);
+ mImplementation->mRoleNames->add(rd.mRoleName,
+ role_id,
+ ADD_BOTTOM);
}
}
}
}//end if member data is not null
}//end if agent is in the group
}
-
-//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
- {
- llwarns << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << llendl;
- names.push_back("(Unknown)");
- }
- }
- else
- {
- //looks like user try to invite offline friend
- //for offline avatar_id gObjectList.findObject() will return null
- //so we need to do this additional search in avatar tracker, see EXT-4732
- if (LLAvatarTracker::instance().isBuddy(agent_id))
- {
- 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())
- {
- 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)
- {
- LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID);
- LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID);
- }
- mPendingUpdate = TRUE;
- }
- else
- {
- mPendingUpdate = FALSE;
- if (mImplementation->mOKButton && mImplementation->mRoleNames->getItemCount())
- {
- mImplementation->mOKButton->setEnabled(TRUE);
- }
- }
-}
-
-BOOL LLPanelGroupInvite::postBuild()
-{
- 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>("ok_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);
-}
diff --git a/indra/newview/llpanelgroupinvite.h b/indra/newview/llpanelgroupinvite.h
index 9f7b5ae9be..b87a5883b8 100755
--- a/indra/newview/llpanelgroupinvite.h
+++ b/indra/newview/llpanelgroupinvite.h
@@ -27,36 +27,27 @@
#define LL_LLPANELGROUPINVITE_H
#include "llpanel.h"
+#include "llpanelgroupbulk.h"
#include "lluuid.h"
class LLAvatarName;
-class LLPanelGroupInvite
-: public LLPanel
+class LLPanelGroupInvite : public LLPanelGroupBulk
{
public:
LLPanelGroupInvite(const LLUUID& group_id);
- ~LLPanelGroupInvite();
+ ~LLPanelGroupInvite() {};
- void addUsers(uuid_vec_t& agent_ids);
- /**
- * this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers().
- */
- void addUserCallback(const LLUUID& id, const LLAvatarName& av_name);
- void clear();
- void update();
+ virtual void clear();
+ virtual void update();
- void setCloseCallback(void (*close_callback)(void*), void* data);
-
- virtual void draw();
virtual BOOL postBuild();
-protected:
- class impl;
- impl* mImplementation;
- BOOL mPendingUpdate;
- LLUUID mStoreSelected;
- void updateLists();
+ static void callbackClickSubmit(void* userdata);
+ virtual void submit();
+
+private:
+ void addRoleNames();
};
#endif
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index fdcd1f5ebb..ad0e7ba753 100755
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -32,6 +32,7 @@
#include "llavatarnamecache.h"
#include "llbutton.h"
#include "llfiltereditor.h"
+#include "llfloatergroupbulkban.h"
#include "llfloatergroupinvite.h"
#include "llavataractions.h"
#include "lliconctrl.h"
@@ -109,8 +110,10 @@ bool agentCanAddToRole(const LLUUID& group_id,
return false;
}
-// static
+// LLPanelGroupRoles /////////////////////////////////////////////////////
+
+// static
LLPanelGroupRoles::LLPanelGroupRoles()
: LLPanelGroupTab(),
mCurrentTab(NULL),
@@ -297,7 +300,6 @@ bool LLPanelGroupRoles::onModalClose(const LLSD& notification, const LLSD& respo
return false;
}
-
bool LLPanelGroupRoles::apply(std::string& mesg)
{
// Pass this along to the currently visible sub tab.
@@ -334,7 +336,6 @@ void LLPanelGroupRoles::update(LLGroupChange gc)
{
if (mGroupID.isNull()) return;
-
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
if (panelp)
{
@@ -351,39 +352,33 @@ void LLPanelGroupRoles::activate()
{
// Start requesting member and role data if needed.
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
- //if (!gdatap || mFirstUse)
+ if (!gdatap || !gdatap->isMemberDataComplete() )
{
- // Check member data.
-
- if (!gdatap || !gdatap->isMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
- }
-
- // Check role data.
- if (!gdatap || !gdatap->isRoleDataComplete() )
- {
- // Mildly hackish - clear all pending changes
- cancel();
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
+ }
- LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
- }
+ if (!gdatap || !gdatap->isRoleDataComplete() )
+ {
+ // Mildly hackish - clear all pending changes
+ cancel();
- // Check role-member mapping data.
- if (!gdatap || !gdatap->isRoleMemberDataComplete() )
- {
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
- }
+ LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
+ }
- // Need this to get base group member powers
- if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
- {
- LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
- }
+ // Check role-member mapping data.
+ if (!gdatap || !gdatap->isRoleMemberDataComplete() )
+ {
+ LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
+ }
- mFirstUse = FALSE;
+ // Need this to get base group member powers
+ if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
+ {
+ LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
}
+ mFirstUse = FALSE;
+
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
if (panelp) panelp->activate();
}
@@ -412,10 +407,32 @@ BOOL LLPanelGroupRoles::hasModal()
return panelp->hasModal();
}
+void LLPanelGroupRoles::setGroupID(const LLUUID& id)
+{
+ LLPanelGroupTab::setGroupID(id);
+
+ LLPanelGroupMembersSubTab* group_members_tab = findChild<LLPanelGroupMembersSubTab>("members_sub_tab");
+ LLPanelGroupRolesSubTab* group_roles_tab = findChild<LLPanelGroupRolesSubTab>("roles_sub_tab");
+ LLPanelGroupActionsSubTab* group_actions_tab = findChild<LLPanelGroupActionsSubTab>("actions_sub_tab");
+ LLPanelGroupBanListSubTab* group_ban_tab = findChild<LLPanelGroupBanListSubTab>("banlist_sub_tab");
+
+ if(group_members_tab) group_members_tab->setGroupID(id);
+ if(group_roles_tab) group_roles_tab->setGroupID(id);
+ if(group_actions_tab) group_actions_tab->setGroupID(id);
+ if(group_ban_tab) group_ban_tab->setGroupID(id);
+
+ LLButton* button = getChild<LLButton>("member_invite");
+ if ( button )
+ button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE));
+
+ if(mSubTabContainer)
+ mSubTabContainer->selectTab(0);
+
+ activate();
+}
+
-////////////////////////////
-// LLPanelGroupSubTab
-////////////////////////////
+// LLPanelGroupSubTab ////////////////////////////////////////////////////
LLPanelGroupSubTab::LLPanelGroupSubTab()
: LLPanelGroupTab(),
mHeader(NULL),
@@ -728,11 +745,8 @@ void LLPanelGroupSubTab::setFooterEnabled(BOOL enable)
}
}
-////////////////////////////
-// LLPanelGroupMembersSubTab
-////////////////////////////
-
+// LLPanelGroupMembersSubTab /////////////////////////////////////////////
static LLRegisterPanelClassWrapper<LLPanelGroupMembersSubTab> t_panel_group_members_subtab("panel_group_members_subtab");
LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab()
@@ -810,6 +824,13 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
mEjectBtn->setEnabled(FALSE);
}
+ mBanBtn = parent->getChild<LLButton>("member_ban", recurse);
+ if(mBanBtn)
+ {
+ mBanBtn->setClickedCallback(onBanMember, this);
+ mBanBtn->setEnabled(FALSE);
+ }
+
return TRUE;
}
@@ -823,34 +844,6 @@ void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id)
LLPanelGroupSubTab::setGroupID(id);
}
-void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id)
-{
- if(mRolesList) mRolesList->deleteAllItems();
- if(mAssignedMembersList) mAssignedMembersList->deleteAllItems();
- if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
-
- if(mRoleName) mRoleName->clear();
- if(mRoleDescription) mRoleDescription->clear();
- if(mRoleTitle) mRoleTitle->clear();
-
- mHasRoleChange = FALSE;
-
- setFooterEnabled(FALSE);
-
- LLPanelGroupSubTab::setGroupID(id);
-}
-void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id)
-{
- if(mActionList) mActionList->deleteAllItems();
- if(mActionRoles) mActionRoles->deleteAllItems();
- if(mActionMembers) mActionMembers->deleteAllItems();
-
- if(mActionDescription) mActionDescription->clear();
-
- LLPanelGroupSubTab::setGroupID(id);
-}
-
-
// static
void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data)
{
@@ -879,7 +872,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
// Build a vector of all selected members, and gather allowed actions.
uuid_vec_t selected_members;
- U64 allowed_by_all = 0xffffffffffffLL;
+ U64 allowed_by_all = 0xFFFFffffFFFFffffLL;
U64 allowed_by_some = 0;
std::vector<LLScrollListItem*>::iterator itor;
@@ -916,8 +909,8 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
LLGroupMgrGroupData::role_list_t::iterator iter = gdatap->mRoles.begin();
LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
- BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID,
- GP_MEMBER_EJECT);
+ BOOL can_ban_members = gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS);
+ BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT);
BOOL member_is_owner = FALSE;
for( ; iter != end; ++iter)
@@ -986,6 +979,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
if (role_id.notNull() && (count > 0))
{
can_eject_members = FALSE;
+ can_ban_members = FALSE;
if (role_id == gdatap->mOwnerRole)
{
member_is_owner = TRUE;
@@ -1047,7 +1041,10 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
mAssignedRolesList->setEnabled(TRUE);
if (gAgent.isGodlike())
+ {
can_eject_members = TRUE;
+ can_ban_members = TRUE;
+ }
if (!can_eject_members && !member_is_owner)
{
@@ -1060,10 +1057,12 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
{
can_eject_members = TRUE;
+ can_ban_members = TRUE;
}
}
}
+ mBanBtn->setEnabled(can_ban_members);
mEjectBtn->setEnabled(can_eject_members);
}
@@ -1101,61 +1100,26 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata)
}
void LLPanelGroupMembersSubTab::handleEjectMembers()
-{
+{
+ //send down an eject message
+ uuid_vec_t selected_members;
+
std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
if (selection.empty()) return;
-
- S32 selection_count = selection.size();
- if (selection_count == 1)
- {
- LLSD args;
- LLUUID selected_avatar = mMembersList->getValue().asUUID();
- std::string fullname = LLSLURL("agent", selected_avatar, "inspect").getSLURLString();
- args["AVATAR_NAME"] = fullname;
- LLSD payload;
- LLNotificationsUtil::add("EjectGroupMemberWarning",
- args,
- payload,
- boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
- }
- else
- {
- LLSD args;
- args["COUNT"] = llformat("%d", selection_count);
- LLSD payload;
- LLNotificationsUtil::add("EjectGroupMembersWarning",
- args,
- payload,
- boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2));
- }
-}
-bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option) // Eject button
+ std::vector<LLScrollListItem*>::iterator itor;
+ for (itor = selection.begin() ;
+ itor != selection.end(); ++itor)
{
- //send down an eject message
- uuid_vec_t selected_members;
-
- std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
- if (selection.empty()) return false;
-
- std::vector<LLScrollListItem*>::iterator itor;
- for (itor = selection.begin() ;
- itor != selection.end(); ++itor)
- {
- LLUUID member_id = (*itor)->getUUID();
- selected_members.push_back( member_id );
- }
-
- mMembersList->deleteSelectedItems();
-
- sendEjectNotifications(mGroupID, selected_members);
-
- LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members);
+ LLUUID member_id = (*itor)->getUUID();
+ selected_members.push_back( member_id );
}
- return false;
+
+ mMembersList->deleteSelectedItems();
+
+ sendEjectNotifications(mGroupID, selected_members);
+
+ LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members);
}
void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members)
@@ -1188,7 +1152,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
BOOL is_owner_role = ( gdatap->mOwnerRole == role_id );
LLUUID member_id;
-
std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
if (selection.empty())
@@ -1199,7 +1162,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
for (std::vector<LLScrollListItem*>::iterator itor = selection.begin() ;
itor != selection.end(); ++itor)
{
-
member_id = (*itor)->getUUID();
//see if we requested a change for this member before
@@ -1265,7 +1227,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
FALSE);
}
-
// static
void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data)
{
@@ -1634,8 +1595,9 @@ void LLPanelGroupMembersSubTab::addMemberToList(LLGroupMemberData* data)
item_params.columns.add().column("donated").value(donated.getString())
.font.name("SANSSERIF_SMALL").style("NORMAL");
- item_params.columns.add().column("online").value(data->getOnlineStatus())
- .font.name("SANSSERIF_SMALL").style("NORMAL");
+ item_params.columns.add().column("online").value(data->getOnlineStatus())
+ .font.name("SANSSERIF_SMALL").style("NORMAL");
+
mMembersList->addNameItemRow(item_params);
mHasMatch = TRUE;
@@ -1687,13 +1649,12 @@ void LLPanelGroupMembersSubTab::updateMembers()
return;
}
- //cleanup list only for first iretation
+ //cleanup list only for first iteration
if(mMemberProgress == gdatap->mMembers.begin())
{
mMembersList->deleteAllItems();
}
-
LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
LLTimer update_time;
@@ -1746,12 +1707,44 @@ void LLPanelGroupMembersSubTab::updateMembers()
handleMemberSelect();
}
+void LLPanelGroupMembersSubTab::onBanMember(void* user_data)
+{
+ LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
+ self->handleBanMember();
+}
+void LLPanelGroupMembersSubTab::handleBanMember()
+{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+ if(!gdatap)
+ {
+ LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL;
+ return;
+ }
-////////////////////////////
-// LLPanelGroupRolesSubTab
-////////////////////////////
+ std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
+ if(selection.empty())
+ {
+ return;
+ }
+ uuid_vec_t ban_ids;
+ std::vector<LLScrollListItem*>::iterator itor;
+ for(itor = selection.begin(); itor != selection.end(); ++itor)
+ {
+ LLUUID ban_id = (*itor)->getUUID();
+ ban_ids.push_back(ban_id);
+
+ LLGroupBanData ban_data;
+ gdatap->createBanEntry(ban_id, ban_data);
+ }
+
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_CREATE, ban_ids);
+ handleEjectMembers();
+}
+
+
+// LLPanelGroupRolesSubTab ///////////////////////////////////////////////
static LLRegisterPanelClassWrapper<LLPanelGroupRolesSubTab> t_panel_group_roles_subtab("panel_group_roles_subtab");
LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab()
@@ -1996,7 +1989,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
mRolesList->sortByColumn(std::string("name"), TRUE);
if ( (gdatap->mRoles.size() < (U32)MAX_ROLES)
- && gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE) )
+ && gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS) )
{
mCreateRoleButton->setEnabled(TRUE);
}
@@ -2044,6 +2037,9 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
void LLPanelGroupRolesSubTab::onRoleSelect(LLUICtrl* ctrl, void* user_data)
{
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
+ if (!self)
+ return;
+
self->handleRoleSelect();
}
@@ -2284,7 +2280,6 @@ bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD&
return false;
}
-
// static
void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_data)
{
@@ -2462,12 +2457,27 @@ void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role)
mHasRoleChange = FALSE;
}
}
-////////////////////////////
-// LLPanelGroupActionsSubTab
-////////////////////////////
-static LLRegisterPanelClassWrapper<LLPanelGroupActionsSubTab> t_panel_group_actions_subtab("panel_group_actions_subtab");
+void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id)
+{
+ if(mRolesList) mRolesList->deleteAllItems();
+ if(mAssignedMembersList) mAssignedMembersList->deleteAllItems();
+ if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
+ if(mRoleName) mRoleName->clear();
+ if(mRoleDescription) mRoleDescription->clear();
+ if(mRoleTitle) mRoleTitle->clear();
+
+ mHasRoleChange = FALSE;
+
+ setFooterEnabled(FALSE);
+
+ LLPanelGroupSubTab::setGroupID(id);
+}
+
+
+// LLPanelGroupActionsSubTab /////////////////////////////////////////////
+static LLRegisterPanelClassWrapper<LLPanelGroupActionsSubTab> t_panel_group_actions_subtab("panel_group_actions_subtab");
LLPanelGroupActionsSubTab::LLPanelGroupActionsSubTab()
: LLPanelGroupSubTab()
@@ -2641,26 +2651,255 @@ void LLPanelGroupActionsSubTab::handleActionSelect()
}
}
-void LLPanelGroupRoles::setGroupID(const LLUUID& id)
+void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id)
{
- LLPanelGroupTab::setGroupID(id);
+ if(mActionList) mActionList->deleteAllItems();
+ if(mActionRoles) mActionRoles->deleteAllItems();
+ if(mActionMembers) mActionMembers->deleteAllItems();
+
+ if(mActionDescription) mActionDescription->clear();
+
+ LLPanelGroupSubTab::setGroupID(id);
+}
+
+
+// LLPanelGroupBanListSubTab /////////////////////////////////////////////
+static LLRegisterPanelClassWrapper<LLPanelGroupBanListSubTab> t_panel_group_ban_subtab("panel_group_banlist_subtab");
+
+LLPanelGroupBanListSubTab::LLPanelGroupBanListSubTab()
+ : LLPanelGroupSubTab(),
+ mBanList(NULL),
+ mCreateBanButton(NULL),
+ mDeleteBanButton(NULL)
+{}
+
+BOOL LLPanelGroupBanListSubTab::postBuildSubTab(LLView* root)
+{
+ LLPanelGroupSubTab::postBuildSubTab(root);
+
+ // Upcast parent so we can ask it for sibling controls.
+ LLPanelGroupRoles* parent = (LLPanelGroupRoles*)root;
+
+ // Look recursively from the parent to find all our widgets.
+ bool recurse = true;
- LLPanelGroupMembersSubTab* group_members_tab = findChild<LLPanelGroupMembersSubTab>("members_sub_tab");
- LLPanelGroupRolesSubTab* group_roles_tab = findChild<LLPanelGroupRolesSubTab>("roles_sub_tab");
- LLPanelGroupActionsSubTab* group_actions_tab = findChild<LLPanelGroupActionsSubTab>("actions_sub_tab");
+ mHeader = parent->getChild<LLPanel>("banlist_header", recurse);
+ mFooter = parent->getChild<LLPanel>("banlist_footer", recurse);
+
+ mBanList = parent->getChild<LLNameListCtrl>("ban_list", recurse);
+
+ mCreateBanButton = parent->getChild<LLButton>("ban_create", recurse);
+ mDeleteBanButton = parent->getChild<LLButton>("ban_delete", recurse);
+ mRefreshBanListButton = parent->getChild<LLButton>("ban_refresh", recurse);
- if(group_members_tab) group_members_tab->setGroupID(id);
- if(group_roles_tab) group_roles_tab->setGroupID(id);
- if(group_actions_tab) group_actions_tab->setGroupID(id);
+ if(!mBanList || !mCreateBanButton || !mDeleteBanButton || !mRefreshBanListButton)
+ return FALSE;
- LLButton* button = getChild<LLButton>("member_invite");
- if ( button )
- button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE));
+ mBanList->setCommitOnSelectionChange(TRUE);
+ mBanList->setCommitCallback(onBanEntrySelect, this);
- if(mSubTabContainer)
- mSubTabContainer->selectTab(0);
+ mCreateBanButton->setClickedCallback(onCreateBanEntry, this);
+ mCreateBanButton->setEnabled(FALSE);
- activate();
+ mDeleteBanButton->setClickedCallback(onDeleteBanEntry, this);
+ mDeleteBanButton->setEnabled(FALSE);
+
+ mRefreshBanListButton->setClickedCallback(onRefreshBanList, this);
+ mRefreshBanListButton->setEnabled(FALSE);
+
+ mBanList->setOnNameListCompleteCallback(boost::bind(&LLPanelGroupBanListSubTab::onBanListCompleted, this, _1));
+
+ setFooterEnabled(FALSE);
+ return TRUE;
+}
+
+void LLPanelGroupBanListSubTab::activate()
+{
+ LLPanelGroupSubTab::activate();
+
+ mBanList->deselectAllItems();
+ mDeleteBanButton->setEnabled(FALSE);
+
+ if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
+ {
+ mCreateBanButton->setEnabled(TRUE);
+ }
+
+ // BAKER: Should I really request everytime activate() is called?
+ // Perhaps I should only do it on a force refresh, or if an action on the list happens...
+ // Because it's not going to live-update the list anyway... You'd have to refresh if you
+ // wanted to see someone else's additions anyway...
+ //
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID);
+
+ setFooterEnabled(FALSE);
+ update(GC_ALL);
+}
+
+void LLPanelGroupBanListSubTab::update(LLGroupChange gc)
+{
+ populateBanList();
+}
+
+void LLPanelGroupBanListSubTab::draw()
+{
+ LLPanelGroupSubTab::draw();
+
+ // BAKER: Might be good to put it here instead of update, maybe.. See how often draw gets hit.
+ // populateBanList();
+}
+
+void LLPanelGroupBanListSubTab::onBanEntrySelect(LLUICtrl* ctrl, void* user_data)
+{
+ LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data);
+ if (!self)
+ return;
+
+ self->handleBanEntrySelect();
}
+void LLPanelGroupBanListSubTab::handleBanEntrySelect()
+{
+ if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
+ {
+ mDeleteBanButton->setEnabled(TRUE);
+ }
+}
+
+void LLPanelGroupBanListSubTab::onCreateBanEntry(void* user_data)
+{
+ LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data);
+ if (!self)
+ return;
+
+ self->handleCreateBanEntry();
+}
+
+void LLPanelGroupBanListSubTab::handleCreateBanEntry()
+{
+ LLFloaterGroupBulkBan::showForGroup(mGroupID);
+ populateBanList();
+}
+
+void LLPanelGroupBanListSubTab::onDeleteBanEntry(void* user_data)
+{
+ LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data);
+ if (!self)
+ return;
+
+ self->handleDeleteBanEntry();
+}
+
+void LLPanelGroupBanListSubTab::handleDeleteBanEntry()
+{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+ if(!gdatap)
+ {
+ LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL;
+ return;
+ }
+
+ std::vector<LLScrollListItem*> selection = mBanList->getAllSelected();
+ if(selection.empty())
+ {
+ return;
+ }
+
+ bool can_ban_members = false;
+ if (gAgent.isGodlike() ||
+ gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
+ {
+ can_ban_members = true;
+ }
+
+ // Owners can ban anyone in the group.
+ LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(gAgent.getID());
+ if (mi != gdatap->mMembers.end())
+ {
+ LLGroupMemberData* member_data = (*mi).second;
+ if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
+ {
+ can_ban_members = true;
+ }
+ }
+
+ if(!can_ban_members)
+ return;
+
+ std::vector<LLUUID> ban_ids;
+ std::vector<LLScrollListItem*>::iterator itor;
+ for(itor = selection.begin(); itor != selection.end(); ++itor)
+ {
+ LLUUID ban_id = (*itor)->getUUID();
+ ban_ids.push_back(ban_id);
+
+ gdatap->removeBanEntry(ban_id);
+ mBanList->removeNameItem(ban_id);
+
+ // Removing an item removes the selection, we shouldn't be able to click
+ // the button anymore until we reselect another entry.
+ mDeleteBanButton->setEnabled(FALSE);
+ }
+
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_DELETE, ban_ids);
+}
+
+void LLPanelGroupBanListSubTab::onRefreshBanList(void* user_data)
+{
+ LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data);
+ if (!self)
+ return;
+
+ self->handleRefreshBanList();
+}
+
+void LLPanelGroupBanListSubTab::handleRefreshBanList()
+{
+ mRefreshBanListButton->setEnabled(FALSE);
+ LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID);
+}
+
+void LLPanelGroupBanListSubTab::onBanListCompleted(bool isComplete)
+{
+ if(isComplete)
+ {
+ mRefreshBanListButton->setEnabled(TRUE);
+ populateBanList();
+ }
+}
+
+void LLPanelGroupBanListSubTab::populateBanList()
+{
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
+ if(!gdatap)
+ {
+ LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL;
+ return;
+ }
+
+ mBanList->deleteAllItems();
+ std::map<LLUUID,LLGroupBanData>::const_iterator entry = gdatap->mBanList.begin();
+ for(; entry != gdatap->mBanList.end(); entry++)
+ {
+ LLNameListCtrl::NameItem ban_entry;
+ ban_entry.value = entry->first;
+ LLGroupBanData bd = entry->second;
+
+ ban_entry.columns.add().column("name").font.name("SANSSERIF_SMALL").style("NORMAL");
+ ban_entry.columns.add().column("ban_date").value(bd.mBanDate.toHTTPDateString("%Y/%m/%d")).font.name("SANSSERIF_SMALL").style("NORMAL");
+
+ mBanList->addNameItemRow(ban_entry);
+ }
+
+ mRefreshBanListButton->setEnabled(TRUE);
+}
+
+void LLPanelGroupBanListSubTab::setGroupID(const LLUUID& id)
+{
+ if(mBanList)
+ mBanList->deleteAllItems();
+
+ setFooterEnabled(FALSE);
+ LLPanelGroupSubTab::setGroupID(id);
+}
diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h
index 0cf272f3ee..e74e4f746d 100755
--- a/indra/newview/llpanelgrouproles.h
+++ b/indra/newview/llpanelgrouproles.h
@@ -39,11 +39,9 @@ class LLScrollListCtrl;
class LLScrollListItem;
class LLTextEditor;
-// Forward declare for friend usage.
-//virtual BOOL LLPanelGroupSubTab::postBuildSubTab(LLView*);
-
typedef std::map<std::string,std::string> icon_map_t;
+
class LLPanelGroupRoles : public LLPanelGroupTab
{
public:
@@ -92,6 +90,7 @@ protected:
std::string mWantApplyMesg;
};
+
class LLPanelGroupSubTab : public LLPanelGroupTab
{
public:
@@ -147,6 +146,7 @@ protected:
void setOthersVisible(BOOL b);
};
+
class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab
{
public:
@@ -173,6 +173,10 @@ public:
void handleRoleCheck(const LLUUID& role_id,
LLRoleMemberChangeType type);
+ static void onBanMember(void* user_data);
+ void handleBanMember();
+
+
void applyMemberChanges();
bool addOwnerCB(const LLSD& notification, const LLSD& response);
@@ -206,6 +210,7 @@ protected:
LLScrollListCtrl* mAssignedRolesList;
LLScrollListCtrl* mAllowedActionsList;
LLButton* mEjectBtn;
+ LLButton* mBanBtn;
BOOL mChanged;
BOOL mPendingMemberUpdate;
@@ -218,6 +223,7 @@ protected:
boost::signals2::connection mAvatarNameCacheConnection;
};
+
class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab
{
public:
@@ -280,6 +286,7 @@ protected:
std::string mRemoveEveryoneTxt;
};
+
class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab
{
public:
@@ -307,4 +314,44 @@ protected:
};
+class LLPanelGroupBanListSubTab : public LLPanelGroupSubTab
+{
+public:
+ LLPanelGroupBanListSubTab();
+ virtual ~LLPanelGroupBanListSubTab() {}
+
+ virtual BOOL postBuildSubTab(LLView* root);
+
+ virtual void activate();
+ virtual void update(LLGroupChange gc);
+ virtual void draw();
+
+ static void onBanEntrySelect(LLUICtrl* ctrl, void* user_data);
+ void handleBanEntrySelect();
+
+ static void onCreateBanEntry(void* user_data);
+ void handleCreateBanEntry();
+
+ static void onDeleteBanEntry(void* user_data);
+ void handleDeleteBanEntry();
+
+ static void onRefreshBanList(void* user_data);
+ void handleRefreshBanList();
+
+ void onBanListCompleted(bool isComplete);
+
+protected:
+ void populateBanList();
+
+public:
+ virtual void setGroupID(const LLUUID& id);
+
+protected:
+ LLNameListCtrl* mBanList;
+ LLButton* mCreateBanButton;
+ LLButton* mDeleteBanButton;
+ LLButton* mRefreshBanListButton;
+
+};
+
#endif // LL_LLPANELGROUPROLES_H
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 6018c2d250..20b210e69a 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1604,6 +1604,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("GetObjectCost");
capabilityNames.append("GetObjectPhysicsData");
capabilityNames.append("GetTexture");
+ capabilityNames.append("GroupBan");
capabilityNames.append("GroupMemberData");
capabilityNames.append("GroupProposalBallot");
capabilityNames.append("HomeLocation");
diff --git a/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml b/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml
new file mode 100644
index 0000000000..bdea79f79d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ height="330"
+ label="Ban Residents"
+ layout="topleft"
+ left="0"
+ name="bulk_ban_panel"
+ top="330"
+ width="210">
+ <panel.string
+ name="loading">
+ (loading...)
+ </panel.string>
+ <panel.string
+ name="ban_selection_too_large">
+ Group Invitations not sent: too many Residents selected. Group Invitations are limited to 100 per request.
+ </panel.string>
+ <text
+ type="string"
+ length="1"
+ height="54"
+ layout="topleft"
+ left="7"
+ name="help_text"
+ top="28"
+ word_wrap="true"
+ width="200">
+ You can select multiple Residents to ban from your group. Click &apos;Open Resident Chooser&apos; to start.
+ </text>
+ <button
+ height="20"
+ label="Open Resident Chooser"
+ layout="topleft"
+ left_delta="-2"
+ name="add_button"
+ top_delta="44"
+ width="200" />
+ <name_list
+ allow_calling_card_drop="true"
+ column_padding="0"
+ height="174"
+ layout="topleft"
+ left_delta="0"
+ multi_select="true"
+ name="banned_agent_list"
+ tool_tip="Hold the Ctrl key and click Resident names to multi-select"
+ top_pad="4"
+ width="200" />
+ <button
+ height="20"
+ label="Remove Selected from List"
+ layout="topleft"
+ left_delta="0"
+ name="remove_button"
+ tool_tip="Removes the Residents selected above from the ban list"
+ top_pad="4"
+ width="200" />
+ <button
+ height="20"
+ label="Ban Residents"
+ layout="topleft"
+ left="4"
+ name="ban_button"
+ top_delta="30"
+ width="135" />
+ <button
+ height="20"
+ label="Cancel"
+ layout="topleft"
+ left_pad="2"
+ name="cancel_button"
+ top_delta="0"
+ width="65" />
+ <string
+ name="GroupBulkBan">
+ Group Ban
+ </string>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_group_invite.xml b/indra/newview/skins/default/xui/en/panel_group_invite.xml
index 124c0596c3..944a496fba 100755
--- a/indra/newview/skins/default/xui/en/panel_group_invite.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_invite.xml
@@ -88,7 +88,7 @@
label="Send Invitations"
layout="topleft"
left="4"
- name="ok_button"
+ name="invite_button"
top="356"
width="135" />
<button
diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml
index df91ad8b5e..9c3dddf476 100755
--- a/indra/newview/skins/default/xui/en/panel_group_roles.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml
@@ -7,125 +7,132 @@
top="0"
name="roles_tab"
width="304">
- <panel.string
- name="default_needs_apply_text">
- There are unsaved changes
- </panel.string>
- <panel.string
- name="want_apply_text">
- Do you want to save your changes?
- </panel.string>
- <panel.string
- name="help_text" />
- <tab_container
- border="false"
- follows="left|top|right"
- height="552"
- halign="center"
+ <panel.string
+ name="default_needs_apply_text">
+ There are unsaved changes
+ </panel.string>
+ <panel.string
+ name="want_apply_text">
+ Do you want to save your changes?
+ </panel.string>
+ <panel.string
+ name="help_text" />
+ <tab_container
+ border="false"
+ follows="left|top|right"
+ height="552"
+ halign="center"
+ layout="topleft"
+ left="0"
+ right="-1"
+ name="roles_tab_container"
+ tab_position="top"
+ tab_height="22"
+ tab_min_width="90"
+ top="0"
+ width="304">
+ <panel
+ border="false"
+ follows="all"
+ height="303"
+ label="MEMBERS"
layout="topleft"
left="0"
right="-1"
- name="roles_tab_container"
- tab_position="top"
- tab_height="22"
- tab_min_width="90"
- top="0"
- width="304">
- <panel
- border="false"
- follows="all"
- height="303"
- label="MEMBERS"
- layout="topleft"
- left="0"
- right="-1"
- help_topic="roles_members_tab"
- name="members_sub_tab"
- tool_tip="Members"
- class="panel_group_members_subtab">
- <panel.string
- name="help_text">
- You can add or remove Roles assigned to Members.
-Select multiple Members by holding the Ctrl key and
-clicking on their names.
- </panel.string>
- <panel.string
- name="donation_area">
- [AREA] m²
- </panel.string>
- <panel.string
- name="power_folder_icon" translate="false">
- Inv_FolderClosed
- </panel.string>
- <panel.string
- name="power_all_have_icon" translate="false">
- Checkbox_On
- </panel.string>
- <panel.string
- name="power_partial_icon" translate="false">
- Checkbox_Off
- </panel.string>
- <filter_editor
- layout="topleft"
- top="5"
- left="5"
- right="-5"
- height="22"
- search_button_visible="false"
- follows="left|top|right"
- label="Filter Members"
- name="filter_input" />
- <name_list
- column_padding="2"
- draw_heading="true"
- height="240"
- follows="left|top|right"
- layout="topleft"
- left="0"
- right="-1"
- multi_select="true"
- name="member_list"
- short_names="false"
- top_pad="5">
- <name_list.columns
- label="Member"
- name="name"
- relative_width="0.44" />
- <name_list.columns
- label="Donation"
- name="donated"
- relative_width="0.25" />
- <name_list.columns
- label="Status"
- name="online"
- relative_width="0.14" />
- </name_list>
- <button
- height="23"
- follows="top|left"
- label="Invite"
- left="5"
- name="member_invite"
- width="100" />
- <button
- height="23"
- label="Eject"
- follows="top|left"
- left_pad="10"
- name="member_eject"
- width="100" />
- </panel>
- <panel
- border="false"
- height="303"
- label="ROLES"
- layout="topleft"
- left="0"
- right="-1"
- help_topic="roles_roles_tab"
- name="roles_sub_tab"
- class="panel_group_roles_subtab">
- <!-- <button
+ help_topic="roles_members_tab"
+ name="members_sub_tab"
+ tool_tip="Members"
+ class="panel_group_members_subtab">
+ <panel.string
+ name="help_text">
+ You can add or remove Roles assigned to Members.
+ Select multiple Members by holding the Ctrl key and
+ clicking on their names.
+ </panel.string>
+ <panel.string
+ name="donation_area">
+ [AREA] m²
+ </panel.string>
+ <panel.string
+ name="power_folder_icon" translate="false">
+ Inv_FolderClosed
+ </panel.string>
+ <panel.string
+ name="power_all_have_icon" translate="false">
+ Checkbox_On
+ </panel.string>
+ <panel.string
+ name="power_partial_icon" translate="false">
+ Checkbox_Off
+ </panel.string>
+ <filter_editor
+ layout="topleft"
+ top="5"
+ left="5"
+ right="-5"
+ height="22"
+ search_button_visible="false"
+ follows="left|top|right"
+ label="Filter Members"
+ name="filter_input" />
+ <name_list
+ column_padding="2"
+ draw_heading="true"
+ height="240"
+ follows="left|top|right"
+ layout="topleft"
+ left="0"
+ right="-1"
+ multi_select="true"
+ name="member_list"
+ short_names="false"
+ top_pad="5">
+ <name_list.columns
+ label="Member"
+ name="name"
+ relative_width="0.44" />
+ <name_list.columns
+ label="Donation"
+ name="donated"
+ relative_width="0.25" />
+ <name_list.columns
+ label="Status"
+ name="online"
+ relative_width="0.14" />
+ </name_list>
+ <button
+ height="23"
+ follows="top|left"
+ label="Invite"
+ left="5"
+ name="member_invite"
+ width="100" />
+ <button
+ height="23"
+ label="Eject"
+ follows="top|left"
+ left_pad="10"
+ name="member_eject"
+ width="100" />
+ <button
+ height="23"
+ label="Ban Member(s)"
+ follows="top|left"
+ left_pad="10"
+ name="member_ban"
+ width="100" />
+ </panel>
+ <panel
+ border="false"
+ height="303"
+ label="ROLES"
+ layout="topleft"
+ left="0"
+ right="-1"
+ help_topic="roles_roles_tab"
+ name="roles_sub_tab"
+ class="panel_group_roles_subtab">
+ <!-- <button
enabled="false"
height="20"
label="Show All"
@@ -134,454 +141,532 @@ clicking on their names.
right="-5"
name="show_all_button"
width="100" />-->
- <panel.string
- name="help_text">
- Roles have a title and an allowed list of Abilities
-that Members can perform. Members can belong to
-one or more Roles. A group can have up to 10 Roles,
-including the Everyone and Owner Roles.
- </panel.string>
- <panel.string
- name="cant_delete_role">
- The &apos;Everyone&apos; and &apos;Owners&apos; Roles are special and can't be deleted.
- </panel.string>
- <panel.string
- name="power_folder_icon" translate="false">
- Inv_FolderClosed
- </panel.string>
- <panel.string
- name="power_all_have_icon" translate="false">
- Checkbox_On
- </panel.string>
- <panel.string
- name="power_partial_icon" translate="false">
- Checkbox_Off
- </panel.string>
- <filter_editor
- layout="topleft"
- top="5"
- left="5"
- right="-5"
- height="22"
- search_button_visible="false"
- follows="left|top|right"
- label="Filter Roles"
- name="filter_input" />
- <scroll_list
- column_padding="0"
- draw_heading="true"
- draw_stripes="false"
- heading_height="23"
- height="132"
- layout="topleft"
- search_column="1"
- left="0"
- follows="left|top|right"
- right="-1"
- name="role_list"
- top_pad="2"
- width="310">
- <scroll_list.columns
- label="Role"
- name="name"
- relative_width="0.45" />
- <scroll_list.columns
- label="Title"
- name="title"
- relative_width="0.45" />
- <scroll_list.columns
- label="#"
- name="members"
- relative_width="0.15" />
- </scroll_list>
- <button
- follows="top|left"
- height="23"
- label="New Role"
- layout="topleft"
- left="0"
- name="role_create"
- width="120" />
- <button
- height="23"
- follows="top|left"
- label="Delete Role"
- layout="topleft"
- left_pad="10"
- name="role_delete"
- width="120" />
- </panel>
- <panel
- border="false"
- height="303"
- label="ABILITIES"
- layout="topleft"
- left="0"
- right="-1"
- help_topic="roles_actions_tab"
- name="actions_sub_tab"
- class="panel_group_actions_subtab"
- tool_tip="You can view an Ability&apos;s Description and which Roles and Members can execute the Ability."
- width="310">
- <panel.string
- name="help_text">
- Abilities allow Members in Roles to do specific
-things in this group. There&apos;s a broad variety of Abilities.
- </panel.string>
- <panel.string
- name="power_folder_icon" translate="false">
- Inv_FolderClosed
- </panel.string>
- <panel.string
- name="power_all_have_icon" translate="false">
- Checkbox_On
- </panel.string>
- <panel.string
- name="power_partial_icon" translate="false">
- Checkbox_Off
- </panel.string>
- <filter_editor
- layout="topleft"
- top="5"
- left="5"
- right="-5"
- height="22"
- search_button_visible="false"
- follows="left|top|right"
- label="Filter Abilities"
- name="filter_input" />
- <scroll_list
- column_padding="0"
- draw_stripes="true"
- height="200"
- follows="left|top|right"
- layout="topleft"
- left="0"
- right="-1"
- name="action_list"
- search_column="2"
- tool_tip="Select an Ability to view more details"
- top_pad="5"
- width="300">
- <scroll_list.columns
- label=""
- name="icon"
- width="2" />
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="action"
- width="270" />
- </scroll_list>
- </panel>
- </tab_container>
+ <panel.string
+ name="help_text">
+ Roles have a title and an allowed list of Abilities
+ that Members can perform. Members can belong to
+ one or more Roles. A group can have up to 10 Roles,
+ including the Everyone and Owner Roles.
+ </panel.string>
+ <panel.string
+ name="cant_delete_role">
+ The &apos;Everyone&apos; and &apos;Owners&apos; Roles are special and can't be deleted.
+ </panel.string>
+ <panel.string
+ name="power_folder_icon" translate="false">
+ Inv_FolderClosed
+ </panel.string>
+ <panel.string
+ name="power_all_have_icon" translate="false">
+ Checkbox_On
+ </panel.string>
+ <panel.string
+ name="power_partial_icon" translate="false">
+ Checkbox_Off
+ </panel.string>
+ <filter_editor
+ layout="topleft"
+ top="5"
+ left="5"
+ right="-5"
+ height="22"
+ search_button_visible="false"
+ follows="left|top|right"
+ label="Filter Roles"
+ name="filter_input" />
+ <scroll_list
+ column_padding="0"
+ draw_heading="true"
+ draw_stripes="false"
+ heading_height="23"
+ height="132"
+ layout="topleft"
+ search_column="1"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ name="role_list"
+ top_pad="2"
+ width="310">
+ <scroll_list.columns
+ label="Role"
+ name="name"
+ relative_width="0.45" />
+ <scroll_list.columns
+ label="Title"
+ name="title"
+ relative_width="0.45" />
+ <scroll_list.columns
+ label="#"
+ name="members"
+ relative_width="0.15" />
+ </scroll_list>
+ <button
+ follows="top|left"
+ height="23"
+ label="New Role"
+ layout="topleft"
+ left="0"
+ name="role_create"
+ width="120" />
+ <button
+ height="23"
+ follows="top|left"
+ label="Delete Role"
+ layout="topleft"
+ left_pad="10"
+ name="role_delete"
+ width="120" />
+ </panel>
<panel
- height="350"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
+ border="false"
+ height="303"
+ label="ABILITIES"
layout="topleft"
- follows="top|left|right"
left="0"
right="-1"
- width="313"
- mouse_opaque="false"
- name="members_footer"
- top="325"
- visible="false">
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- top="8"
- text_color="EmphasisColor"
- name="static"
- width="300">
- Assigned Roles
- </text>
- <scroll_list
- draw_stripes="true"
- follows="left|top|right"
- height="150"
- layout="topleft"
- left="0"
- right="-1"
- name="member_assigned_roles"
- top_pad="0">
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="role"
- width="270" />
- </scroll_list>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- top_pad="5"
- text_color="EmphasisColor"
- name="static2"
- width="285">
- Allowed Abilities
- </text>
- <scroll_list
- draw_stripes="true"
- follows="left|top|right"
- height="150"
- layout="topleft"
- left="0"
- right="-1"
- name="member_allowed_actions"
- search_column="2"
- tool_tip="For details of each allowed ability see the abilities tab"
- top_pad="0">
- <scroll_list.columns
- label=""
- name="icon"
- width="2" />
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="action"
- width="270" />
- </scroll_list>
+ help_topic="roles_actions_tab"
+ name="actions_sub_tab"
+ class="panel_group_actions_subtab"
+ tool_tip="You can view an Ability&apos;s Description and which Roles and Members can execute the Ability."
+ width="310">
+ <panel.string
+ name="help_text">
+ Abilities allow Members in Roles to do specific
+ things in this group. There&apos;s a broad variety of Abilities.
+ </panel.string>
+ <panel.string
+ name="power_folder_icon" translate="false">
+ Inv_FolderClosed
+ </panel.string>
+ <panel.string
+ name="power_all_have_icon" translate="false">
+ Checkbox_On
+ </panel.string>
+ <panel.string
+ name="power_partial_icon" translate="false">
+ Checkbox_Off
+ </panel.string>
+ <filter_editor
+ layout="topleft"
+ top="5"
+ left="5"
+ right="-5"
+ height="22"
+ search_button_visible="false"
+ follows="left|top|right"
+ label="Filter Abilities"
+ name="filter_input" />
+ <scroll_list
+ column_padding="0"
+ draw_stripes="true"
+ height="200"
+ follows="left|top|right"
+ layout="topleft"
+ left="0"
+ right="-1"
+ name="action_list"
+ search_column="2"
+ tool_tip="Select an Ability to view more details"
+ top_pad="5"
+ width="300">
+ <scroll_list.columns
+ label=""
+ name="icon"
+ width="2" />
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="action"
+ width="270" />
+ </scroll_list>
</panel>
<panel
- height="550"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
+ border="false"
+ height="303"
+ label="BANNED AGENTS"
layout="topleft"
- follows="top|left|right"
left="0"
right="-1"
- width="313"
- mouse_opaque="false"
- name="roles_footer"
- top_delta="0"
- top="209"
- visible="false">
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- top="5"
- name="static"
- width="300">
- Role Name
- </text>
- <line_editor
- type="string"
- height="20"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- max_length_bytes="20"
- name="role_name"
- top_pad="0"
- width="300">
- </line_editor>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- name="static3"
- top_pad="5"
- width="300">
- Role Title
- </text>
- <line_editor
- type="string"
- height="20"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- max_length_bytes="20"
- name="role_title"
- top_pad="0"
- width="300">
- </line_editor>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- name="static2"
- top_pad="5"
- width="200">
- Description
- </text>
- <text_editor
- type="string"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- max_length="295"
- height="35"
- name="role_description"
- top_pad="0"
- width="300"
- word_wrap="true">
- </text_editor>
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- text_color="EmphasisColor"
- name="static4"
- top_pad="5"
- width="300">
- Assigned Members
- </text>
- <name_list
- draw_stripes="true"
- height="128"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- name="role_assigned_members"
- top_pad="0"
- width="300" />
- <check_box
- height="15"
- label="Reveal members"
- left="5"
- layout="topleft"
- name="role_visible_in_list"
- tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group."
- top_pad="4"
- width="300" />
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- text_color="EmphasisColor"
- name="static5"
- top_pad="2"
- width="300">
- Allowed Abilities
- </text>
- <scroll_list
- draw_stripes="true"
- height="140"
- layout="topleft"
- left="0"
- follows="left|top|right"
- right="-1"
- name="role_allowed_actions"
- search_column="2"
- tool_tip="For details of each allowed ability see the abilities tab"
- top_pad="0"
- width="300">
- <scroll_list.columns
- label=""
- name="icon"
- width="2" />
- <scroll_list.columns
- label=""
- name="checkbox"
- width="20" />
- <scroll_list.columns
- label=""
- name="action"
- width="270" />
- </scroll_list>
+ help_topic="roles_banlist_tab"
+ name="banlist_sub_tab"
+ class="panel_group_banlist_subtab"
+ tool_tip="View the banned agents from this group."
+ width="310">
+ <panel.string
+ name="help_text">
+ Any resident on the ban list will be unable to join the group.
+ </panel.string>
+ <filter_editor
+ layout="topleft"
+ top="5"
+ left="5"
+ right="-5"
+ height="22"
+ search_button_visible="false"
+ follows="left|top|right"
+ label="Filter Bans"
+ name="filter_bans" />
+ <name_list
+ column_padding="0"
+ draw_heading="true"
+ height="400"
+ follows="left|top|right"
+ layout="topleft"
+ left="0"
+ right="-1"
+ multi_select="true"
+ name="ban_list"
+ short_names="false"
+ top_pad="5">
+ <name_list.columns
+ label="Resident"
+ name="name"
+ font.name="SANSSERIF_SMALL"
+ font.style="NORMAL"
+ relative_width="0.7" />
+ <name_list.columns
+ label="Date Banned"
+ name="ban_date"
+ relative_width="0.3" />
+ </name_list>
+ <button
+ follows="top|left"
+ height="23"
+ label="Ban Resident(s)"
+ layout="topleft"
+ left="3"
+ name="ban_create"
+ tool_tip="Ban residents from your group"
+ width="120" />
+ <button
+ follows="top|left"
+ height="23"
+ label="Remove Ban(s)"
+ layout="topleft"
+ left_pad="5"
+ name="ban_delete"
+ tool_tip="Unban selected residents from your group"
+ width="120" />
+ <button
+ follows="top|left"
+ height="23"
+ width="23"
+ image_overlay="Refresh_Off"
+ layout="topleft"
+ left_pad="5"
+ name="ban_refresh"
+ tool_tip="Refresh the ban list"
+ />
</panel>
- <panel
- height="424"
- background_visible="false"
- bg_alpha_color="FloaterUnfocusBorderColor"
+ </tab_container>
+ <panel
+ height="350"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
+ layout="topleft"
+ follows="top|left|right"
+ left="0"
+ right="-1"
+ width="313"
+ mouse_opaque="false"
+ name="members_footer"
+ top="325"
+ visible="false">
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ top="8"
+ text_color="EmphasisColor"
+ name="static"
+ width="300">
+ Assigned Roles
+ </text>
+ <scroll_list
+ draw_stripes="true"
+ follows="left|top|right"
+ height="150"
layout="topleft"
- follows="top|left|right"
left="0"
right="-1"
- width="313"
- mouse_opaque="false"
- name="actions_footer"
- top_delta="0"
- top="255"
- visible="false">
- <text_editor
- bg_readonly_color="Transparent"
- text_readonly_color="EmphasisColor"
- font="SansSerifSmall"
- type="string"
- enabled="false"
- halign="left"
- layout="topleft"
+ name="member_assigned_roles"
+ top_pad="0">
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="role"
+ width="270" />
+ </scroll_list>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ top_pad="5"
+ text_color="EmphasisColor"
+ name="static2"
+ width="285">
+ Allowed Abilities
+ </text>
+ <scroll_list
+ draw_stripes="true"
follows="left|top|right"
- left="0"
- right="-1"
- height="90"
- max_length="512"
- name="action_description"
- top="0"
- word_wrap="true">
- This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
- </text_editor>
- <text
+ height="150"
+ layout="topleft"
+ left="0"
+ right="-1"
+ name="member_allowed_actions"
+ search_column="2"
+ tool_tip="For details of each allowed ability see the abilities tab"
+ top_pad="0">
+ <scroll_list.columns
+ label=""
+ name="icon"
+ width="2" />
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="action"
+ width="270" />
+ </scroll_list>
+ </panel>
+ <panel
+ height="550"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
+ layout="topleft"
+ follows="top|left|right"
+ left="0"
+ right="-1"
+ width="313"
+ mouse_opaque="false"
+ name="roles_footer"
+ top_delta="0"
+ top="209"
+ visible="false">
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ top="5"
+ name="static"
+ width="300">
+ Role Name
+ </text>
+ <line_editor
+ type="string"
+ height="20"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ max_length_bytes="20"
+ name="role_name"
+ top_pad="0"
+ width="300">
+ </line_editor>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ name="static3"
+ top_pad="5"
+ width="300">
+ Role Title
+ </text>
+ <line_editor
+ type="string"
+ height="20"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ max_length_bytes="20"
+ name="role_title"
+ top_pad="0"
+ width="300">
+ </line_editor>
+ <text
type="string"
height="16"
layout="topleft"
follows="left|top"
left="5"
name="static2"
- top_pad="1"
- width="300">
- Roles with this ability
- </text>
- <scroll_list
- height="172"
- layout="topleft"
- follows="left|top|right"
- left="5"
- right="-1"
- name="action_roles"
- top_pad="0"
- width="300" />
- <text
- type="string"
- height="16"
- layout="topleft"
- follows="left|top"
- left="5"
- name="static3"
top_pad="5"
- width="300">
- Members with this ability
- </text>
- <name_list
- height="122"
- follows="left|top|right"
- layout="topleft"
- left="5"
- right="-1"
- name="action_members"
- top_pad="0"
- width="300" />
- </panel>
+ width="200">
+ Description
+ </text>
+ <text_editor
+ type="string"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ max_length="295"
+ height="35"
+ name="role_description"
+ top_pad="0"
+ width="300"
+ word_wrap="true">
+ </text_editor>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ text_color="EmphasisColor"
+ name="static4"
+ top_pad="5"
+ width="300">
+ Assigned Members
+ </text>
+ <name_list
+ draw_stripes="true"
+ height="128"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ name="role_assigned_members"
+ top_pad="0"
+ width="300" />
+ <check_box
+ height="15"
+ label="Reveal members"
+ left="5"
+ layout="topleft"
+ name="role_visible_in_list"
+ tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group."
+ top_pad="4"
+ width="300" />
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ text_color="EmphasisColor"
+ name="static5"
+ top_pad="2"
+ width="300">
+ Allowed Abilities
+ </text>
+ <scroll_list
+ draw_stripes="true"
+ height="140"
+ layout="topleft"
+ left="0"
+ follows="left|top|right"
+ right="-1"
+ name="role_allowed_actions"
+ search_column="2"
+ tool_tip="For details of each allowed ability see the abilities tab"
+ top_pad="0"
+ width="300">
+ <scroll_list.columns
+ label=""
+ name="icon"
+ width="2" />
+ <scroll_list.columns
+ label=""
+ name="checkbox"
+ width="20" />
+ <scroll_list.columns
+ label=""
+ name="action"
+ width="270" />
+ </scroll_list>
+ </panel>
+ <panel
+ height="424"
+ background_visible="false"
+ bg_alpha_color="FloaterUnfocusBorderColor"
+ layout="topleft"
+ follows="top|left|right"
+ left="0"
+ right="-1"
+ width="313"
+ mouse_opaque="false"
+ name="actions_footer"
+ top_delta="0"
+ top="255"
+ visible="false">
+ <text_editor
+ bg_readonly_color="Transparent"
+ text_readonly_color="EmphasisColor"
+ font="SansSerifSmall"
+ type="string"
+ enabled="false"
+ halign="left"
+ layout="topleft"
+ follows="left|top|right"
+ left="0"
+ right="-1"
+ height="90"
+ max_length="512"
+ name="action_description"
+ top="0"
+ word_wrap="true">
+ This Ability is &apos;Eject Members from this Group&apos;. Only an Owner can eject another Owner.
+ </text_editor>
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ name="static2"
+ top_pad="1"
+ width="300">
+ Roles with this ability
+ </text>
+ <scroll_list
+ height="172"
+ layout="topleft"
+ follows="left|top|right"
+ left="5"
+ right="-1"
+ name="action_roles"
+ top_pad="0"
+ width="300" />
+ <text
+ type="string"
+ height="16"
+ layout="topleft"
+ follows="left|top"
+ left="5"
+ name="static3"
+ top_pad="5"
+ width="300">
+ Members with this ability
+ </text>
+ <name_list
+ height="122"
+ follows="left|top|right"
+ layout="topleft"
+ left="5"
+ right="-1"
+ name="action_members"
+ top_pad="0"
+ width="300" />
+ </panel>
</panel>
diff --git a/indra/newview/skins/default/xui/en/role_actions.xml b/indra/newview/skins/default/xui/en/role_actions.xml
index 0eeccbeac5..490217d3f6 100755
--- a/indra/newview/skins/default/xui/en/role_actions.xml
+++ b/indra/newview/skins/default/xui/en/role_actions.xml
@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<role_actions>
+ <action_set
+ description="These Abilities include powers to ban and un-ban residents from the group."
+ name="Group Ban">
+ <action description="Manage ban list"
+ longdescription="Allows the group member to ban / un-ban Residents from this group."
+ name="allow ban" value="51" />
+ </action_set>
<action_set
description="These Abilities include powers to add and remove group Members, and allow new Members to join without an invitation."
name="Membership">
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 7e79d297ef..3a34c0df5f 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3695,6 +3695,7 @@ Abuse Report</string>
<string name="LocalEstimateUSD">US$ [AMOUNT]</string>
<!-- Group Profile roles and powers -->
+ <string name="Group Ban">Group Ban</string>
<string name="Membership">Membership</string>
<string name="Roles">Roles</string>
<string name="Group Identity">Group Identity</string>