Merge. Refresh from viewer-release after 3.7.13 release.

master
Monty Brandenberg 2014-08-04 14:57:14 -04:00
commit 9a8b1552f0
35 changed files with 2982 additions and 752 deletions

View File

@ -485,3 +485,4 @@ a9f2d0cb11f73b06858e6083bb50083becc3f9cd 3.7.9-release
91dae9494b4d147541c7a01902334ba19a7ec05e 3.7.10-release
64799eb298834073a3e9992cd8d27c3cb9d30b10 3.7.11-release
3b44ea8988cb902f0dda8429e8d5e4569e304532 3.7.12-release
d86a7e1bc96d27b683f951d3701d5b7042158c68 3.7.13-release

View File

@ -477,7 +477,8 @@ void LLToolTipMgr::show(const std::string& msg)
void LLToolTipMgr::show(const LLToolTip::Params& params)
{
if (!params.styled_message.isProvided()
&& (!params.message.isProvided() || params.message().empty())) return;
&& (!params.message.isProvided() || params.message().empty())
&& !params.image.isProvided()) return;
// fill in default tooltip params from tool_tip.xml
LLToolTip::Params params_with_defaults(params);

View File

@ -238,6 +238,7 @@ set(viewer_SOURCE_FILES
llfloatergesture.cpp
llfloatergodtools.cpp
llfloatergotoline.cpp
llfloatergroupbulkban.cpp
llfloatergroupinvite.cpp
llfloatergroups.cpp
llfloaterhandler.cpp
@ -412,6 +413,8 @@ set(viewer_SOURCE_FILES
llpanelface.cpp
llpanelgenerictip.cpp
llpanelgroup.cpp
llpanelgroupbulk.cpp
llpanelgroupbulkban.cpp
llpanelgroupgeneral.cpp
llpanelgroupinvite.cpp
llpanelgrouplandmoney.cpp
@ -839,6 +842,7 @@ set(viewer_HEADER_FILES
llfloatergesture.h
llfloatergodtools.h
llfloatergotoline.h
llfloatergroupbulkban.h
llfloatergroupinvite.h
llfloatergroups.h
llfloaterhandler.h
@ -1006,6 +1010,9 @@ set(viewer_HEADER_FILES
llpanelface.h
llpanelgenerictip.h
llpanelgroup.h
llpanelgroupbulk.h
llpanelgroupbulkimpl.h
llpanelgroupbulkban.h
llpanelgroupgeneral.h
llpanelgroupinvite.h
llpanelgrouplandmoney.h

View File

@ -1 +1 @@
3.7.13
3.7.14

View File

@ -6118,16 +6118,16 @@
<integer>0</integer>
</map>
<key>MemoryLogFrequency</key>
<map>
<key>Comment</key>
<string>Seconds between display of Memory in log (0 for never)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>600.0</real>
</map>
<map>
<key>Comment</key>
<string>Seconds between display of Memory in log (0 for never)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>30.0</real>
</map>
<key>MemoryPrivatePoolEnabled</key>
<map>
<key>Comment</key>

View File

@ -51,6 +51,7 @@ LLConversationItem::LLConversationItem(std::string display_name, const LLUUID& u
mConvType(CONV_UNKNOWN),
mLastActiveTime(0.0),
mDisplayModeratorOptions(false),
mDisplayGroupBanOptions(false),
mAvatarNameCacheConnection()
{
}
@ -63,6 +64,7 @@ LLConversationItem::LLConversationItem(const LLUUID& uuid, LLFolderViewModelInte
mConvType(CONV_UNKNOWN),
mLastActiveTime(0.0),
mDisplayModeratorOptions(false),
mDisplayGroupBanOptions(false),
mAvatarNameCacheConnection()
{
}
@ -75,6 +77,7 @@ LLConversationItem::LLConversationItem(LLFolderViewModelInterface& root_view_mod
mConvType(CONV_UNKNOWN),
mLastActiveTime(0.0),
mDisplayModeratorOptions(false),
mDisplayGroupBanOptions(false),
mAvatarNameCacheConnection()
{
}
@ -159,6 +162,12 @@ void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32
items.push_back(std::string("ModerateVoiceMute"));
items.push_back(std::string("ModerateVoiceUnmute"));
}
if ((getType() != CONV_SESSION_1_ON_1) && mDisplayGroupBanOptions)
{
items.push_back(std::string("Group Ban Separator"));
items.push_back(std::string("BanMember"));
}
}
}

View File

@ -143,6 +143,7 @@ protected:
bool mNeedsRefresh; // Flag signaling to the view that something changed for this item
F64 mLastActiveTime;
bool mDisplayModeratorOptions;
bool mDisplayGroupBanOptions;
boost::signals2::connection mAvatarNameCacheConnection;
};
@ -206,6 +207,7 @@ public:
void dumpDebugData();
void setModeratorOptionsVisible(bool visible) { mDisplayModeratorOptions = visible; }
void setDisplayModeratorRole(bool displayRole);
void setGroupBanVisible(bool visible) { mDisplayGroupBanOptions = visible; }
private:
void onAvatarNameCache(const LLAvatarName& av_name); // callback used by fetchAvatarName

View File

@ -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();
}

View File

@ -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

View File

@ -532,6 +532,7 @@ void LLFloaterIMContainer::draw()
{
LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
participant_model->setModeratorOptionsVisible(isGroupModerator() && participant_model->getUUID() != gAgentID);
participant_model->setGroupBanVisible(haveAbilityToBan() && participant_model->getUUID() != gAgentID);
current_participant_model++;
}
@ -1150,6 +1151,10 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec
{
toggleAllowTextChat(userID);
}
else if ("ban_member" == command)
{
banSelectedMember(userID);
}
}
else if (selectedIDS.size() > 1)
{
@ -1271,6 +1276,22 @@ bool LLFloaterIMContainer::enableContextMenuItem(const LLSD& userdata)
uuid_vec_t uuids;
getParticipantUUIDs(uuids);
//If there is group or ad-hoc chat in multiselection, everything needs to be disabled
if(uuids.size() > 1)
{
const std::set<LLFolderViewItem*> selectedItems = mConversationsRoot->getSelectionList();
LLConversationItem * conversationItem;
for(std::set<LLFolderViewItem*>::const_iterator it = selectedItems.begin(); it != selectedItems.end(); ++it)
{
conversationItem = static_cast<LLConversationItem *>((*it)->getViewModelItem());
if((conversationItem->getType() == LLConversationItem::CONV_SESSION_GROUP) || (conversationItem->getType() == LLConversationItem::CONV_SESSION_AD_HOC))
{
return false;
}
}
}
if ("conversation_log" == item)
{
return gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 0;
@ -1375,6 +1396,10 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v
else if ("can_call" == item)
{
return LLAvatarActions::canCall();
}
else if ("can_open_voice_conversation" == item)
{
return is_single_select && LLAvatarActions::canCall();
}
else if ("can_zoom_in" == item)
{
@ -1387,6 +1412,10 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v
else if ("can_offer_teleport" == item)
{
return LLAvatarActions::canOfferTeleport(uuids);
}
else if ("can_ban_member" == item)
{
return canBanSelectedMember(single_id);
}
else if (("can_moderate_voice" == item) || ("can_allow_text_chat" == item) || ("can_mute" == item) || ("can_unmute" == item))
{
@ -1810,6 +1839,95 @@ bool LLFloaterIMContainer::isGroupModerator()
return false;
}
bool LLFloaterIMContainer::haveAbilityToBan()
{
LLSpeakerMgr * speaker_manager = getSpeakerMgrForSelectedParticipant();
if (NULL == speaker_manager)
{
LL_WARNS() << "Speaker manager is missing" << LL_ENDL;
return false;
}
LLUUID group_uuid = speaker_manager->getSessionID();
return gAgent.isInGroup(group_uuid) && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS);
}
bool LLFloaterIMContainer::canBanSelectedMember(const LLUUID& participant_uuid)
{
LLSpeakerMgr * speaker_manager = getSpeakerMgrForSelectedParticipant();
if (NULL == speaker_manager)
{
LL_WARNS() << "Speaker manager is missing" << LL_ENDL;
return false;
}
LLUUID group_uuid = speaker_manager->getSessionID();
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid);
if(!gdatap)
{
LL_WARNS("Groups") << "Unable to get group data for group " << group_uuid << LL_ENDL;
return false;
}
if (!gdatap->mMembers.size())
{
return false;
}
LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find((participant_uuid));
if (mi == gdatap->mMembers.end())
{
return false;
}
LLGroupMemberData* member_data = (*mi).second;
// Is the member an owner?
if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
{
return false;
}
if( gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) &&
gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS) )
{
return true;
}
return false;
}
void LLFloaterIMContainer::banSelectedMember(const LLUUID& participant_uuid)
{
LLSpeakerMgr * speaker_manager = getSpeakerMgrForSelectedParticipant();
if (NULL == speaker_manager)
{
LL_WARNS() << "Speaker manager is missing" << LL_ENDL;
return;
}
LLUUID group_uuid = speaker_manager->getSessionID();
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid);
if(!gdatap)
{
LL_WARNS("Groups") << "Unable to get group data for group " << group_uuid << LL_ENDL;
return;
}
std::vector<LLUUID> ids;
ids.push_back(participant_uuid);
LLGroupBanData ban_data;
gdatap->createBanEntry(participant_uuid, ban_data);
LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, group_uuid, LLGroupMgr::BAN_CREATE, ids);
LLGroupMgr::getInstance()->sendGroupMemberEjects(group_uuid, ids);
LLGroupMgr::getInstance()->sendGroupMembersRequest(group_uuid);
LLSD args;
std::string name;
gCacheName->getFullName(participant_uuid, name);
args["AVATAR_NAME"] = name;
args["GROUP_NAME"] = gdatap->mName;
LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
}
void LLFloaterIMContainer::moderateVoice(const std::string& command, const LLUUID& userID)
{
if (!gAgent.getRegion()) return;

View File

@ -167,12 +167,16 @@ private:
LLSpeaker * getSpeakerOfSelectedParticipant(LLSpeakerMgr * speaker_managerp);
LLSpeakerMgr * getSpeakerMgrForSelectedParticipant();
bool isGroupModerator();
bool haveAbilityToBan();
bool canBanSelectedMember(const LLUUID& participant_uuid);
LLUUID getGroupUIIDForSelectedParticipant();
bool isMuted(const LLUUID& avatar_id);
void moderateVoice(const std::string& command, const LLUUID& userID);
void moderateVoiceAllParticipants(bool unmute);
void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
void toggleAllowTextChat(const LLUUID& participant_uuid);
void toggleMute(const LLUUID& participant_id, U32 flags);
void banSelectedMember(const LLUUID& participant_uuid);
void openNearbyChat();
bool isParticipantListExpanded();

View File

@ -149,7 +149,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)
@ -159,9 +159,6 @@ public:
else if (!gdatap->isMemberDataComplete())
{
LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData()->isMemberDataComplete() was FALSE" << LL_ENDL;
}
else
{
processGroupData();
mRequestProcessed = true;
}

