Group Bans!

Thankies Baker Linden~

Ported Ansariel's mAvatarNameCacheConnection change to mAvatarNameCacheConnections to llpanelgroupbulkimpl.h

Adds setGroupID in places, in case we ever want to add that.. but for now we don't really need/use it
Adds Refresh_Off icon from upstream.

Viewer Interesting changes:
Moves LLGroupChange out of stdenums.h into llgroupmgr.h
Moves roles_constants.h from llcommon into newview

This looks like it's better without space changes...
This commit is contained in:
Inusaito Sayori
2014-06-21 16:44:39 -04:00
parent b36bb8b5bb
commit d87a48ea06
30 changed files with 2143 additions and 154 deletions

View File

@@ -254,7 +254,6 @@ set(llcommon_HEADER_FILES
metapropertyt.h
reflective.h
reflectivet.h
roles_constants.h
stdenums.h
stdtypes.h
string_table.h

View File

@@ -118,16 +118,6 @@ enum EAddPosition
ADD_BOTTOM
};
enum LLGroupChange
{
GC_PROPERTIES,
GC_MEMBER_DATA,
GC_ROLE_DATA,
GC_ROLE_MEMBER_DATA,
GC_TITLES,
GC_ALL
};
//----------------------------------------------------------------------------
// DEPRECATED - create new, more specific files for shared enums/constants
//----------------------------------------------------------------------------

View File

@@ -936,6 +936,7 @@ P(fetchScriptLimitsRegionSummaryResponder);
P(fnPtrResponder);
P(floaterPermsResponder);
P2(gamingDataReceived, transfer_22s_connect_10s);
P(groupBanDataResponder);
P2(groupMemberDataResponder, transfer_300s);
P2(groupProposalBallotResponder, transfer_300s);
P(homeLocationResponder);

View File

@@ -216,6 +216,7 @@ set(viewer_SOURCE_FILES
llfloaterfriends.cpp
llfloatergesture.cpp
llfloatergodtools.cpp
llfloatergroupbulkban.cpp
llfloatergroupinfo.cpp
llfloatergroupinvite.cpp
llfloatergroups.cpp
@@ -368,6 +369,8 @@ set(viewer_SOURCE_FILES
llpanelface.cpp
llpanelgeneral.cpp
llpanelgroup.cpp
llpanelgroupbulk.cpp
llpanelgroupbulkban.cpp
llpanelgroupgeneral.cpp
llpanelgroupinvite.cpp
llpanelgrouplandmoney.cpp
@@ -739,6 +742,7 @@ set(viewer_HEADER_FILES
llfloaterfriends.h
llfloatergesture.h
llfloatergodtools.h
llfloatergroupbulkban.h
llfloatergroupinfo.h
llfloatergroupinvite.h
llfloatergroups.h
@@ -891,6 +895,9 @@ set(viewer_HEADER_FILES
llpanelface.h
llpanelgeneral.h
llpanelgroup.h
llpanelgroupbulk.h
llpanelgroupbulkban.h
llpanelgroupbulkimpl.h
llpanelgroupgeneral.h
llpanelgroupinvite.h
llpanelgrouplandmoney.h
@@ -1117,6 +1124,7 @@ set(viewer_HEADER_FILES
rlvinventory.h
rlvlocks.h
rlvui.h
roles_constants.h
scriptcounter.h
sgmemstat.h
sgversion.h

View File

@@ -0,0 +1,131 @@
/**
* @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"
const LLRect FGB_RECT(0, 320, 210, 0);
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->close();
}
//-----------------------------------------------------------------------------
// Implementation
//-----------------------------------------------------------------------------
LLFloaterGroupBulkBan::LLFloaterGroupBulkBan(const std::string& name,
const LLRect &rect,
const std::string& title,
const LLUUID& group_id)
: LLFloater(name, rect, title)
{
S32 floater_header_size = LLFLOATER_HEADER_SIZE;
LLRect contents(getRect());
contents.mTop -= floater_header_size;
mImpl = new impl(group_id);
mImpl->mBulkBanPanelp = new LLPanelGroupBulkBan(group_id);
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)
{
// 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("groupban",
FGB_RECT,
"Group Ban",
group_id);
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->open();
fgb->mImpl->mBulkBanPanelp->update();
}

View File

@@ -0,0 +1,51 @@
/**
* @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 std::string& name,
const LLRect& rect,
const std::string& title,
const LLUUID& group_id = LLUUID::null);
class impl;
impl* mImpl;
};
#endif // LL_LLFLOATERGROUPBULKBAN_H

View File

@@ -155,7 +155,7 @@ public:
void changed(LLGroupChange gc)
{
if (gc == GC_MEMBER_DATA && !mRequestProcessed)
if (gc == GC_PROPERTIES && !mRequestProcessed)
{
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupId);
if (!gdatap)
@@ -165,9 +165,6 @@ public:
else if (!gdatap->isMemberDataComplete())
{
llwarns << "LLGroupMgr::getInstance()->getGroupData()->isMemberDataComplete() was FALSE" << llendl;
}
else
{
processGroupData();
mRequestProcessed = true;
}

View File

@@ -232,11 +232,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();
@@ -425,7 +425,7 @@ void LLGroupMgrGroupData::removeMemberData()
delete mi->second;
}
mMembers.clear();
mMemberDataComplete = FALSE;
mMemberDataComplete = false;
mMemberVersion.generate();
}
@@ -447,8 +447,8 @@ void LLGroupMgrGroupData::removeRoleData()
}
mRoles.clear();
mReceivedRoleMemberPairs = 0;
mRoleDataComplete = FALSE;
mRoleMemberDataComplete = FALSE;
mRoleDataComplete = false;
mRoleMemberDataComplete = false;
}
void LLGroupMgrGroupData::removeRoleMemberData()
@@ -472,7 +472,7 @@ void LLGroupMgrGroupData::removeRoleMemberData()
}
mReceivedRoleMemberPairs = 0;
mRoleMemberDataComplete = FALSE;
mRoleMemberDataComplete = false;
}
LLGroupMgrGroupData::~LLGroupMgrGroupData()
@@ -825,6 +825,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
//
@@ -1039,12 +1053,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);
}
}
@@ -1114,7 +1128,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);
@@ -1189,12 +1203,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);
}
}
@@ -1306,7 +1320,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
}
}
group_datap->mRoleMemberDataComplete = TRUE;
group_datap->mRoleMemberDataComplete = true;
group_datap->mRoleMembersRequestID.setNull();
}
@@ -1934,8 +1948,149 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
class AIHTTPTimeoutPolicy;
extern AIHTTPTimeoutPolicy groupBanDataResponder_timeout;
extern AIHTTPTimeoutPolicy groupMemberDataResponder_timeout;
// Responder class for capability group management
class GroupBanDataResponder : public LLHTTPClient::ResponderWithResult
{
public:
GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh=false);
virtual ~GroupBanDataResponder() {}
virtual void result(const LLSD& mContent); //httpSuccess();
virtual void error(U32 mStatus, const std::string& mContent); //httpFailure();
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return groupBanDataResponder_timeout; }
/*virtual*/ char const* getName(void) const { return "GroupBanDataResponder"; }
private:
LLUUID mGroupID;
BOOL mForceRefresh;
};
GroupBanDataResponder::GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh) :
mGroupID(gropup_id),
mForceRefresh(force_refresh)
{}
//void GroupBanDataResponder::httpFailure()
void GroupBanDataResponder::error(U32 mStatus, const std::string& mContent)
{
LL_WARNS("GrpMgr") << "Error receiving group member data [status:"
<< mStatus << "]: " << mContent << LL_ENDL;
}
//void GroupBanDataResponder::httpSuccess()
void GroupBanDataResponder::result(const LLSD& mContent)
{
if (mContent.size())
{
if (mContent.has("ban_list"))
{
// group ban data received
LLGroupMgr::processGroupBanRequest(mContent);
mForceRefresh = false;
}
}
if (mForceRefresh)
{
// no ban data received, refreshing data successful operation
LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID);
}
}
void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type,
const LLUUID& group_id,
U32 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("GroupAPIv1");
if (cap_url.empty())
{
return;
}
cap_url += "?group_id=" + group_id.asString();
LLSD body = LLSD::emptyMap();
body["ban_action"] = (LLSD::Integer)(ban_action & ~BAN_UPDATE);
// Add our list of potential banned residents 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(group_id, ban_action & BAN_UPDATE);
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::ResponderWithResult
{
@@ -2104,12 +2259,12 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
if (group_datap->mTitles.size() < 1)
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);
}

View File

@@ -33,7 +33,21 @@
#include <string>
#include <map>
// Forward Declarations
class LLMessageSystem;
class LLGroupRoleData;
class LLGroupMgr;
enum LLGroupChange
{
GC_PROPERTIES,
GC_MEMBER_DATA,
GC_ROLE_DATA,
GC_ROLE_MEMBER_DATA,
GC_TITLES,
GC_BANLIST,
GC_ALL
};
class LLGroupMgrObserver
{
@@ -54,8 +68,6 @@ public:
virtual void changed(const LLUUID& group_id, LLGroupChange gc) = 0;
};
class LLGroupRoleData;
class LLGroupMemberData
{
friend class LLGroupMgrGroupData;
@@ -190,6 +202,17 @@ struct lluuid_pair_less
}
};
struct LLGroupBanData
{
LLGroupBanData() : mBanDate() {}
~LLGroupBanData() {}
LLDate mBanDate;
// TODO: std::string ban_reason;
};
struct LLGroupTitle
{
std::string mTitle;
@@ -197,8 +220,6 @@ struct LLGroupTitle
BOOL mSelected;
};
class LLGroupMgr;
class LLGroupMgrGroupData
{
friend class LLGroupMgr;
@@ -228,26 +249,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& ban_i, const LLGroupBanData& ban_data = LLGroupBanData());
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;
@@ -277,12 +308,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
@@ -309,6 +340,23 @@ 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,
BAN_UPDATE = 4
};
public:
LLGroupMgr();
~LLGroupMgr();
@@ -343,6 +391,13 @@ public:
static void sendGroupMemberEjects(const LLUUID& group_id,
uuid_vec_t& member_ids);
static void sendGroupBanRequest(EBanRequestType request_type,
const LLUUID& group_id,
U32 ban_action = BAN_NO_ACTION,
const uuid_vec_t ban_list = uuid_vec_t());
static void processGroupBanRequest(const LLSD& content);
void sendCapGroupMembersRequest(const LLUUID& group_id);
static void processCapGroupMembersRequest(const LLSD& content);
@@ -387,4 +442,3 @@ private:
#endif