View File

@ -234,11 +234,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();
@ -427,7 +427,7 @@ void LLGroupMgrGroupData::removeMemberData()
delete mi->second;
}
mMembers.clear();
mMemberDataComplete = FALSE;
mMemberDataComplete = false;
mMemberVersion.generate();
}
@ -449,8 +449,8 @@ void LLGroupMgrGroupData::removeRoleData()
}
mRoles.clear();
mReceivedRoleMemberPairs = 0;
mRoleDataComplete = FALSE;
mRoleMemberDataComplete = FALSE;
mRoleDataComplete = false;
mRoleMemberDataComplete= false;
}
void LLGroupMgrGroupData::removeRoleMemberData()
@ -474,7 +474,7 @@ void LLGroupMgrGroupData::removeRoleMemberData()
}
mReceivedRoleMemberPairs = 0;
mRoleMemberDataComplete = FALSE;
mRoleMemberDataComplete= false;
}
LLGroupMgrGroupData::~LLGroupMgrGroupData()
@ -750,6 +750,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
//
@ -959,12 +973,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);
}
}
@ -1034,7 +1048,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);
@ -1111,12 +1125,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);
}
}
@ -1225,7 +1239,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data)
}
}
group_datap->mRoleMemberDataComplete = TRUE;
group_datap->mRoleMemberDataComplete= true;
group_datap->mRoleMembersRequestID.setNull();
}
@ -1848,6 +1862,138 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
}
// Responder class for capability group management
class GroupBanDataResponder : public LLHTTPClient::Responder
{
public:
GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh=false);
virtual ~GroupBanDataResponder() {}
virtual void httpSuccess();
virtual void httpFailure();
private:
LLUUID mGroupID;
BOOL mForceRefresh;
};
GroupBanDataResponder::GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh) :
mGroupID(gropup_id),
mForceRefresh(force_refresh)
{}
void GroupBanDataResponder::httpFailure()
{
LL_WARNS("GrpMgr") << "Error receiving group member data [status:"
<< mStatus << "]: " << mContent << LL_ENDL;
}
void GroupBanDataResponder::httpSuccess()
{
if (mContent.has("ban_list"))
{
// group ban data received
LLGroupMgr::processGroupBanRequest(mContent);
}
else if (mForceRefresh)
{
// no ban data received, refreshing data after 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::Responder
{
@ -1941,7 +2087,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,6 +2154,22 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
online_status,
is_owner);
LLGroupMemberData* member_old = group_datap->mMembers[member_id];
if (member_old && group_datap->mRoleMemberDataComplete)
{
LLGroupMemberData::role_list_t::iterator rit = member_old->roleBegin();
LLGroupMemberData::role_list_t::iterator end = member_old->roleEnd();
for ( ; rit != end; ++rit)
{
data->addRole((*rit).first,(*rit).second);
}
}
else
{
group_datap->mRoleMemberDataComplete = false;
}
group_datap->mMembers[member_id] = data;
}
@ -2024,12 +2186,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)
if (group_datap->mPendingRoleMemberRequest || !group_datap->mRoleMemberDataComplete)
{
group_datap->mPendingRoleMemberRequest = FALSE;
group_datap->mPendingRoleMemberRequest = false;
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id);
}

View File

@ -33,8 +33,10 @@
#include <string>
#include <map>
// Forward Declarations
class LLMessageSystem;
class LLGroupRoleData;
class LLGroupMgr;
enum LLGroupChange
{
@ -43,9 +45,12 @@ enum LLGroupChange
GC_ROLE_DATA,
GC_ROLE_MEMBER_DATA,
GC_TITLES,
GC_BANLIST,
GC_ALL
};
const U32 GB_MAX_BANNED_AGENTS = 500;
class LLGroupMgrObserver
{
public:
@ -65,8 +70,6 @@ public:
virtual void changed(const LLUUID& group_id, LLGroupChange gc) = 0;
};
class LLGroupRoleData;
class LLGroupMemberData
{
friend class LLGroupMgrGroupData;
@ -201,6 +204,17 @@ struct lluuid_pair_less
}
};
struct LLGroupBanData
{
LLGroupBanData(): mBanDate() {}
~LLGroupBanData() {}
LLDate mBanDate;
// TODO: std:string ban_reason;
};
struct LLGroupTitle
{
std::string mTitle;
@ -208,8 +222,6 @@ struct LLGroupTitle
BOOL mSelected;
};
class LLGroupMgr;
class LLGroupMgrGroupData
{
friend class LLGroupMgr;
@ -239,11 +251,11 @@ 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; }
bool isSingleMemberNotOwner();
F32 getAccessTime() const { return mAccessTime; }
@ -251,17 +263,26 @@ public:
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;
@ -292,12 +313,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
@ -324,6 +345,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();
@ -357,8 +395,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,
U32 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);
@ -403,4 +447,3 @@ private:
#endif