View File

@@ -53,7 +53,8 @@ LLNameListCtrl::LLNameListCtrl(const std::string& name, const LLRect& rect, BOOL
: LLScrollListCtrl(name, rect, NULL, allow_multiple_selection, draw_border,draw_heading),
mNameColumnIndex(name_column_index),
mAllowCallingCardDrop(false),
mNameSystem(name_system)
mNameSystem(name_system),
mPendingLookupsRemaining(0)
{
setToolTip(tooltip);
}
@@ -203,6 +204,17 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
mAvatarNameCacheConnections.erase(it);
}
mAvatarNameCacheConnections[id] = LLAvatarNameCache::get(id,boost::bind(&LLNameListCtrl::onAvatarNameCache,this, _1, _2, suffix, item->getHandle()));
if (mPendingLookupsRemaining <= 0)
{
// BAKER TODO:
// We might get into a state where mPendingLookupsRemainig might
// go negative. So just reset it right now and figure out if it's
// possible later :)
mPendingLookupsRemaining = 0;
mNameListCompleteSignal(false);
}
mPendingLookupsRemaining++;
}
break;
}
@@ -254,6 +266,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id)
{
selectNthItem(idx); // not sure whether this is needed, taken from previous implementation
deleteSingleItem(idx);
mPendingLookupsRemaining--;
}
}
@@ -292,6 +306,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();
}

View File

@@ -67,6 +67,8 @@ class LLNameListCtrl
: public LLScrollListCtrl, public LLInstanceTracker<LLNameListCtrl>
{
public:
typedef boost::signals2::signal<void(bool)> namelist_complete_signal_t;
typedef enum e_name_type
{
INDIVIDUAL,
@@ -155,6 +157,16 @@ private:
const LLCachedControl<S32> mNameSystem;
typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
S32 mPendingLookupsRemaining;
namelist_complete_signal_t mNameListCompleteSignal;
public:
boost::signals2::connection setOnNameListCompleteCallback(boost::function<void(bool)> onNameListCompleteCallback)
{
return mNameListCompleteSignal.connect(onNameListCompleteCallback);
}
};

View File

@@ -157,6 +157,7 @@ LLPanelGroup::LLPanelGroup(const LLUUID& group_id)
mFactoryMap["members_sub_tab"] = LLCallbackMap(LLPanelGroupMembersSubTab::createTab, &mID);
mFactoryMap["roles_sub_tab"] = LLCallbackMap(LLPanelGroupRolesSubTab::createTab, &mID);
mFactoryMap["actions_sub_tab"] = LLCallbackMap(LLPanelGroupActionsSubTab::createTab, &mID);
mFactoryMap["banlist_sub_tab"] = LLCallbackMap(LLPanelGroupBanListSubTab::createTab, &mID);
LLGroupMgr::getInstance()->addObserver(this);

View File

@@ -168,12 +168,16 @@ public:
virtual BOOL isVisibleByAgent(LLAgent* agentp);
virtual void setGroupID(const LLUUID& id) { mGroupID = id; }
void setAllowEdit(BOOL v) { mAllowEdit = v; }
void addObserver(LLPanelGroupTabObserver *obs);
void removeObserver(LLPanelGroupTabObserver *obs);
void notifyObservers();
const LLUUID& getGroupID() const { return mGroupID; }
protected:
LLUUID mGroupID;
LLTabContainer* mTabContainer;

View File

@@ -0,0 +1,424 @@
/**
* @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),
mRoleNames(NULL),
mOwnerWarning(),
mAlreadyInGroup(),
mConfirmedOwnerInvite(false),
mListFullNotificationSent(false)
{}
LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl()
{
for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
{
if (it->second.connected())
{
it->second.disconnect();
}
}
mAvatarNameCacheConnections.clear();
}
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
/* Singu Note: We're different, we don't do this..
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);
boost::bind(&LLPanelGroupBulkImpl::callbackAddUsers, panelp->mImplementation, _1), TRUE);
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)
{
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);
}
else
{
if (mAvatarNameCacheConnections[agent_ids[i]].connected())
{
mAvatarNameCacheConnections[agent_ids[i]].disconnect();
}
// *TODO : Add a callback per avatar name being fetched.
mAvatarNameCacheConnections[agent_ids[i]] = LLAvatarNameCache::get(agent_ids[i],boost::bind(&LLPanelGroupBulkImpl::onAvatarNameCache, this, _1, _2));
}
}
}
void LLPanelGroupBulkImpl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
{
if (mAvatarNameCacheConnections[agent_id].connected())
{
mAvatarNameCacheConnections[agent_id].disconnect();
}
std::vector<std::string> names;
uuid_vec_t agent_ids;
agent_ids.push_back(agent_id);
std::string name;
LLAvatarNameCache::getPNSName(av_name, name);
names.push_back(name);
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(mListFullNotificationSent)
{
return;
}
if( !mListFullNotificationSent &&
(names.size() + mInviteeIDs.size() > MAX_GROUP_INVITES))
{
mListFullNotificationSent = true;
// 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 && gdatap->isGroupPropertiesDataComplete())
{
mPendingGroupPropertiesUpdate = false;
}
else
{
if(!mPendingGroupPropertiesUpdate)
{
mPendingGroupPropertiesUpdate = true;
LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID);
}
}
if(gdatap && gdatap->isRoleDataComplete())
{
mPendingRoleDataUpdate = false;
}
else
{
if(!mPendingRoleDataUpdate)
{
mPendingRoleDataUpdate = true;
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
}
}
if(gdatap && 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);
std::string name;
LLAvatarNameCache::getPNSName(av_name, name);
names.push_back(name);
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
{
std::string name;
LLAvatarNameCache::getPNSName(av_name, name);
names.push_back(name);
}
}
}
}
mImplementation->mListFullNotificationSent = false;
mImplementation->addUsers(names, agent_ids);
}

View File

@@ -0,0 +1,73 @@
/**
* @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);
/*virtual*/ ~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

View File

@@ -0,0 +1,160 @@
/**
* @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 "llslurl.h"
#include "llspinctrl.h"
#include "lltextbox.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
#include <boost/foreach.hpp>
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");
LLUICtrlFactory::getInstance()->buildPanel(this, "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->setCommitCallback(boost::bind(&LLPanelGroupBulkBan::submit, 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;
}
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;
}
LLGroupMgrGroupData * group_datap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
if (group_datap)
{
BOOST_FOREACH(const LLGroupMgrGroupData::ban_list_t::value_type& group_ban_pair, group_datap->mBanList)
{
const LLUUID& group_ban_agent_id = group_ban_pair.first;
if (std::find(banned_agent_list.begin(), banned_agent_list.end(), group_ban_agent_id) != banned_agent_list.end())
{
// Fail!
std::string av_name;
LLAvatarNameCache::getPNSName(group_ban_agent_id, av_name);
LLStringUtil::format_map_t string_args;
string_args["[RESIDENT]"] = av_name;
LLSD msg;
msg["MESSAGE"] = getString("already_banned", string_args);
LLNotificationsUtil::add("GenericAlert", msg);
(*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
return;
}
}
}
LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mImplementation->mGroupID, LLGroupMgr::BAN_CREATE | LLGroupMgr::BAN_UPDATE, banned_agent_list);
LLGroupMgr::getInstance()->sendGroupMemberEjects(mImplementation->mGroupID, banned_agent_list);
//then close
(*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
}

View File

@@ -0,0 +1,46 @@
/**
* @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();
virtual void submit();
};
#endif // LL_LLPANELGROUPBULKBAN_H

View File

@@ -0,0 +1,96 @@
/**
* @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);
void callbackAddUsers(const uuid_vec_t& agent_ids);
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
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;
typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
// 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;
bool mListFullNotificationSent;
};
#endif // LL_LLPANELGROUPBULKIMPL_H

View File

@@ -258,7 +258,7 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap)
//else if they have the limited add to roles power
//we add every role the user is in
//else we just add to everyone
bool is_owner = member_data->isInRole(gdatap->mOwnerRole);
bool is_owner = member_data->isOwner();
bool can_assign_any = gAgent.hasPowerInGroup(mGroupID,
GP_ROLE_ASSIGN_MEMBER);
bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID,
@@ -540,7 +540,7 @@ void LLPanelGroupInvite::updateLists()
{
waiting = true;
}
if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete())
if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete())
{
if ( mImplementation->mRoleNames )
{
@@ -568,6 +568,7 @@ void LLPanelGroupInvite::updateLists()
{
LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID);
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID);
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mImplementation->mGroupID);
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID);
}
mPendingUpdate = TRUE;
@@ -615,7 +616,7 @@ BOOL LLPanelGroupInvite::postBuild()
}
mImplementation->mOKButton =
getChild<LLButton>("ok_button", recurse);
getChild<LLButton>("invite_button", recurse);
if ( mImplementation->mOKButton )
{
mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation);

View File

@@ -1,4 +1,4 @@
/**
/**
* @file llpanelgrouproles.cpp
* @brief Panel for roles information about a particular group.
*
@@ -38,6 +38,7 @@
#include "llavatarnamecache.h"
#include "llbutton.h"
#include "llfiltereditor.h"
#include "llfloatergroupbulkban.h"
#include "llfloatergroupinvite.h"
#include "lliconctrl.h"
#include "lllineeditor.h"
@@ -109,6 +110,9 @@ bool agentCanAddToRole(const LLUUID& group_id,
return false;
}
// LLPanelGroupRoles /////////////////////////////////////////////////////
// static
void* LLPanelGroupRoles::createTab(void* data)
{
@@ -308,7 +312,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.
@@ -374,39 +377,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()->sendGroupRoleDataRequest(mGroupID);
}
// Check role-member mapping data.
if (!gdatap || !gdatap->isRoleMemberDataComplete() )
{
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
}
// Need this to get base group member powers
if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
{
LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
}
mFirstUse = FALSE;
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
}
if (!gdatap || !gdatap->isRoleDataComplete() )
{
// Mildly hackish - clear all pending changes
cancel();
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
}
// Check role-member mapping data.
if (!gdatap || !gdatap->isRoleMemberDataComplete() )
{
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
}
// 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();
}
@@ -441,14 +438,38 @@ void LLPanelGroupRoles::tabChanged()
notifyObservers();
}
////////////////////////////
// LLPanelGroupSubTab
////////////////////////////
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(1);
group_roles_tab->mFirstOpen = TRUE;
activate();
}
// LLPanelGroupSubTab ////////////////////////////////////////////////////
LLPanelGroupSubTab::LLPanelGroupSubTab(const std::string& name, const LLUUID& group_id)
: LLPanelGroupTab(name, group_id),
mHeader(NULL),
mFooter(NULL),
mActivated(false),
mHasGroupBanPower(false),
mSearchEditor(NULL)
{
}
@@ -493,6 +514,17 @@ BOOL LLPanelGroupSubTab::postBuild()
return LLPanelGroupTab::postBuild();
}
void LLPanelGroupSubTab::setGroupID(const LLUUID& id)
{
LLPanelGroupTab::setGroupID(id);
if(mSearchEditor)
{
mSearchEditor->clear();
setSearchFilter("");
}
mActivated = false;
}
void LLPanelGroupSubTab::setSearchFilter(const std::string& filter)
{
@@ -559,9 +591,10 @@ void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl,
return;
}
mHasGroupBanPower = false;
std::vector<LLRoleActionSet*>::iterator ras_it = LLGroupMgr::getInstance()->mRoleActionSets.begin();
std::vector<LLRoleActionSet*>::iterator ras_end = LLGroupMgr::getInstance()->mRoleActionSets.end();
for ( ; ras_it != ras_end; ++ras_it)
{
buildActionCategory(ctrl,
@@ -685,6 +718,33 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl,
row["columns"][column_index]["value"] = (*ra_it)->mDescription;
row["columns"][column_index]["font"] = "SANSSERIF_SMALL";
if (mHasGroupBanPower)
{
// The ban ability is being set. Prevent these abilities from being manipulated
if ((*ra_it)->mPowerBit == GP_MEMBER_EJECT)
{
row["enabled"] = false;
}
else if ((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER)
{
row["enabled"] = false;
}
}
else
{
/* Singu Note: enabled should not be set on here if it was turned off above for another reason... right? Oh well, we'll find out.
*/
// The ban ability is not set. Allow these abilities to be manipulated
if ((*ra_it)->mPowerBit == GP_MEMBER_EJECT)
{
row["enabled"] = true;
}
else if ((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER)
{
row["enabled"] = true;
}
}
LLScrollListItem* item = ctrl->addElement(row, ADD_BOTTOM, (*ra_it));
if (-1 != check_box_index)
@@ -720,6 +780,15 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl,
check->setTentative(TRUE);
}
}
// Regardless of whether or not this ability is allowed by all or some, we want to prevent
// the group managers from accidentally disabling either of the two additional abilities
// tied with GP_GROUP_BAN_ACCESS
if ( (allowed_by_all & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS ||
(allowed_by_some & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS)
{
mHasGroupBanPower = true;
}
}
}
@@ -739,10 +808,7 @@ void LLPanelGroupSubTab::setFooterEnabled(BOOL enable)
}
}
////////////////////////////
// LLPanelGroupMembersSubTab
////////////////////////////
// LLPanelGroupMembersSubTab /////////////////////////////////////////////
// static
void* LLPanelGroupMembersSubTab::createTab(void* data)
{
@@ -812,9 +878,27 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
mEjectBtn->setEnabled(FALSE);
}
mBanBtn = parent->getChild<LLButton>("member_ban", recurse);
if (mBanBtn)
{
mBanBtn->setClickedCallback(boost::bind(&LLPanelGroupMembersSubTab::handleBanMember,this));
mBanBtn->setEnabled(FALSE);
}
return TRUE;
}
void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id)
{
//clear members list
if(mMembersList) mMembersList->deleteAllItems();
if(mAssignedRolesList) mAssignedRolesList->deleteAllItems();
if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
LLPanelGroupSubTab::setGroupID(id);
}
// static
void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data)
@@ -844,7 +928,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 = GP_ALL_POWERS; //0xffffffffffffLL;
U64 allowed_by_some = 0;
std::vector<LLScrollListItem*>::iterator itor;
@@ -881,8 +965,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)
@@ -929,6 +1013,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
{
// Can't remove other owners.
cb_enable = FALSE;
can_ban_members = FALSE;
break;
}
}
@@ -1012,7 +1097,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)
{
@@ -1025,10 +1113,41 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
{
can_eject_members = TRUE;
can_ban_members = TRUE;
}
}
}
// ... or we can eject them because we have all the requisite powers...
if ( gAgent.hasPowerInGroup(mGroupID, GP_ROLE_REMOVE_MEMBER) &&
!member_is_owner)
{
if (gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT))
{
can_eject_members = TRUE;
}
if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
{
can_ban_members = TRUE;
}
}
uuid_vec_t::const_iterator member_iter = selected_members.begin();
uuid_vec_t::const_iterator member_end = selected_members.end();
for ( ; member_iter != member_end; ++member_iter)
{
// Don't count the agent.
if ((*member_iter) == gAgent.getID())
{
can_eject_members = FALSE;
can_ban_members = FALSE;
}
}
mBanBtn->setEnabled(can_ban_members);
mEjectBtn->setEnabled(can_eject_members);
}
@@ -1098,7 +1217,9 @@ void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, c
for (uuid_vec_t::const_iterator i = selected_members.begin(); i != selected_members.end(); ++i)
{
LLSD args;
args["AVATAR_NAME"] = LLSLURL("agent", *i, "displayname").getSLURLString();
std::string av_name;
LLAvatarNameCache::getPNSName(*i, av_name);
args["AVATAR_NAME"] = av_name;
args["GROUP_NAME"] = group_data->mName;
LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
@@ -1114,12 +1235,11 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
//add that the user is requesting to change the roles for selected
//members
U64 powers_all_have = 0xffffffffffffLL;
U64 powers_all_have = GP_ALL_POWERS;
U64 powers_some_have = 0;
BOOL is_owner_role = ( gdatap->mOwnerRole == role_id );
LLUUID member_id;
std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
if (selection.empty())
@@ -1130,7 +1250,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
@@ -1196,7 +1315,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
FALSE);
}
// static
void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data)
{
@@ -1567,15 +1685,15 @@ void LLPanelGroupMembersSubTab::addMemberToList(LLGroupMemberData* data)
LLNameListCtrl::NameItem item_params;
item_params.value = data->getID();
item_params.columns.add().column("name").font/*.name*/("SANSSERIF_SMALL")/*.style("NORMAL")*/;
item_params.columns.add().column("name").font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL");
item_params.columns.add().column("donated").value(donated.getString())
.font/*.name*/("SANSSERIF_SMALL")/*.style("NORMAL")*/;
.font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL");
static const LLCachedControl<std::string> format(gSavedSettings, "ShortDateFormat");
item_params.columns.add().column("online").value(data->getOnlineStatus())
.format(format).type(is_online_status_string(data->getOnlineStatus()) ? "text" : "date")
.font/*.name*/("SANSSERIF_SMALL")/*.style("NORMAL")*/;
.font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL");
mMembersList->addNameItemRow(item_params);
mHasMatch = TRUE;
@@ -1642,7 +1760,6 @@ void LLPanelGroupMembersSubTab::updateMembers()
mMembersList->deleteAllItems();
}
LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
LLTimer update_time;
@@ -1700,12 +1817,35 @@ void LLPanelGroupMembersSubTab::updateMembers()
handleMemberSelect();
}
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;
}
// Singu Note: We have this function, so there's less code here.
uuid_vec_t ban_ids = mMembersList->getSelectedIDs();
if (ban_ids.empty())
{
return;
}
uuid_vec_t::iterator itor;
for(itor = ban_ids.begin(); itor != ban_ids.end(); ++itor)
{
LLGroupBanData ban_data;
gdatap->createBanEntry(*itor, ban_data);
}
LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_CREATE, ban_ids);
handleEjectMembers();
}
////////////////////////////
// LLPanelGroupRolesSubTab
////////////////////////////
// LLPanelGroupRolesSubTab ///////////////////////////////////////////////
// static
void* LLPanelGroupRolesSubTab::createTab(void* data)
{
@@ -1724,7 +1864,7 @@ LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab(const std::string& name, const
mMemberVisibleCheck(NULL),
mDeleteRoleButton(NULL),
mCreateRoleButton(NULL),
mFirstOpen(TRUE),
mHasRoleChange(FALSE)
{
}
@@ -1824,6 +1964,7 @@ void LLPanelGroupRolesSubTab::deactivate()
lldebugs << "LLPanelGroupRolesSubTab::deactivate()" << llendl;
LLPanelGroupSubTab::deactivate();
mFirstOpen = FALSE;
}
bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg)
@@ -1831,6 +1972,12 @@ bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg)
lldebugs << "LLPanelGroupRolesSubTab::needsApply()" << llendl;
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
if (!gdatap)
{
llwarns << "Unable to get group data for group " << mGroupID << llendl;
return false;
}
return (mHasRoleChange // Text changed in current role
|| (gdatap && gdatap->pendingRoleChanges())); // Pending role changes in the group
@@ -1841,7 +1988,7 @@ bool LLPanelGroupRolesSubTab::apply(std::string& mesg)
lldebugs << "LLPanelGroupRolesSubTab::apply()" << llendl;
saveRoleChanges(true);
mFirstOpen = FALSE;
LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID);
notifyObservers();
@@ -1978,14 +2125,17 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
}
}
if (!gdatap || !gdatap->isMemberDataComplete())
if (!mFirstOpen)
{
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
}
if (!gdatap || !gdatap->isRoleMemberDataComplete())
{
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
if (!gdatap || !gdatap->isMemberDataComplete())
{
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
}
if (!gdatap || !gdatap->isRoleMemberDataComplete())
{
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
}
}
if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc)
@@ -2001,6 +2151,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();
}
@@ -2180,41 +2333,116 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force)
LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata();
U64 power = rap->mPowerBit;
if (check->get())
bool isEnablingAbility = check->get();
LLRoleData rd;
LLSD args;
if (isEnablingAbility &&
!force &&
((GP_ROLE_ASSIGN_MEMBER == power) || (GP_ROLE_CHANGE_ACTIONS == power) ))
{
if (!force && ( (GP_ROLE_ASSIGN_MEMBER == power)
|| (GP_ROLE_CHANGE_ACTIONS == power) ))
// Uncheck the item, for now. It will be
// checked if they click 'Yes', below.
check->set(FALSE);
LLRoleData rd;
LLSD args;
if ( gdatap->getRoleData(role_id, rd) )
{
// Uncheck the item, for now. It will be
// checked if they click 'Yes', below.
check->set(FALSE);
LLRoleData rd;
LLSD args;
if ( gdatap->getRoleData(role_id, rd) )
args["ACTION_NAME"] = rap->mDescription;
args["ROLE_NAME"] = rd.mRoleName;
mHasModal = TRUE;
std::string warning = "AssignDangerousActionWarning";
if (GP_ROLE_CHANGE_ACTIONS == power)
{
args["ACTION_NAME"] = rap->mDescription;
args["ROLE_NAME"] = rd.mRoleName;
mHasModal = TRUE;
std::string warning = "AssignDangerousActionWarning";
if (GP_ROLE_CHANGE_ACTIONS == power)
{
warning = "AssignDangerousAbilityWarning";
}
LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check));
}
else
{
llwarns << "Unable to look up role information for role id: "
<< role_id << llendl;
warning = "AssignDangerousAbilityWarning";
}
LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check));
}
else
{
gdatap->addRolePower(role_id,power);
llwarns << "Unable to look up role information for role id: "
<< role_id << llendl;
}
}
if (GP_GROUP_BAN_ACCESS == power)
{
std::string warning = isEnablingAbility ? "AssignBanAbilityWarning" : "RemoveBanAbilityWarning";
//////////////////////////////////////////////////////////////////////////
// Get role data for both GP_ROLE_REMOVE_MEMBER and GP_MEMBER_EJECT
// Add description and role name to LLSD
// Pop up dialog saying "Yo, you also granted these other abilities when you did this!"
if (gdatap->getRoleData(role_id, rd))
{
args["ACTION_NAME"] = rap->mDescription;
args["ROLE_NAME"] = rd.mRoleName;
mHasModal = TRUE;
std::vector<LLScrollListItem*> all_data = mAllowedActionsList->getAllData();
std::vector<LLScrollListItem*>::iterator ad_it = all_data.begin();
std::vector<LLScrollListItem*>::iterator ad_end = all_data.end();
LLRoleAction* adp;
for( ; ad_it != ad_end; ++ad_it)
{
adp = (LLRoleAction*)(*ad_it)->getUserdata();
if (adp->mPowerBit == GP_MEMBER_EJECT)
{
args["ACTION_NAME_2"] = adp->mDescription;
}
else if (adp->mPowerBit == GP_ROLE_REMOVE_MEMBER)
{
args["ACTION_NAME_3"] = adp->mDescription;
}
}
LLNotificationsUtil::add(warning, args);
}
else
{
llwarns << "Unable to look up role information for role id: "
<< role_id << llendl;
}
//////////////////////////////////////////////////////////////////////////
LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.find(role_id);
U64 current_role_powers = GP_NO_POWERS;
if (rit != gdatap->mRoles.end())
{
current_role_powers = ((*rit).second->getRoleData().mRolePowers);
}
if (isEnablingAbility)
{
power |= (GP_ROLE_REMOVE_MEMBER | GP_MEMBER_EJECT);
current_role_powers |= power;
}
else
{
current_role_powers &= ~GP_GROUP_BAN_ACCESS;
}
mAllowedActionsList->deleteAllItems();
buildActionsList( mAllowedActionsList,
current_role_powers,
current_role_powers,
boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false),
TRUE,
FALSE,
FALSE);
}
//////////////////////////////////////////////////////////////////////////
// Adding non-specific ability to role
//////////////////////////////////////////////////////////////////////////
if (isEnablingAbility)
{
gdatap->addRolePower(role_id, power);
}
else
{
gdatap->removeRolePower(role_id,power);
@@ -2222,6 +2450,7 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force)
mHasRoleChange = TRUE;
notifyObservers();
}
bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check)
@@ -2241,7 +2470,6 @@ bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD&
return false;
}
// static
void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_data)
{
@@ -2419,10 +2647,26 @@ void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role)
mHasRoleChange = FALSE;
}
}
////////////////////////////
// LLPanelGroupActionsSubTab
////////////////////////////
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
void* LLPanelGroupActionsSubTab::createTab(void* data)
{
@@ -2600,3 +2844,223 @@ void LLPanelGroupActionsSubTab::handleActionSelect()
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
}
}
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);
}
// LLPanelGroupBanListSubTab /////////////////////////////////////////////
// static
void* LLPanelGroupBanListSubTab::createTab(void* data)
{
LLUUID* group_id = static_cast<LLUUID*>(data);
return new LLPanelGroupBanListSubTab("panel group ban list sub tab", *group_id);
}
LLPanelGroupBanListSubTab::LLPanelGroupBanListSubTab(const std::string& name, const LLUUID& group_id)
: LLPanelGroupSubTab(name, group_id),
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;
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 (!mBanList || !mCreateBanButton || !mDeleteBanButton || !mRefreshBanListButton)
return FALSE;
mBanList->setCommitOnSelectionChange(TRUE);
mBanList->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleBanEntrySelect, this));
mCreateBanButton->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleCreateBanEntry, this));
mCreateBanButton->setEnabled(FALSE);
mDeleteBanButton->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleDeleteBanEntry, this));
mDeleteBanButton->setEnabled(FALSE);
mRefreshBanListButton->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleRefreshBanList, this));
mRefreshBanListButton->setEnabled(FALSE);
mBanList->setOnNameListCompleteCallback(boost::bind(&LLPanelGroupBanListSubTab::onBanListCompleted, this, _1));
populateBanList();
//setFooterEnabled(FALSE); // Singu Note: This probably serves no purpose upstream, but for us, we need the footer enabled because we use it to make use of this entire panel.
return TRUE;
}
void LLPanelGroupBanListSubTab::activate()
{
LLPanelGroupSubTab::activate();
mBanList->deselectAllItems();
mDeleteBanButton->setEnabled(FALSE);
mCreateBanButton->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS));
// 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); // Singu Note: This probably serves no purpose upstream, but for us, we need the footer enabled because we use it to make use of this entire panel.
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.
//if(
// populateBanList();
}
void LLPanelGroupBanListSubTab::handleBanEntrySelect()
{
if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS))
{
mDeleteBanButton->setEnabled(!!mBanList->getFirstSelected()); // Singu Note: Avoid empty selection.
}
}
void LLPanelGroupBanListSubTab::handleCreateBanEntry()
{
LLFloaterGroupBulkBan::showForGroup(mGroupID);
//populateBanList();
}
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;
}
// Singu Note: We have this function, so there's less code here.
uuid_vec_t ban_ids = mBanList->getSelectedIDs();
if (ban_ids.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;
uuid_vec_t::iterator itor;
for(itor = ban_ids.begin(); itor != ban_ids.end(); ++itor)
{
LLUUID ban_id = (*itor);
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::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").font_style("NORMAL");
// Singu Note: We have special date columns, so our code is unique here
ban_entry.columns.add().column("ban_date").value(bd.mBanDate).format("%Y/%m%d").font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL");
mBanList->addNameItemRow(ban_entry);
}
mRefreshBanListButton->setEnabled(TRUE);
}
void LLPanelGroupBanListSubTab::setGroupID(const LLUUID& id)
{
if (mBanList)
mBanList->deleteAllItems();
//setFooterEnabled(FALSE);
LLPanelGroupSubTab::setGroupID(id);
}