View File

@ -64,7 +64,8 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p)
mNameColumnIndex(p.name_column.column_index),
mNameColumn(p.name_column.column_name),
mAllowCallingCardDrop(p.allow_calling_card_drop),
mShortNames(p.short_names)
mShortNames(p.short_names),
mPendingLookupsRemaining(0)
{}
// public
@ -337,6 +338,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 mPendingLookupsRemaining might
// go negative. So just reset it right now and figure out if it's
// possible later :)
mPendingLookupsRemaining = 0;
mNameListCompleteSignal(false);
}
mPendingLookupsRemaining++;
}
break;
}
@ -388,6 +400,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id)
{
selectNthItem(idx); // not sure whether this is needed, taken from previous implementation
deleteSingleItem(idx);
mPendingLookupsRemaining--;
}
}
@ -429,6 +443,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,7 @@ class LLNameListCtrl
: public LLScrollListCtrl, public LLInstanceTracker<LLNameListCtrl>
{
public:
typedef boost::signals2::signal<void(bool)> namelist_complete_signal_t;
typedef enum e_name_type
{
@ -156,7 +157,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, std::string suffix, LLHandle<LLNameListItem> item);
@ -168,6 +169,16 @@ private:
bool mShortNames; // display name only, no SLID
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

@ -0,0 +1,421 @@
/**
* @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),
mListFullNotificationSent(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(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);
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->mListFullNotificationSent = false;
mImplementation->addUsers(names, agent_ids);
}

View File

@ -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);
/*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,259 @@
/**
* @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 "llavataractions.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");
}
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");
mImplementation->mBanNotPermitted = getString("ban_not_permitted");
mImplementation->mBanLimitFail = getString("ban_limit_fail");
mImplementation->mCannotBanYourself = getString("cant_ban_yourself");
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()
{
if (!gAgent.hasPowerInGroup(mImplementation->mGroupID, GP_GROUP_BAN_ACCESS))
{
// Fail! Agent no longer have ban rights. Permissions could have changed after button was pressed.
LLSD msg;
msg["MESSAGE"] = mImplementation->mBanNotPermitted;
LLNotificationsUtil::add("GenericAlert", msg);
(*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
return;
}
LLGroupMgrGroupData * group_datap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID);
if (group_datap && group_datap->mBanList.size() >= GB_MAX_BANNED_AGENTS)
{
// Fail! Size limit exceeded. List could have updated after button was pressed.
LLSD msg;
msg["MESSAGE"] = mImplementation->mBanLimitFail;
LLNotificationsUtil::add("GenericAlert", msg);
(*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
return;
}
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_BANS_PER_REQUEST = 100; // Max bans per request. 100 to match server cap.
if (banned_agent_list.size() > MAX_BANS_PER_REQUEST)
{
// Fail!
LLSD msg;
msg["MESSAGE"] = mImplementation->mTooManySelected;
LLNotificationsUtil::add("GenericAlert", msg);
(*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
return;
}
// remove already banned users and yourself from request.
std::vector<LLAvatarName> banned_avatar_names;
std::vector<LLAvatarName> out_of_limit_names;
bool banning_self = FALSE;
std::vector<LLUUID>::iterator conflict = std::find(banned_agent_list.begin(), banned_agent_list.end(), gAgent.getID());
if (conflict != banned_agent_list.end())
{
banned_agent_list.erase(conflict);
banning_self = TRUE;
}
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;
std::vector<LLUUID>::iterator conflict = std::find(banned_agent_list.begin(), banned_agent_list.end(), group_ban_agent_id);
if (conflict != banned_agent_list.end())
{
LLAvatarName av_name;
LLAvatarNameCache::get(group_ban_agent_id, &av_name);
banned_avatar_names.push_back(av_name);
banned_agent_list.erase(conflict);
if (banned_agent_list.size() == 0)
{
break;
}
}
}
// this check should always be the last one before we send the request.
// Otherwise we have a possibility of cutting more then we need to.
if (banned_agent_list.size() > GB_MAX_BANNED_AGENTS - group_datap->mBanList.size())
{
std::vector<LLUUID>::iterator exeedes_limit = banned_agent_list.begin() + GB_MAX_BANNED_AGENTS - group_datap->mBanList.size();
for (std::vector<LLUUID>::iterator itor = exeedes_limit ;
itor != banned_agent_list.end(); ++itor)
{
LLAvatarName av_name;
LLAvatarNameCache::get(*itor, &av_name);
out_of_limit_names.push_back(av_name);
}
banned_agent_list.erase(exeedes_limit,banned_agent_list.end());
}
}
// sending request and ejecting members
if (banned_agent_list.size() != 0)
{
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);
}
// building notification
if (banned_avatar_names.size() > 0 || banning_self || out_of_limit_names.size() > 0)
{
std::string reasons;
if(banned_avatar_names.size() > 0)
{
reasons = "\n " + buildResidentsArgument(banned_avatar_names, "residents_already_banned");
}
if(banning_self)
{
reasons += "\n " + mImplementation->mCannotBanYourself;
}
if(out_of_limit_names.size() > 0)
{
reasons += "\n " + buildResidentsArgument(out_of_limit_names, "ban_limit_reached");
}
LLStringUtil::format_map_t msg_args;
msg_args["[REASONS]"] = reasons;
LLSD msg;
if (banned_agent_list.size() == 0)
{
msg["MESSAGE"] = getString("ban_failed", msg_args);
}
else
{
msg["MESSAGE"] = getString("partial_ban", msg_args);
}
LLNotificationsUtil::add("GenericAlert", msg);
}
//then close
(*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData);
}
std::string LLPanelGroupBulkBan::buildResidentsArgument(std::vector<LLAvatarName> avatar_names, const std::string &format)
{
std::string names_string;
LLAvatarActions::buildResidentsString(avatar_names, names_string);
LLStringUtil::format_map_t args;
args["[RESIDENTS]"] = names_string;
return getString(format, args);
}

View File

@ -0,0 +1,49 @@
/**
* @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();
private:
std::string buildResidentsArgument(std::vector<LLAvatarName> avatar_names, const std::string &format);
};
#endif // LL_LLPANELGROUPBULKBAN_H

View File

@ -0,0 +1,99 @@
/**
* @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::string mBanNotPermitted;
std::string mBanLimitFail;
std::string mCannotBanYourself;
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;
bool mListFullNotificationSent;
};
#endif // LL_LLPANELGROUPBULKIMPL_H

View File

@ -260,7 +260,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,
@ -492,7 +492,7 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids)
}
else
{
LL_WARNS() << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << LL_ENDL;
llwarns << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << llendl;
names.push_back("(Unknown)");
}
}
@ -579,7 +579,7 @@ void LLPanelGroupInvite::updateLists()
{
waiting = true;
}
if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete())
if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete())
{
if ( mImplementation->mRoleNames )
{
@ -607,6 +607,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;
@ -654,7 +655,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);

File diff suppressed because it is too large Load Diff

View File

@ -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:
@ -143,10 +142,14 @@ protected:
icon_map_t mActionIcons;
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:
@ -173,6 +176,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 +213,7 @@ protected:
LLScrollListCtrl* mAssignedRolesList;
LLScrollListCtrl* mAllowedActionsList;
LLButton* mEjectBtn;
LLButton* mBanBtn;
BOOL mChanged;
BOOL mPendingMemberUpdate;
@ -219,6 +227,7 @@ protected:
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
};
class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab
{
public:
@ -241,7 +250,7 @@ public:
static void onActionCheck(LLUICtrl*, void*);
bool addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check);
static void onPropertiesKey(LLLineEditor*, void*);
void onDescriptionKeyStroke(LLTextEditor* caller);
@ -260,6 +269,9 @@ public:
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);
@ -281,6 +293,7 @@ protected:
std::string mRemoveEveryoneTxt;
};
class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab
{
public:
@ -308,4 +321,46 @@ 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 setBanCount(U32 ban_count);
void populateBanList();
public:
virtual void setGroupID(const LLUUID& id);
protected:
LLNameListCtrl* mBanList;
LLButton* mCreateBanButton;
LLButton* mDeleteBanButton;
LLButton* mRefreshBanListButton;
LLTextBase* mBanCountText;
};
#endif // LL_LLPANELGROUPROLES_H

View File

@ -488,8 +488,9 @@ void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
gCacheName->getGroup(parcel->getGroupID(),
boost::bind(&LLPanelPlaceInfo::onNameCache, mRegionGroupText, _2));
gCacheName->getGroup(parcel->getGroupID(),
boost::bind(&LLPanelPlaceInfo::onNameCache, mParcelOwner, _2));
std::string owner =
LLSLURL("group", parcel->getGroupID(), "inspect").getSLURLString();
mParcelOwner->setText(owner);
}
else
{

View File

@ -2708,6 +2708,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");

102
indra/newview/roles_constants.h Executable file → Normal file
View File

@ -53,98 +53,100 @@ 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)
// bit 0x1 << 46 (GP_PROPOSAL_VIEW)
const U64 GP_NO_POWERS = 0x0;
const U64 GP_ALL_POWERS = 0xFFFFFFFFFFFFFFFFLL;
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

View File

@ -72,7 +72,7 @@ Second Life is brought to you by the Lindens:
top_pad="10"
width="435"
word_wrap="true">
Philip, Andrew, Doug, Richard, Phoenix, Ian, Mark, Robin, Dan, Char, Ryan, Eric, Jim, Lee, Jeff, Michael, Kelly, Steve, Catherine, Bub, Ramzi, Jill, Jeska, Don, Kona, Callum, Charity, Jack, Shawn, babbage, James, Lauren, Blue, Brent, Reuben, Pathfinder, Jesse, Patsy, Torley, Bo, Cyn, Jonathan, Gia, Annette, Ginsu, Harry, Lex, Runitai, Guy, Cornelius, Beth, Swiss, Thumper, Wendy, Teeple, Seth, Dee, Mia, Sally, Liana, Aura, Beez, Milo, Red, Gulliver, Marius, Joe, Jose, Dore, Justin, Nora, Morpheus, Lexie, Amber, Chris, Xan, Leyla, Walker, Sabin, Joshua, Hiromi, Tofu, Fritz, June, Jean, Ivy, Dez, Ken, Betsy, Which, Spike, Rob, Zee, Dustin, George, Claudia, del, Matthew, jane, jay, Adrian, Yool, Rika, Yoz, siobhan, Qarl, Benjamin, Beast, Everett, madhavi, Christopher, Izzy, stephany, Jeremy, sean, adreanne, Pramod, Tobin, sejong, Iridium, maurice, kj, Meta, kari, JP, bert, kyle, Jon, Socrates, Bridie, Ivan, maria, Aric, Coco, Periapse, sandy, Storrs, Lotte, Colossus, Brad, Pastrami, Zen, BigPapi, Banzai, Sardonyx, Mani, Garry, Jaime, Neuro, Samuel, Niko, CeeLo, Austin, Soft, Poppy, emma, tessa, angelo, kurz, alexa, Sue, CG, Blake, Erica, Brett, Bevis, kristen, Q, simon, Enus, MJ, laurap, Kip, Scouse, Ron, Ram, kend, Marty, Prospero, melissa, kraft, Nat, Seraph, Hamilton, Lordan, Green, miz, Ashlei, Trinity, Ekim, Echo, Charlie, Rowan, Rome, Jt, Doris, benoc, Christy, Bao, Kate, Tj, Patch, Cheah, Johan, Brandy, Angela, Oreh, Cogsworth, Lan, Mitchell, Space, Bambers, Einstein, Bender, Malbers, Matias, Maggie, Rothman, Milton, Niall, Marin, Allison, Mango, Andrea, Katt, Yi, Ambroff, Rico, Raymond, Gail, Christa, William, Dawn, Usi, Dynamike, M, Corr, Dante, Molly, kaylee, Danica, Kelv, Lil, jacob, Nya, Rodney, elsie, Blondin, Grant, Nyx, Devin, Monty, Minerva, Keira, Katie, Jenn, Makai, Clare, Joy, Cody, Gayathri, FJ, spider, Oskar, Landon, Jarv, Noelle, Al, Doc, Gray, Vir, t, Maestro, Simone, Shannon, yang, Courtney, Scott, charlene, Quixote, Susan, Zed, Amanda, Katelin, Esbee, JoRoan, Enkidu, roxie, Scarlet, Merov, Kevin, Judy, Rand, Newell, Les, Dessie, Galen, Michon, Geo, Siz, Calyle, Pete, Praveen, Callen, Sheldon, Pink, Nelson, jenelle, Terrence, Nathan, Juan, Sascha, Huseby, Karina, Kaye, Kotler, Lis, Darv, Charrell, Dakota, Kimmora, Theeba, Taka, Mae, Perry, Ducot, dana, Esther, Dough, gisele, Doten, Viale, Fisher, jessieann, ashley, Torres, delby, rountree, kurt, Slaton, Madison, Rue, Gino, Wen, Casssandra, Brodesky, Squid, Gez, Rakesh, Gecko, Ladan, Tony, Tatem, Squire, Falcon, BK, Crimp, Tiggs, Bacon, Coyot, Carmilla, Webb, Sea, Arch, Jillian, Jason, Bernard, Vogt, Peggy, dragon, Pup, xandix, Wallace, Bewest, Inoshiro, Rhett, AG, Aimee, Ghengis, Itiaes, Eli, Steffan, Epic, Grapes, Stone, Prep, Scobu, Robert, Alain, Carla, Vicky, Tia, Alec, Taras, Lisa, Oz, Ariane, Log, House, Kazu, Kim, Drofnas, Tyler, Campbell, Michele, Madeline, Nelly, Baron, Thor, Lori, Hele, Fredrik, Teddy, Pixie, Berry, Gabrielle, Alfonso, Brooke, Wolf, Ringo, Cru, Charlar, Rodvik, Gibson, Elise, Bagman, Greger, Leonidas, Jerm, Leslie, CB, Brenda, Durian, Carlo, mm, Zeeshan, Caleb, Max, Elikak, Mercille, Steph, Chase
Philip, Andrew, Doug, Richard, Phoenix, Ian, Mark, Robin, Dan, Char, Ryan, Eric, Jim, Lee, Jeff, Michael, Kelly, Steve, Catherine, Bub, Ramzi, Jill, Jeska, Don, Kona, Callum, Charity, Jack, Shawn, babbage, James, Lauren, Blue, Brent, Reuben, Pathfinder, Jesse, Patsy, Torley, Bo, Cyn, Jonathan, Gia, Annette, Ginsu, Harry, Lex, Runitai, Guy, Cornelius, Beth, Swiss, Thumper, Wendy, Teeple, Seth, Dee, Mia, Sally, Liana, Aura, Beez, Milo, Red, Gulliver, Marius, Joe, Jose, Dore, Justin, Nora, Morpheus, Lexie, Amber, Chris, Xan, Leyla, Walker, Sabin, Joshua, Hiromi, Tofu, Fritz, June, Jean, Ivy, Dez, Ken, Betsy, Which, Spike, Rob, Zee, Dustin, George, Claudia, del, Matthew, jane, jay, Adrian, Yool, Rika, Yoz, siobhan, Qarl, Benjamin, Beast, Everett, madhavi, Christopher, Izzy, stephany, Jeremy, sean, adreanne, Pramod, Tobin, sejong, Iridium, maurice, kj, Meta, kari, JP, bert, kyle, Jon, Socrates, Bridie, Ivan, maria, Aric, Coco, Periapse, sandy, Storrs, Lotte, Colossus, Brad, Pastrami, Zen, BigPapi, Banzai, Sardonyx, Mani, Garry, Jaime, Neuro, Samuel, Niko, CeeLo, Austin, Soft, Poppy, emma, tessa, angelo, kurz, alexa, Sue, CG, Blake, Erica, Brett, Bevis, kristen, Q, simon, Enus, MJ, laurap, Kip, Scouse, Ron, Ram, kend, Marty, Prospero, melissa, kraft, Nat, Seraph, Hamilton, Lordan, Green, miz, Ashlei, Trinity, Ekim, Echo, Charlie, Rowan, Rome, Jt, Doris, benoc, Christy, Bao, Kate, Tj, Patch, Cheah, Johan, Brandy, Angela, Oreh, Cogsworth, Lan, Mitchell, Space, Bambers, Einstein, Bender, Malbers, Matias, Maggie, Rothman, Milton, Niall, Marin, Allison, Mango, Andrea, Katt, Yi, Ambroff, Rico, Raymond, Gail, Christa, William, Dawn, Usi, Dynamike, M, Corr, Dante, Molly, kaylee, Danica, Kelv, Lil, jacob, Nya, Rodney, elsie, Blondin, Grant, Nyx, Devin, Monty, Minerva, Keira, Katie, Jenn, Makai, Clare, Joy, Cody, Gayathri, FJ, spider, Oskar, Landon, Jarv, Noelle, Al, Doc, Gray, Vir, t, Maestro, Simone, Shannon, yang, Courtney, Scott, charlene, Quixote, Susan, Zed, Amanda, Katelin, Esbee, JoRoan, Enkidu, roxie, Scarlet, Merov, Kevin, Judy, Rand, Newell, Les, Dessie, Galen, Michon, Geo, Siz, Calyle, Pete, Praveen, Callen, Sheldon, Pink, Nelson, jenelle, Terrence, Nathan, Juan, Sascha, Huseby, Karina, Kaye, Kotler, Lis, Darv, Charrell, Dakota, Kimmora, Theeba, Taka, Mae, Perry, Ducot, dana, Esther, Dough, gisele, Doten, Viale, Fisher, jessieann, ashley, Torres, delby, rountree, kurt, Slaton, Madison, Rue, Gino, Wen, Casssandra, Brodesky, Squid, Gez, Rakesh, Gecko, Ladan, Tony, Tatem, Squire, Falcon, BK, Crimp, Tiggs, Bacon, Coyot, Carmilla, Webb, Sea, Arch, Jillian, Jason, Bernard, Vogt, Peggy, dragon, Pup, xandix, Wallace, Bewest, Inoshiro, Rhett, AG, Aimee, Ghengis, Itiaes, Eli, Steffan, Epic, Grapes, Stone, Prep, Scobu, Robert, Alain, Carla, Vicky, Tia, Alec, Taras, Lisa, Oz, Ariane, Log, House, Kazu, Kim, Drofnas, Tyler, Campbell, Michele, Madeline, Nelly, Baron, Thor, Lori, Hele, Fredrik, Teddy, Pixie, Berry, Gabrielle, Alfonso, Brooke, Wolf, Ringo, Cru, Charlar, Rodvik, Gibson, Elise, Bagman, Greger, Leonidas, Jerm, Leslie, CB, Brenda, Durian, Carlo, mm, Zeeshan, Caleb, Max, Elikak, Mercille, Steph, Chase, Baker
</text_editor>
<text
follows="top|left"

View File

@ -17,6 +17,7 @@
layout="topleft"
name="open_voice_conversation">
<on_click function="Avatar.DoToSelected" parameter="open_voice_conversation"/>
<on_enable function="Avatar.EnableItem" parameter="can_open_voice_conversation"/>
</menu_item_call>
<menu_item_call
label="Disconnect from voice"
@ -213,4 +214,12 @@
<on_enable function="Avatar.EnableItem" parameter="can_moderate_voice" />
</menu_item_call>
</context_menu>
<menu_item_separator layout="topleft" name="Group Ban Separator"/>
<menu_item_call
label="Ban member"
layout="topleft"
name="BanMember">
<on_click function="Avatar.DoToSelected" parameter="ban_member" />
<on_enable function="Avatar.EnableItem" parameter="can_ban_member" />
</menu_item_call>
</toggleable_menu>

View File

@ -506,7 +506,35 @@ Add this Ability to &apos;[ROLE_NAME]&apos;?
notext="No"
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="EjectGroupMemberWarning"
@ -3746,6 +3774,28 @@ Leave Group?
yestext="OK"/>
</notification>
<notification
icon="aler.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,108 @@
<?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 bans not sent: too many Residents selected. Group bans are limited to 100 per request.
</panel.string>
<panel.string
name="ban_not_permitted">
Group ban not sent: you do not have 'Manage ban list' ability.
</panel.string>
<panel.string
name="ban_limit_fail">
Group ban not sent: your group have reached limit of allowed ban records.
</panel.string>
<panel.string
name="partial_ban">
Some group bans were not sent:
[REASONS]
</panel.string>
<panel.string
name="ban_failed">
Group bans were not sent:
[REASONS]
</panel.string>
<panel.string
name="residents_already_banned">
- The following resident(s) are already banned: [RESIDENTS].
</panel.string>
<panel.string
name="ban_limit_reached">
- Ban limit reached, following agents not banned: [RESIDENTS].
</panel.string>
<panel.string
name="cant_ban_yourself">
- You cannot ban yourself from a group.
</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>

View File

@ -76,7 +76,7 @@
Choose what Role to assign them to:
</text>
<combo_box
height="16"
height="20"
layout="topleft"
left_delta="0"
name="role_name"
@ -88,7 +88,7 @@
label="Send Invitations"
layout="topleft"
left="4"
name="ok_button"
name="invite_button"
top="356"
width="135" />
<button

View File

@ -118,6 +118,13 @@ clicking on their names.
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"
@ -138,291 +145,372 @@ 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
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"
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>
<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="550"
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="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"
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
border="false"
height="303"
label="BANNED RESIDENTS"
layout="topleft"
left="0"
right="-1"
help_topic="roles_banlist_tab"
name="banlist_sub_tab"
class="panel_group_banlist_subtab"
tool_tip="View the banned residents 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>
<panel.string
name="ban_count_template">
Ban count: [COUNT]/[LIMIT]
</panel.string>
<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"
/>
<text
type="string"
height="18"
left_pad="5"
follows="top|left"
layout="topleft"
name="ban_count"
width="100">
</text>
</panel>
</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"
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"
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
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"
@ -431,161 +519,161 @@ things in this group. There&apos;s a broad variety of Abilities.
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>
</panel>
<panel
height="424"
background_visible="false"
bg_alpha_color="FloaterUnfocusBorderColor"
Description
</text>
<text_editor
type="string"
layout="topleft"
follows="top|left|right"
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"
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>
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>

View File

@ -9,7 +9,10 @@
<action description="Eject Members from this Group"
longdescription="Eject Members from this Group using the &apos;Eject&apos; button in the Roles section &gt; Members 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
<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;Enrollment fee&apos;"
longdescription="Toggle &apos;Open Enrollment&apos; to let new Members join without an invitation, and change the &apos;Enrollment fee&apos; in the General section."
name="member options" value="3" />

View File

@ -3775,6 +3775,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>