View File

@@ -46,11 +46,9 @@ class LLScrollListItem;
class LLTextEditor;
class LLGroupMemberData;
// 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 LLPanelGroupTabObserver
{
@@ -89,6 +87,8 @@ public:
virtual void cancel();
virtual void update(LLGroupChange gc);
virtual void setGroupID(const LLUUID& id);
// PanelGroupTab observer trigger
virtual void tabChanged();
@@ -103,6 +103,7 @@ protected:
std::string mWantApplyMesg;
};
class LLPanelGroupSubTab : public LLPanelGroupTab
{
public:
@@ -123,6 +124,8 @@ public:
bool matchesActionSearchFilter(std::string action);
void setFooterEnabled(BOOL enable);
virtual void setGroupID(const LLUUID& id);
protected:
void buildActionsList(LLScrollListCtrl* ctrl,
U64 allowed_by_some,
@@ -152,9 +155,13 @@ protected:
bool mActivated;
bool mHasGroupBanPower; // Used to communicate between action sets due to the dependency between
// GP_GROUP_BAN_ACCESS and GP_EJECT_MEMBER and GP_ROLE_REMOVE_MEMBER
void setOthersVisible(BOOL b);
};
class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab
{
public:
@@ -182,6 +189,9 @@ public:
void handleRoleCheck(const LLUUID& role_id,
LLRoleMemberChangeType type);
void handleBanMember();
void applyMemberChanges();
bool addOwnerCB(const LLSD& notification, const LLSD& response);
@@ -195,6 +205,8 @@ public:
virtual void draw();
virtual void setGroupID(const LLUUID& id);
void addMemberToList(LLGroupMemberData* data);
void onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name, const LLUUID& av_id);
@@ -213,6 +225,7 @@ protected:
LLScrollListCtrl* mAssignedRolesList;
LLScrollListCtrl* mAllowedActionsList;
LLButton* mEjectBtn;
LLButton* mBanBtn;
BOOL mChanged;
BOOL mPendingMemberUpdate;
@@ -226,6 +239,7 @@ protected:
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab
{
public:
@@ -266,6 +280,11 @@ public:
void handleDeleteRole();
void saveRoleChanges(bool select_saved_role);
virtual void setGroupID(const LLUUID& id);
BOOL mFirstOpen;
protected:
void handleActionCheck(LLUICtrl* ctrl, bool force);
LLSD createRoleItem(const LLUUID& role_id, std::string name, std::string title, S32 members);
@@ -287,6 +306,7 @@ protected:
std::string mRemoveEveryoneTxt;
};
class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab
{
public:
@@ -304,6 +324,8 @@ public:
virtual void update(LLGroupChange gc);
void handleActionSelect();
virtual void setGroupID(const LLUUID& id);
protected:
LLScrollListCtrl* mActionList;
LLScrollListCtrl* mActionRoles;
@@ -313,4 +335,42 @@ protected:
};
class LLPanelGroupBanListSubTab : public LLPanelGroupSubTab
{
public:
LLPanelGroupBanListSubTab(const std::string& name, const LLUUID& group_id);
virtual ~LLPanelGroupBanListSubTab() {}
virtual BOOL postBuildSubTab(LLView* root);
static void* createTab(void* data);
virtual void activate();
virtual void update(LLGroupChange gc);
virtual void draw();
void handleBanEntrySelect();
void handleCreateBanEntry();
void handleDeleteBanEntry();
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

View File

@@ -1719,6 +1719,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("GetObjectCost");
capabilityNames.append("GetObjectPhysicsData");
capabilityNames.append("GetTexture");
capabilityNames.append("GroupAPIv1");
capabilityNames.append("GroupMemberData");
capabilityNames.append("GroupProposalBallot");
capabilityNames.append("HomeLocation");

View File

@@ -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)
@@ -146,6 +146,9 @@ 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
| GP_NOTICES_RECEIVE

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

View File

@@ -415,4 +415,5 @@
<texture name="Inv_WindLight.png" preload="true"/>
<texture name="Inv_WaterLight.png" preload="true"/>
<texture name="Refresh_Off" file_name="Refresh_Off.png" preload="true" />
</textures>

View File

@@ -612,6 +612,34 @@ Add this Ability to &apos;[ROLE_NAME]&apos;?
yestext="Yes"/>
</notification>
<notification
icon="alertmodal.tga"
name="AssignBanAbilityWarning"
type="alertmodal">
You are about to add the Ability &apos;[ACTION_NAME]&apos; to the Role &apos;[ROLE_NAME]&apos;.
*WARNING*
Any Member in a Role with this Ability will also be granted the Abilities &apos;[ACTION_NAME_2]&apos; and &apos;[ACTION_NAME_3]&apos;
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="RemoveBanAbilityWarning"
type="alertmodal">
You are removing the Ability &apos;[ACTION_NAME]&apos; to the Role &apos;[ROLE_NAME]&apos;.
*WARNING*
Removing this ability will NOT remove the Abilities &apos;[ACTION_NAME_2]&apos; and &apos;[ACTION_NAME_3]&apos;.
If you no longer wish to have these abilities granted to this role, disable them immediately!
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="AttachmentDrop"
@@ -3333,6 +3361,28 @@ Leave Group?
yestext="OK"/>
</notification>
<notification
icon="alert.tga"
name="GroupDepartError"
type="alert">
Unable to leave group: [reason].
<tag>reason</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alert.tga"
name="GroupDepart"
type="alert">
You have left the group [group_name].
<tag>group_name</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alert.tga"
name="ConfirmKick"

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
height="270"
label="Ban Residents"
layout="topleft"
left="0"
name="bulk_ban_panel"
mouse_opaque="false"
bottom="0"
width="210">
<panel.string
name="loading">
(loading...)
</panel.string>
<panel.string
name="ban_selection_too_large">
Group bans not sent: too many Residents selected. Group bans are limited to 100 per request.
</panel.string>
<panel.string
name="already_banned">
Group Invitations not sent: resident '[RESIDENT]' already banned.
</panel.string>
<text
type="string"
length="1"
height="54"
bottom="-28"
layout="topleft"
left="7"
name="help_text"
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"
bottom_delta="-10"
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"
menu_num="0"
bottom_delta="-178"
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"
bottom_delta="-24"
width="200" />
<button
height="20"
label="Ban Residents"
layout="topleft"
left="4"
name="ban_button"
bottom_delta="-26"
width="135" />
<button
height="20"
label="Cancel"
layout="topleft"
left_delta="137"
name="cancel_button"
bottom_delta="0"
width="65" />
<string
name="GroupBulkBan">
Group Ban
</string>
</panel>

View File

@@ -26,7 +26,7 @@ Resident Chooser&apos; to start.
tool_tip="Choose from the list of Roles you are allowed to assign members to."
width="196" />
<button bottom="4" font="SansSerifSmall" halign="center" height="20"
label="Send Invitations" left="4" name="ok_button" width="130" />
label="Send Invitations" left="4" name="invite_button" width="130" />
<button bottom_delta="0" font="SansSerifSmall" halign="center" height="20"
label="Cancel" left_delta="132" name="cancel_button" width="70" />
<string name="confirm_invite_owner_str">
@@ -39,7 +39,7 @@ Resident Chooser&apos; to start.
Group Invitations not sent: too many Residents selected. Group Invitations are limited to 100 per request.
</string>
<!--button bottom="25" font="SansSerifSmall" halign="center" height="20"
label="Send Invitations" left="65" name="ok_button" width="140" />
label="Send Invitations" left="65" name="invite_button" width="140" />
<button bottom_delta="-22" font="SansSerifSmall" halign="center" height="20"
label="Cancel" left_delta="0" name="cancel_button" width="140" /-->
<string name="loading">(loading...)</string>

View File

@@ -57,6 +57,18 @@ easily be customized, allowing for greater organization and flexibility.
execute the Ability.
</text>
</panel>
<panel border="false" bottom_delta="0" height="24" left="7" name="banlist_header"
visible="false" width="380">
<text bottom_delta="0" font="SansSerifBig" halign="left" height="16" left="0"
name="static" width="200">
Banned Residents
</text>
<text bottom_delta="-36" font="SansSerifSmall" halign="left" height="32" left="0"
name="static2" width="394">
Examine which Residents are not allowed in this group. Members with the
'Manage ban list' ability may block certain residents from joining the group.
</text>
</panel>
<tab_container border="false" bottom_delta="-190" height="180" left="6"
name="roles_tab_container" tab_position="top" width="406">
<panel border="true" bottom="0" height="164" label="Members" left="1"
@@ -82,7 +94,8 @@ execute the Ability.
<button bottom_delta="-20" font="SansSerif" halign="center" height="19"
label="Invite New Member ..." left="4" name="member_invite" width="146" />
<button bottom_delta="0" font="SansSerif" halign="center" height="19"
label="Eject From Group" left="-153" name="member_eject" width="146" />
label="Eject From Group" left_delta="149" name="member_eject" width="146" />
<button bottom_delta="0" left_delta="149" width="100" follows="top|left" height="19" label="Ban Member(s)" name="member_ban"/>
<string name="help_text">
You can add or remove Roles assigned to Members.
Select multiple Members by holding the Ctrl key and
@@ -144,6 +157,21 @@ things in this group. There&apos;s a broad variety of Abilities.
</string>
<string name="power_folder_icon">inv_folder_plain_closed.tga</string>
</panel>
<panel
border="false"
height="303"
label="Banned Residents"
layout="topleft"
left="0"
right="-1"
help_topic="roles_banlist_tab"
name="banlist_sub_tab"
width="310">
<panel.string
name="help_text">
Any resident on the ban list will be unable to join the group.
</panel.string>
</panel>
</tab_container>
<panel border="false" bottom_delta="-235" height="215" left="7" name="members_footer"
select="true" visible="true" width="406">
@@ -265,4 +293,63 @@ things in this group. There&apos;s a broad variety of Abilities.
height="125" left="150" multi_select="true" name="action_members"
width="254" menu_num="0" name_system="GroupMembersNameSystem"/>
</panel>
<!-- Singu Note: This is a total hack, abusing that footer is not part of the tab container -->
<panel border="false" bottom="-500" height="425" left="7" name="banlist_footer" mouse_opaque="false" visible="false">
<name_list
column_padding="0"
draw_heading="true"
height="368"
follows="left|top|right"
layout="topleft"
left="0"
right="-1"
multi_select="true"
name="ban_list"
menu_num="0"
name_system="GroupMembersNameSystem"
bottom="-365">
<column
label="Resident"
name="name"
font_name="SANSSERIF_SMALL"
font-style="NORMAL"
relative_width="0.7" />
<column
label="Date Banned"
name="ban_date"
relative_width="0.3" />
</name_list>
<button
follows="top|left"
height="20"
label="Ban Resident(s)"
layout="topleft"
left="3"
name="ban_create"
tool_tip="Ban residents from your group"
width="120" />
<button
follows="top|left"
bottom_delta="0"
height="20"
label="Remove Ban(s)"
layout="topleft"
left_delta="125"
name="ban_delete"
tool_tip="Unban selected residents from your group"
width="120" />
<button
follows="top|left"
bottom_delta="0"
height="20"
width="100"
image_overlay="Refresh_Off"
image_overlay_alignment="left"
layout="topleft"
left_delta="165"
name="ban_refresh"
label="Refresh"
tool_tip="Refresh the ban list"
/>
</panel>
</panel>

View File

@@ -9,6 +9,9 @@
<action description="Eject Members from this Group"
longdescription="Eject Members from this Group using the &apos;Eject From Group&apos; button in the Members &amp; Roles tab &gt; Members sub-tab. An Owner can eject anyone except another Owner. If you&apos;re not an Owner, a Member can be ejected from a group if, and only if, they&apos;re only in the Everyone Role, and NO other Roles. To remove Members from Roles, you need to have the &apos;Remove Members from Roles&apos; Ability."
name="member eject" value="2" />
<action description="Manage ban list"
longdescription="Allows the group member to ban / un-ban Residents from this group."
name="allow ban" value="51" />
<action
description="Toggle &apos;Open Enrollment&apos; and change &apos;Signup Fee&apos;"
longdescription="Toggle &apos;Open Enrollment&apos; to let new Members join without an invitation, and change &apos;Signup Fee&apos; in the Group Preferences section of the General tab."