diff options
25 files changed, 2694 insertions, 1244 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1c1e2ef9ef..ada34da275 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -232,6 +232,7 @@ set(viewer_SOURCE_FILES llfloatergesture.cpp llfloatergodtools.cpp llfloatergotoline.cpp + llfloatergroupbulkban.cpp llfloatergroupinvite.cpp llfloatergroups.cpp llfloaterhandler.cpp @@ -403,6 +404,8 @@ set(viewer_SOURCE_FILES llpanelface.cpp llpanelgenerictip.cpp llpanelgroup.cpp + llpanelgroupbulk.cpp + llpanelgroupbulkban.cpp llpanelgroupgeneral.cpp llpanelgroupinvite.cpp llpanelgrouplandmoney.cpp @@ -824,6 +827,7 @@ set(viewer_HEADER_FILES llfloatergesture.h llfloatergodtools.h llfloatergotoline.h + llfloatergroupbulkban.h llfloatergroupinvite.h llfloatergroups.h llfloaterhandler.h @@ -988,6 +992,9 @@ set(viewer_HEADER_FILES llpanelface.h llpanelgenerictip.h llpanelgroup.h + llpanelgroupbulk.h + llpanelgroupbulkimpl.h + llpanelgroupbulkban.h llpanelgroupgeneral.h llpanelgroupinvite.h llpanelgrouplandmoney.h diff --git a/indra/newview/llfloatergroupbulkban.cpp b/indra/newview/llfloatergroupbulkban.cpp new file mode 100644 index 0000000000..54a2283b13 --- /dev/null +++ b/indra/newview/llfloatergroupbulkban.cpp @@ -0,0 +1,134 @@ +/** +* @file llfloatergroupbulkban.cpp +* @brief Floater to ban Residents from a group. +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatergroupbulkban.h" +#include "llpanelgroupbulkban.h" +#include "lltrans.h" +#include "lldraghandle.h" + + +class LLFloaterGroupBulkBan::impl +{ +public: + impl(const LLUUID& group_id) : mGroupID(group_id), mBulkBanPanelp(NULL) {} + ~impl() {} + + static void closeFloater(void* data); + +public: + LLUUID mGroupID; + LLPanelGroupBulkBan* mBulkBanPanelp; + + static std::map<LLUUID, LLFloaterGroupBulkBan*> sInstances; +}; + +// +// Globals +// +std::map<LLUUID, LLFloaterGroupBulkBan*> LLFloaterGroupBulkBan::impl::sInstances; + +void LLFloaterGroupBulkBan::impl::closeFloater(void* data) +{ + LLFloaterGroupBulkBan* floaterp = (LLFloaterGroupBulkBan*)data; + if(floaterp) + floaterp->closeFloater(); +} + +//----------------------------------------------------------------------------- +// Implementation +//----------------------------------------------------------------------------- +LLFloaterGroupBulkBan::LLFloaterGroupBulkBan(const LLUUID& group_id/*=LLUUID::null*/) + : LLFloater(group_id) +{ + S32 floater_header_size = getHeaderHeight(); + LLRect contents; + + mImpl = new impl(group_id); + mImpl->mBulkBanPanelp = new LLPanelGroupBulkBan(group_id); + + contents = mImpl->mBulkBanPanelp->getRect(); + contents.mTop -= floater_header_size; + + setTitle(mImpl->mBulkBanPanelp->getString("GroupBulkBan")); + mImpl->mBulkBanPanelp->setCloseCallback(impl::closeFloater, this); + mImpl->mBulkBanPanelp->setRect(contents); + + addChild(mImpl->mBulkBanPanelp); +} + +LLFloaterGroupBulkBan::~LLFloaterGroupBulkBan() +{ + if(mImpl->mGroupID.notNull()) + { + impl::sInstances.erase(mImpl->mGroupID); + } + + delete mImpl->mBulkBanPanelp; + delete mImpl; +} + +void LLFloaterGroupBulkBan::showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids) +{ + const LLFloater::Params& floater_params = LLFloater::getDefaultParams(); + S32 floater_header_size = floater_params.header_height; + LLRect contents; + + // Make sure group_id isn't null + if (group_id.isNull()) + { + llwarns << "LLFloaterGroupInvite::showForGroup with null group_id!" << llendl; + return; + } + + // If we don't have a floater for this group, create one. + LLFloaterGroupBulkBan* fgb = get_if_there(impl::sInstances, + group_id, + (LLFloaterGroupBulkBan*)NULL); + if (!fgb) + { + fgb = new LLFloaterGroupBulkBan(group_id); + contents = fgb->mImpl->mBulkBanPanelp->getRect(); + contents.mTop += floater_header_size; + fgb->setRect(contents); + fgb->getDragHandle()->setRect(contents); + fgb->getDragHandle()->setTitle(fgb->mImpl->mBulkBanPanelp->getString("GroupBulkBan")); + + impl::sInstances[group_id] = fgb; + + fgb->mImpl->mBulkBanPanelp->clear(); + } + + if (agent_ids != NULL) + { + fgb->mImpl->mBulkBanPanelp->addUsers(*agent_ids); + } + + fgb->center(); + fgb->openFloater(); + fgb->mImpl->mBulkBanPanelp->update(); +} diff --git a/indra/newview/llfloatergroupbulkban.h b/indra/newview/llfloatergroupbulkban.h new file mode 100644 index 0000000000..5b680a1ba4 --- /dev/null +++ b/indra/newview/llfloatergroupbulkban.h @@ -0,0 +1,48 @@ +/** +* @file llfloatergroupbulkban.h +* @brief This floater is a wrapper for LLPanelGroupBulkBan, which +* is used to ban Residents from a specific group. +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLFLOATERGROUPBULKBAN_H +#define LL_LLFLOATERGROUPBULKBAN_H + +#include "llfloater.h" +#include "lluuid.h" + +class LLFloaterGroupBulkBan : public LLFloater +{ +public: + virtual ~LLFloaterGroupBulkBan(); + + static void showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids = NULL); + +protected: + LLFloaterGroupBulkBan(const LLUUID& group_id = LLUUID::null); + + class impl; + impl* mImpl; +}; + +#endif // LL_LLFLOATERGROUPBULKBAN_H diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 18cdc6ec6d..83ce2b0483 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -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() @@ -745,6 +745,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 // @@ -954,12 +968,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); } } @@ -1029,7 +1043,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); @@ -1106,12 +1120,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); } } @@ -1220,7 +1234,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) } } - group_datap->mRoleMemberDataComplete = TRUE; + group_datap->mRoleMemberDataComplete= true; group_datap->mRoleMembersRequestID.setNull(); } @@ -1844,6 +1858,121 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, // Responder class for capability group management +class GroupBanDataResponder : public LLHTTPClient::Responder +{ +public: + GroupBanDataResponder() {} + virtual ~GroupBanDataResponder() {} + virtual void result(const LLSD& pContent); + virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent); +}; + +void GroupBanDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +{ + LL_WARNS("GrpMgr") << "Error receiving group member data [status:" + << pStatus << "]: " << pContent << LL_ENDL; +} + +void GroupBanDataResponder::result(const LLSD& content) +{ + LLGroupMgr::processGroupBanRequest(content); +} + +void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type, + const LLUUID& group_id, + EBanRequestAction ban_action, /* = BAN_NO_ACTION */ + const std::vector<LLUUID> ban_list) /* = std::vector<LLUUID>() */ +{ + LLViewerRegion* currentRegion = gAgent.getRegion(); + if(!currentRegion) + { + LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL; + return; + } + + // Check to make sure we have our capabilities + if(!currentRegion->capabilitiesReceived()) + { + LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL; + return; + } + + // Get our capability + std::string cap_url = currentRegion->getCapability("GroupAPIv1"); + if(cap_url.empty()) + { + return; + } + cap_url += "?group_id=" + group_id.asString(); + + LLSD body = LLSD::emptyMap(); + body["ban_action"] = ban_action; + // Add our list of potential banned 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(); + switch(request_type) + { + case REQUEST_GET: + LLHTTPClient::get(cap_url, grp_ban_responder); + break; + case REQUEST_POST: + LLHTTPClient::post(cap_url, body, grp_ban_responder); + break; + case REQUEST_PUT: + case REQUEST_DEL: + break; + } +} + + +void LLGroupMgr::processGroupBanRequest(const LLSD& content) +{ + // Did we get anything in content? + if(!content.size()) + { + LL_WARNS("GrpMgr") << "No group member data received." << LL_ENDL; + return; + } + + LLUUID group_id = content["group_id"].asUUID(); + + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); + if (!gdatap) + return; + + LLSD::map_const_iterator i = content["ban_list"].beginMap(); + LLSD::map_const_iterator iEnd = content["ban_list"].endMap(); + for(;i != iEnd; ++i) + { + const LLUUID ban_id(i->first); + LLSD ban_entry(i->second); + + LLGroupBanData ban_data; + if(ban_entry.has("ban_date")) + { + ban_data.mBanDate = ban_entry["ban_date"].asDate(); + // TODO: Ban Reason + } + + gdatap->createBanEntry(ban_id, ban_data); + } + + gdatap->mChanged = TRUE; + LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST); +} + + + +// Responder class for capability group management class GroupMemberDataResponder : public LLHTTPClient::Responder { public: @@ -1928,7 +2057,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) @@ -2011,12 +2140,12 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id); - group_datap->mMemberDataComplete = TRUE; + group_datap->mMemberDataComplete = true; group_datap->mMemberRequestID.setNull(); // Make the role-member data request if (group_datap->mPendingRoleMemberRequest) { - group_datap->mPendingRoleMemberRequest = FALSE; + group_datap->mPendingRoleMemberRequest = false; LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id); } diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index d107fceb49..9e1c1eec90 100755 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -33,8 +33,10 @@ #include <string> #include <map> +// Forward Declarations class LLMessageSystem; - +class LLGroupRoleData; +class LLGroupMgr; enum LLGroupChange { @@ -43,6 +45,7 @@ enum LLGroupChange GC_ROLE_DATA, GC_ROLE_MEMBER_DATA, GC_TITLES, + GC_BANLIST, GC_ALL }; @@ -65,8 +68,6 @@ public: virtual void changed(const LLUUID& group_id, LLGroupChange gc) = 0; }; -class LLGroupRoleData; - class LLGroupMemberData { friend class LLGroupMgrGroupData; @@ -201,6 +202,17 @@ struct lluuid_pair_less } }; + +struct LLGroupBanData +{ + LLGroupBanData(): mBanDate() {} + ~LLGroupBanData() {} + + LLDate mBanDate; + // TODO: std:string ban_reason; +}; + + struct LLGroupTitle { std::string mTitle; @@ -208,8 +220,6 @@ struct LLGroupTitle BOOL mSelected; }; -class LLGroupMgr; - class LLGroupMgrGroupData { friend class LLGroupMgr; @@ -239,27 +249,36 @@ public: void recalcAllAgentPowers(); void recalcAgentPowers(const LLUUID& agent_id); - BOOL isMemberDataComplete() { return mMemberDataComplete; } - BOOL isRoleDataComplete() { return mRoleDataComplete; } - BOOL isRoleMemberDataComplete() { return mRoleMemberDataComplete; } - BOOL isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; } + bool isMemberDataComplete() { return mMemberDataComplete; } + bool isRoleDataComplete() { return mRoleDataComplete; } + bool isRoleMemberDataComplete() { return mRoleMemberDataComplete; } + bool isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; } F32 getAccessTime() const { return mAccessTime; } void setAccessed(); const LLUUID& getMemberVersion() const { return mMemberVersion; } + void clearBanList() { mBanList.clear(); } + void getBanList(const LLUUID& 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; @@ -290,12 +309,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 @@ -323,6 +342,22 @@ class LLGroupMgr : public LLSingleton<LLGroupMgr> LOG_CLASS(LLGroupMgr); public: + enum EBanRequestType + { + REQUEST_GET = 0, + REQUEST_POST, + REQUEST_PUT, + REQUEST_DEL + }; + + enum EBanRequestAction + { + BAN_NO_ACTION = 0, + BAN_CREATE = 1, + BAN_DELETE = 2 + }; + +public: LLGroupMgr(); ~LLGroupMgr(); @@ -355,8 +390,14 @@ public: static void sendGroupMemberInvites(const LLUUID& group_id, std::map<LLUUID,LLUUID>& role_member_pairs); static void sendGroupMemberEjects(const LLUUID& group_id, uuid_vec_t& member_ids); + + static void sendGroupBanRequest(EBanRequestType request_type, + const LLUUID& group_id, + EBanRequestAction ban_action = BAN_NO_ACTION, + const uuid_vec_t ban_list = uuid_vec_t()); + + static void processGroupBanRequest(const LLSD& content); - // BAKER void sendCapGroupMembersRequest(const LLUUID& group_id); static void processCapGroupMembersRequest(const LLSD& content); @@ -401,4 +442,3 @@ private: #endif - diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index b2a3a9f645..ba85aa7c9e 100755 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -65,7 +65,8 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p) mNameColumn(p.name_column.column_name), mAllowCallingCardDrop(p.allow_calling_card_drop), mShortNames(p.short_names), - mAvatarNameCacheConnection() + mAvatarNameCacheConnection(), + mPendingLookupsRemaining(0) {} // public @@ -335,6 +336,17 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( mAvatarNameCacheConnection.disconnect(); } mAvatarNameCacheConnection = LLAvatarNameCache::get(id,boost::bind(&LLNameListCtrl::onAvatarNameCache,this, _1, _2, item->getHandle())); + + if(mPendingLookupsRemaining <= 0) + { + // BAKER TODO: + // We might get into a state where mPendingLookupsRemaining might + // go negative. So just reset it right now and figure out if it's + // possible later :) + mPendingLookupsRemaining = 0; + mNameListCompleteSignal(false); + } + mPendingLookupsRemaining++; } break; } @@ -386,6 +398,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id) { selectNthItem(idx); // not sure whether this is needed, taken from previous implementation deleteSingleItem(idx); + + mPendingLookupsRemaining--; } } @@ -412,6 +426,23 @@ void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, } } + ////////////////////////////////////////////////////////////////////////// + // BAKER - FIX NameListCtrl + //if (mPendingLookupsRemaining <= 0) + { + // We might get into a state where mPendingLookupsRemaining might + // go negative. So just reset it right now and figure out if it's + // possible later :) + //mPendingLookupsRemaining = 0; + + mNameListCompleteSignal(true); + } + //else + { + // mPendingLookupsRemaining--; + } + ////////////////////////////////////////////////////////////////////////// + dirtyColumns(); } diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 92e82b672d..a3e17eb6df 100755 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -67,6 +67,7 @@ class LLNameListCtrl : public LLScrollListCtrl, public LLInstanceTracker<LLNameListCtrl> { public: + typedef boost::signals2::signal<void(bool)> namelist_complete_signal_t; typedef enum e_name_type { @@ -152,7 +153,7 @@ public: /*virtual*/ void updateColumns(bool force_update); - /*virtual*/ void mouseOverHighlightNthItem( S32 index ); + /*virtual*/ void mouseOverHighlightNthItem( S32 index ); private: void showInspector(const LLUUID& avatar_id, bool is_group); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, LLHandle<LLNameListItem> item); @@ -163,6 +164,16 @@ private: BOOL mAllowCallingCardDrop; bool mShortNames; // display name only, no SLID boost::signals2::connection mAvatarNameCacheConnection; + + S32 mPendingLookupsRemaining; + namelist_complete_signal_t mNameListCompleteSignal; + +public: + boost::signals2::connection setOnNameListCompleteCallback(boost::function<void(bool)> onNameListCompleteCallback) + { + return mNameListCompleteSignal.connect(onNameListCompleteCallback); + } + }; diff --git a/indra/newview/llpanelgroupbulk.cpp b/indra/newview/llpanelgroupbulk.cpp new file mode 100644 index 0000000000..1eafc5bd64 --- /dev/null +++ b/indra/newview/llpanelgroupbulk.cpp @@ -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); +} + diff --git a/indra/newview/llpanelgroupbulk.h b/indra/newview/llpanelgroupbulk.h new file mode 100644 index 0000000000..25ae71ab86 --- /dev/null +++ b/indra/newview/llpanelgroupbulk.h @@ -0,0 +1,74 @@ +/** +* @file llpanelgroupbulk.h +* @brief Header file for llpanelgroupbulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLPANELGROUPBULK_H +#define LL_LLPANELGROUPBULK_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLAvatarName; +class LLGroupMgrGroupData; +class LLPanelGroupBulkImpl; + +// Base panel class for bulk group invite / ban floaters +class LLPanelGroupBulk : public LLPanel +{ +public: + LLPanelGroupBulk(const LLUUID& group_id); + /*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 + diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp new file mode 100644 index 0000000000..5b9dc21f20 --- /dev/null +++ b/indra/newview/llpanelgroupbulkban.cpp @@ -0,0 +1,145 @@ +/** +* @file llpanelgroupbulkban.cpp +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelgroupbulkban.h" +#include "llpanelgroupbulk.h" +#include "llpanelgroupbulkimpl.h" + +#include "llagent.h" +#include "llavatarnamecache.h" +#include "llfloateravatarpicker.h" +#include "llbutton.h" +#include "llcallingcard.h" +#include "llcombobox.h" +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llnamelistctrl.h" +#include "llnotificationsutil.h" +#include "llscrolllistitem.h" +#include "llslurl.h" +#include "llspinctrl.h" +#include "lltextbox.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" + + +LLPanelGroupBulkBan::LLPanelGroupBulkBan(const LLUUID& group_id) : LLPanelGroupBulk(group_id) +{ + // Pass on construction of this panel to the control factory. + buildFromFile( "panel_group_bulk_ban.xml"); +} + +BOOL LLPanelGroupBulkBan::postBuild() +{ + BOOL recurse = TRUE; + + mImplementation->mLoadingText = getString("loading"); + mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse); + mImplementation->mBulkAgentList = getChild<LLNameListCtrl>("banned_agent_list", recurse); + if ( mImplementation->mBulkAgentList ) + { + mImplementation->mBulkAgentList->setCommitOnSelectionChange(TRUE); + mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation); + } + + LLButton* button = getChild<LLButton>("add_button", recurse); + if ( button ) + { + // default to opening avatarpicker automatically + // (*impl::callbackClickAdd)((void*)this); + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this); + } + + mImplementation->mRemoveButton = + getChild<LLButton>("remove_button", recurse); + if ( mImplementation->mRemoveButton ) + { + mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); + mImplementation->mRemoveButton->setEnabled(FALSE); + } + + mImplementation->mOKButton = + getChild<LLButton>("ban_button", recurse); + if ( mImplementation->mOKButton ) + { + mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this); + mImplementation->mOKButton->setEnabled(FALSE); + } + + button = getChild<LLButton>("cancel_button", recurse); + if ( button ) + { + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); + } + + mImplementation->mTooManySelected = getString("ban_selection_too_large"); + + update(); + return TRUE; +} + +// TODO: Refactor the shitty callback functions with void* -- just use boost::bind to call submit() instead. +void LLPanelGroupBulkBan::callbackClickSubmit(void* userdata) +{ + LLPanelGroupBulkBan* selfp = (LLPanelGroupBulkBan*)userdata; + + if(selfp) + selfp->submit(); +} + + +void LLPanelGroupBulkBan::submit() +{ + std::vector<LLUUID> banned_agent_list; + std::vector<LLScrollListItem*> agents = mImplementation->mBulkAgentList->getAllData(); + std::vector<LLScrollListItem*>::iterator iter = agents.begin(); + for(;iter != agents.end(); ++iter) + { + LLScrollListItem* agent = *iter; + banned_agent_list.push_back(agent->getUUID()); + } + + const S32 MAX_GROUP_BANS = 100; // Max invites per request. 100 to match server cap. + if (banned_agent_list.size() > MAX_GROUP_BANS) + { + // Fail! + LLSD msg; + msg["MESSAGE"] = mImplementation->mTooManySelected; + LLNotificationsUtil::add("GenericAlert", msg); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); + return; + } + + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mImplementation->mGroupID, LLGroupMgr::BAN_CREATE, banned_agent_list); + LLGroupMgr::getInstance()->sendGroupMemberEjects(mImplementation->mGroupID, banned_agent_list); + + //then close + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); +} + diff --git a/indra/newview/llpanelgroupbulkban.h b/indra/newview/llpanelgroupbulkban.h new file mode 100644 index 0000000000..0684f365a0 --- /dev/null +++ b/indra/newview/llpanelgroupbulkban.h @@ -0,0 +1,47 @@ +/** +* @file llpanelgroupbulkban.h +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLPANELGROUPBULKBAN_H +#define LL_LLPANELGROUPBULKBAN_H + +#include "llpanel.h" +#include "lluuid.h" +#include "llpanelgroupbulk.h" + +class LLAvatarName; + +class LLPanelGroupBulkBan : public LLPanelGroupBulk +{ +public: + LLPanelGroupBulkBan(const LLUUID& group_id); + ~LLPanelGroupBulkBan() {} + + virtual BOOL postBuild(); + + static void callbackClickSubmit(void* userdata); + virtual void submit(); +}; + +#endif // LL_LLPANELGROUPBULKBAN_H diff --git a/indra/newview/llpanelgroupbulkimpl.h b/indra/newview/llpanelgroupbulkimpl.h new file mode 100644 index 0000000000..0bc834d67e --- /dev/null +++ b/indra/newview/llpanelgroupbulkimpl.h @@ -0,0 +1,96 @@ +/** +* @file llpanelgroupbulkimpl.h +* @brief Class definition for implementation class of LLPanelGroupBulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLPANELGROUPBULKIMPL_H +#define LL_LLPANELGROUPBULKIMPL_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLAvatarName; +class LLNameListCtrl; +class LLTextBox; +class LLComboBox; + +////////////////////////////////////////////////////////////////////////// +// Implementation found in llpanelgroupbulk.cpp +////////////////////////////////////////////////////////////////////////// +class LLPanelGroupBulkImpl +{ +public: + LLPanelGroupBulkImpl(const LLUUID& group_id); + ~LLPanelGroupBulkImpl(); + + static void callbackClickAdd(void* userdata); + static void callbackClickRemove(void* userdata); + + static void callbackClickCancel(void* userdata); + + static void callbackSelect(LLUICtrl* ctrl, void* userdata); + static void callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data); + + static void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, void* user_data); + + void handleRemove(); + void handleSelection(); + + void addUsers(const std::vector<std::string>& names, const uuid_vec_t& agent_ids); + void setGroupName(std::string name); + + +public: + static const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap. + + + LLUUID mGroupID; + + LLNameListCtrl* mBulkAgentList; + LLButton* mOKButton; + LLButton* mRemoveButton; + LLTextBox* mGroupName; + + std::string mLoadingText; + std::string mTooManySelected; + + std::set<LLUUID> mInviteeIDs; + + void (*mCloseCallback)(void* data); + void* mCloseCallbackUserData; + boost::signals2::connection mAvatarNameCacheConnection; + + // The following are for the LLPanelGroupInvite subclass only. + // These aren't needed for LLPanelGroupBulkBan, but if we have to add another + // group bulk floater for some reason, we'll have these objects too. +public: + LLComboBox* mRoleNames; + std::string mOwnerWarning; + std::string mAlreadyInGroup; + bool mConfirmedOwnerInvite; + bool mListFullNotificationSent; +}; + +#endif // LL_LLPANELGROUPBULKIMPL_H + diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index dd13e8abf4..48736be253 100755 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -26,6 +26,8 @@ #include "llviewerprecompiledheaders.h" #include "llpanelgroupinvite.h" +#include "llpanelgroupbulk.h" +#include "llpanelgroupbulkimpl.h" #include "llagent.h" #include "llavatarnamecache.h" @@ -45,203 +47,221 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" -class LLPanelGroupInvite::impl + +bool invite_owner_callback(LLHandle<LLPanel> panel_handle, const LLSD& notification, const LLSD& response) { -public: - impl(const LLUUID& group_id); - ~impl(); - - void addUsers(const std::vector<std::string>& names, - const uuid_vec_t& agent_ids); - void submitInvitations(); - void addRoleNames(LLGroupMgrGroupData* gdatap); - void handleRemove(); - void handleSelection(); - - static void callbackClickCancel(void* userdata); - static void callbackClickOK(void* userdata); - static void callbackClickAdd(void* userdata); - static void callbackClickRemove(void* userdata); - static void callbackSelect(LLUICtrl* ctrl, void* userdata); - static void callbackAddUsers(const uuid_vec_t& agent_ids, - void* user_data); - - static void onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name, - void* user_data); - - bool inviteOwnerCallback(const LLSD& notification, const LLSD& response); - -public: - LLUUID mGroupID; - - std::string mLoadingText; - LLNameListCtrl *mInvitees; - LLComboBox *mRoleNames; - LLButton *mOKButton; - LLButton *mRemoveButton; - LLTextBox *mGroupName; - std::string mOwnerWarning; - std::string mAlreadyInGroup; - std::string mTooManySelected; - bool mConfirmedOwnerInvite; - std::set<LLUUID> mInviteeIDs; - - void (*mCloseCallback)(void* data); - - void* mCloseCallbackUserData; - - boost::signals2::connection mAvatarNameCacheConnection; -}; - - -LLPanelGroupInvite::impl::impl(const LLUUID& group_id): - mGroupID( group_id ), - mLoadingText (), - mInvitees ( NULL ), - mRoleNames( NULL ), - mOKButton ( NULL ), - mRemoveButton( NULL ), - mGroupName( NULL ), - mConfirmedOwnerInvite( false ), - mCloseCallback( NULL ), - mCloseCallbackUserData( NULL ), - mAvatarNameCacheConnection() + LLPanelGroupInvite* panel = dynamic_cast<LLPanelGroupInvite*>(panel_handle.get()); + if(!panel) + return false; + + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: + // user confirmed that they really want a new group owner + panel->mImplementation->mConfirmedOwnerInvite = true; + panel->submit(); + break; + case 1: + // fall through + default: + break; + } + return false; +} + + +LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id) : LLPanelGroupBulk(group_id) { + // Pass on construction of this panel to the control factory. + buildFromFile( "panel_group_invite.xml"); } -LLPanelGroupInvite::impl::~impl() +void LLPanelGroupInvite::clear() { - if (mAvatarNameCacheConnection.connected()) + LLPanelGroupBulk::clear(); + + if(mImplementation->mRoleNames) { - mAvatarNameCacheConnection.disconnect(); + mImplementation->mRoleNames->clear(); + mImplementation->mRoleNames->removeall(); + mImplementation->mRoleNames->setCurrentByID(LLUUID::null); } } -const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap. +void LLPanelGroupInvite::update() +{ + LLPanelGroupBulk::update(); + + if(mImplementation->mRoleNames) + { + LLUUID store_selected_role = mImplementation->mRoleNames->getCurrentID(); + mImplementation->mRoleNames->clear(); + mImplementation->mRoleNames->removeall(); + mImplementation->mRoleNames->setCurrentByID(LLUUID::null); + + if(!mPendingRoleDataUpdate && !mPendingMemberDataUpdate) + { + ////////////////////////////////////////////////////////////////////////// + // Add role names + addRoleNames(); + //////////////////////////////////////////////////////////////////////////// + mImplementation->mRoleNames->setCurrentByID(store_selected_role); + } + else + { + mImplementation->mRoleNames->add(mImplementation->mLoadingText, LLUUID::null, ADD_BOTTOM); + } + + } +} -void LLPanelGroupInvite::impl::addUsers(const std::vector<std::string>& names, - const uuid_vec_t& agent_ids) +BOOL LLPanelGroupInvite::postBuild() { - std::string name; - LLUUID id; + BOOL recurse = TRUE; - if (names.size() + mInviteeIDs.size() > MAX_GROUP_INVITES) + mImplementation->mLoadingText = getString("loading"); + mImplementation->mRoleNames = getChild<LLComboBox>("role_name", + recurse); + mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse); + mImplementation->mBulkAgentList = getChild<LLNameListCtrl>("invitee_list", recurse); + if ( mImplementation->mBulkAgentList ) { - // Fail! Show a warning and don't add any names. - LLSD msg; - msg["MESSAGE"] = mTooManySelected; - LLNotificationsUtil::add("GenericAlert", msg); - return; + mImplementation->mBulkAgentList->setCommitOnSelectionChange(TRUE); + mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation); } - for (S32 i = 0; i < (S32)names.size(); i++) + LLButton* button = getChild<LLButton>("add_button", recurse); + if ( button ) { - name = names[i]; - id = agent_ids[i]; + // default to opening avatarpicker automatically + // (*impl::callbackClickAdd)((void*)this); + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this); + } - // Make sure this agent isn't already in the list. - if (mInviteeIDs.find(id) != mInviteeIDs.end()) - { - continue; - } + mImplementation->mRemoveButton = + getChild<LLButton>("remove_button", recurse); + if ( mImplementation->mRemoveButton ) + { + mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); + mImplementation->mRemoveButton->setEnabled(FALSE); + } - //add the name to the names list - LLSD row; - row["id"] = id; - row["columns"][0]["value"] = name; + mImplementation->mOKButton = getChild<LLButton>("invite_button", recurse); + if ( mImplementation->mOKButton ) + { + mImplementation->mOKButton->setClickedCallback(LLPanelGroupInvite::callbackClickSubmit, this); + mImplementation->mOKButton->setEnabled(FALSE); + } - mInvitees->addElement(row); - mInviteeIDs.insert(id); + button = getChild<LLButton>("cancel_button", recurse); + if ( button ) + { + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); } + + mImplementation->mOwnerWarning = getString("confirm_invite_owner_str"); + mImplementation->mAlreadyInGroup = getString("already_in_group"); + mImplementation->mTooManySelected = getString("invite_selection_too_large"); + + update(); + + return (mImplementation->mRoleNames && + mImplementation->mBulkAgentList && + mImplementation->mRemoveButton); +} + +void LLPanelGroupInvite::callbackClickSubmit(void* userdata) +{ + LLPanelGroupInvite* selfp = (LLPanelGroupInvite*)userdata; + + if(selfp) + selfp->submit(); } -void LLPanelGroupInvite::impl::submitInvitations() +void LLPanelGroupInvite::submit() { std::map<LLUUID, LLUUID> role_member_pairs; - LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + if(!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mImplementation->mGroupID << LL_ENDL; + return; + } // Default to everyone role. LLUUID role_id = LLUUID::null; - if (mRoleNames) + if (mImplementation->mRoleNames) { - role_id = mRoleNames->getCurrentID(); - + role_id = mImplementation->mRoleNames->getCurrentID(); + + //LLUUID t_ownerUUID = gdatap->mOwnerRole; + //bool t_confirmInvite = mImplementation->mConfirmedOwnerInvite; + // owner role: display confirmation and wait for callback - if ((role_id == gdatap->mOwnerRole) && (!mConfirmedOwnerInvite)) + if ((role_id == gdatap->mOwnerRole) && (!mImplementation->mConfirmedOwnerInvite)) { LLSD args; - args["MESSAGE"] = mOwnerWarning; - LLNotificationsUtil::add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupInvite::impl::inviteOwnerCallback, this, _1, _2)); + args["MESSAGE"] = mImplementation->mOwnerWarning; + LLNotificationsUtil::add( "GenericAlertYesCancel", + args, + LLSD(), + boost::bind(invite_owner_callback, + this->getHandle(), + _1, _2)); return; // we'll be called again if user confirms } } bool already_in_group = false; //loop over the users - std::vector<LLScrollListItem*> items = mInvitees->getAllData(); + std::vector<LLScrollListItem*> items = mImplementation->mBulkAgentList->getAllData(); for (std::vector<LLScrollListItem*>::iterator iter = items.begin(); - iter != items.end(); ++iter) + iter != items.end(); ++iter) { LLScrollListItem* item = *iter; - if(LLGroupActions::isAvatarMemberOfGroup(mGroupID, item->getUUID())) + if(LLGroupActions::isAvatarMemberOfGroup(mImplementation->mGroupID, item->getUUID())) { already_in_group = true; continue; } role_member_pairs[item->getUUID()] = role_id; } - - if (role_member_pairs.size() > MAX_GROUP_INVITES) + + if (role_member_pairs.size() > LLPanelGroupBulkImpl::MAX_GROUP_INVITES) { // Fail! LLSD msg; - msg["MESSAGE"] = mTooManySelected; + msg["MESSAGE"] = mImplementation->mTooManySelected; LLNotificationsUtil::add("GenericAlert", msg); - (*mCloseCallback)(mCloseCallbackUserData); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); return; } - LLGroupMgr::getInstance()->sendGroupMemberInvites(mGroupID, role_member_pairs); - + LLGroupMgr::getInstance()->sendGroupMemberInvites(mImplementation->mGroupID, role_member_pairs); + if(already_in_group) { LLSD msg; - msg["MESSAGE"] = mAlreadyInGroup; + msg["MESSAGE"] = mImplementation->mAlreadyInGroup; LLNotificationsUtil::add("GenericAlert", msg); } //then close - (*mCloseCallback)(mCloseCallbackUserData); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); } -bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification, const LLSD& response) +void LLPanelGroupInvite::addRoleNames() { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - switch(option) + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + if(!gdatap) { - case 0: - // user confirmed that they really want a new group owner - mConfirmedOwnerInvite = true; - submitInvitations(); - break; - case 1: - // fall through - default: - break; + return; } - return false; -} - - -void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap) -{ - LLGroupMgrGroupData::member_list_t::iterator agent_iter = - gdatap->mMembers.find(gAgent.getID()); + LLGroupMgrGroupData::member_list_t::iterator agent_iter = gdatap->mMembers.find(gAgent.getID()); //get the member data for the agent if it exists if ( agent_iter != gdatap->mMembers.end() ) @@ -251,7 +271,7 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap) //loop over the agent's roles in the group //then add those roles to the list of roles that the agent //can invite people to be - if ( member_data && mRoleNames) + if ( member_data && mImplementation->mRoleNames) { //if the user is the owner then we add //all of the roles in the group @@ -261,10 +281,10 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap) //we add every role the user is in //else we just add to everyone bool is_owner = member_data->isInRole(gdatap->mOwnerRole); - bool can_assign_any = gAgent.hasPowerInGroup(mGroupID, - GP_ROLE_ASSIGN_MEMBER); - bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID, - GP_ROLE_ASSIGN_MEMBER_LIMITED); + bool can_assign_any = gAgent.hasPowerInGroup(mImplementation->mGroupID, + GP_ROLE_ASSIGN_MEMBER); + bool can_assign_limited = gAgent.hasPowerInGroup(mImplementation->mGroupID, + GP_ROLE_ASSIGN_MEMBER_LIMITED); LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin(); LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); @@ -279,401 +299,18 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap) // Owners can add any role. if ( is_owner // Even 'can_assign_any' can't add owner role. - || (can_assign_any && role_id != gdatap->mOwnerRole) + || (can_assign_any && role_id != gdatap->mOwnerRole) // Add all roles user is in - || (can_assign_limited && member_data->isInRole(role_id)) + || (can_assign_limited && member_data->isInRole(role_id)) // Everyone role. - || role_id == LLUUID::null ) + || role_id == LLUUID::null ) { - mRoleNames->add(rd.mRoleName, - role_id, - ADD_BOTTOM); + mImplementation->mRoleNames->add(rd.mRoleName, + role_id, + ADD_BOTTOM); } } } }//end if member data is not null }//end if agent is in the group } - -//static -void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata) -{ - LLPanelGroupInvite* panelp = (LLPanelGroupInvite*) userdata; - - if ( panelp ) - { - //Right now this is hard coded with some knowledge that it is part - //of a floater since the avatar picker needs to be added as a dependent - //floater to the parent floater. - //Soon the avatar picker will be embedded into this panel - //instead of being it's own separate floater. But that is next week. - //This will do for now. -jwolk May 10, 2006 - LLView * button = panelp->findChild<LLButton>("add_button"); - LLFloater * root_floater = gFloaterView->getParentFloater(panelp); - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( - boost::bind(impl::callbackAddUsers, _1, panelp->mImplementation), TRUE, FALSE, FALSE, root_floater->getName(), button); - if (picker) - { - root_floater->addDependentFloater(picker); - } - } -} - -//static -void LLPanelGroupInvite::impl::callbackClickRemove(void* userdata) -{ - impl* selfp = (impl*) userdata; - - if ( selfp ) selfp->handleRemove(); -} - -void LLPanelGroupInvite::impl::handleRemove() -{ - // Check if there is anything selected. - std::vector<LLScrollListItem*> selection = - mInvitees->getAllSelected(); - if (selection.empty()) return; - - std::vector<LLScrollListItem*>::iterator iter; - for(iter = selection.begin(); iter != selection.end(); ++iter) - { - mInviteeIDs.erase( (*iter)->getUUID() ); - } - - // Remove all selected invitees. - mInvitees->deleteSelectedItems(); - mRemoveButton->setEnabled(FALSE); -} - -// static -void LLPanelGroupInvite::impl::callbackSelect( - LLUICtrl* ctrl, void* userdata) -{ - impl* selfp = (impl*) userdata; - if ( selfp ) selfp->handleSelection(); -} - -void LLPanelGroupInvite::impl::handleSelection() -{ - // Check if there is anything selected. - std::vector<LLScrollListItem*> selection = - mInvitees->getAllSelected(); - if (selection.empty()) - { - mRemoveButton->setEnabled(FALSE); - } - else - { - mRemoveButton->setEnabled(TRUE); - } -} - -void LLPanelGroupInvite::impl::callbackClickCancel(void* userdata) -{ - impl* selfp = (impl*) userdata; - - if ( selfp ) - { - (*(selfp->mCloseCallback))(selfp->mCloseCallbackUserData); - } -} - -void LLPanelGroupInvite::impl::callbackClickOK(void* userdata) -{ - impl* selfp = (impl*) userdata; - - if ( selfp ) selfp->submitInvitations(); -} - - - -//static -void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data) -{ - std::vector<std::string> names; - for (S32 i = 0; i < (S32)agent_ids.size(); i++) - { - LLAvatarName av_name; - if (LLAvatarNameCache::get(agent_ids[i], &av_name)) - { - LLPanelGroupInvite::impl::onAvatarNameCache(agent_ids[i], av_name, user_data); - } - else - { - impl* selfp = (impl*) user_data; - if (selfp) - { - if (selfp->mAvatarNameCacheConnection.connected()) - { - selfp->mAvatarNameCacheConnection.disconnect(); - } - // *TODO : Add a callback per avatar name being fetched. - selfp->mAvatarNameCacheConnection = LLAvatarNameCache::get(agent_ids[i],boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, _1, _2, user_data)); - } - } - } - -} - -void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id, - const LLAvatarName& av_name, - void* user_data) -{ - impl* selfp = (impl*) user_data; - - if (selfp) - { - if (selfp->mAvatarNameCacheConnection.connected()) - { - selfp->mAvatarNameCacheConnection.disconnect(); - } - std::vector<std::string> names; - uuid_vec_t agent_ids; - agent_ids.push_back(agent_id); - names.push_back(av_name.getCompleteName()); - - selfp->addUsers(names, agent_ids); - } -} - - -LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id) - : LLPanel(), - mImplementation(new impl(group_id)), - mPendingUpdate(FALSE) -{ - // Pass on construction of this panel to the control factory. - buildFromFile( "panel_group_invite.xml"); -} - -LLPanelGroupInvite::~LLPanelGroupInvite() -{ - delete mImplementation; -} - -void LLPanelGroupInvite::setCloseCallback(void (*close_callback)(void*), - void* data) -{ - mImplementation->mCloseCallback = close_callback; - mImplementation->mCloseCallbackUserData = data; -} - -void LLPanelGroupInvite::clear() -{ - mStoreSelected = LLUUID::null; - mImplementation->mInvitees->deleteAllItems(); - mImplementation->mRoleNames->clear(); - mImplementation->mRoleNames->removeall(); - mImplementation->mOKButton->setEnabled(FALSE); - mImplementation->mInviteeIDs.clear(); -} - -void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids) -{ - std::vector<std::string> names; - for (S32 i = 0; i < (S32)agent_ids.size(); i++) - { - std::string fullname; - LLUUID agent_id = agent_ids[i]; - LLViewerObject* dest = gObjectList.findObject(agent_id); - if(dest && dest->isAvatar()) - { - LLNameValue* nvfirst = dest->getNVPair("FirstName"); - LLNameValue* nvlast = dest->getNVPair("LastName"); - if(nvfirst && nvlast) - { - fullname = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - - } - if (!fullname.empty()) - { - names.push_back(fullname); - } - else - { - LL_WARNS() << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << LL_ENDL; - names.push_back("(Unknown)"); - } - } - else - { - //looks like user try to invite offline friend - //for offline avatar_id gObjectList.findObject() will return null - //so we need to do this additional search in avatar tracker, see EXT-4732 - if (LLAvatarTracker::instance().isBuddy(agent_id)) - { - LLAvatarName av_name; - if (!LLAvatarNameCache::get(agent_id, &av_name)) - { - // actually it should happen, just in case - //LLAvatarNameCache::get(LLUUID(agent_id), boost::bind(&LLPanelGroupInvite::addUserCallback, this, _1, _2)); - // for this special case! - //when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence - // removed id will be added in callback - agent_ids.erase(agent_ids.begin() + i); - } - else - { - names.push_back(av_name.getAccountName()); - } - } - } - } - mImplementation->addUsers(names, agent_ids); -} - -void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const LLAvatarName& av_name) -{ - std::vector<std::string> names; - uuid_vec_t agent_ids; - agent_ids.push_back(id); - names.push_back(av_name.getAccountName()); - - mImplementation->addUsers(names, agent_ids); -} - -void LLPanelGroupInvite::draw() -{ - LLPanel::draw(); - if (mPendingUpdate) - { - updateLists(); - } -} - -void LLPanelGroupInvite::update() -{ - mPendingUpdate = FALSE; - if (mImplementation->mGroupName) - { - mImplementation->mGroupName->setText(mImplementation->mLoadingText); - } - if ( mImplementation->mRoleNames ) - { - mStoreSelected = mImplementation->mRoleNames->getCurrentID(); - mImplementation->mRoleNames->clear(); - mImplementation->mRoleNames->removeall(); - mImplementation->mRoleNames->add(mImplementation->mLoadingText, LLUUID::null, ADD_BOTTOM); - mImplementation->mRoleNames->setCurrentByID(LLUUID::null); - } - - updateLists(); -} - -void LLPanelGroupInvite::updateLists() -{ - LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); - bool waiting = false; - - if (gdatap) - { - if (gdatap->isGroupPropertiesDataComplete()) - { - if (mImplementation->mGroupName) - { - mImplementation->mGroupName->setText(gdatap->mName); - } - } - else - { - waiting = true; - } - if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()) - { - if ( mImplementation->mRoleNames ) - { - mImplementation->mRoleNames->clear(); - mImplementation->mRoleNames->removeall(); - - //add the role names and select the everybody role by default - mImplementation->addRoleNames(gdatap); - mImplementation->mRoleNames->setCurrentByID(mStoreSelected); - } - } - else - { - waiting = true; - } - } - else - { - waiting = true; - } - - if (waiting) - { - if (!mPendingUpdate) - { - LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID); - LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID); - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID); - } - mPendingUpdate = TRUE; - } - else - { - mPendingUpdate = FALSE; - if (mImplementation->mOKButton && mImplementation->mRoleNames->getItemCount()) - { - mImplementation->mOKButton->setEnabled(TRUE); - } - } -} - -BOOL LLPanelGroupInvite::postBuild() -{ - BOOL recurse = TRUE; - - mImplementation->mLoadingText = getString("loading"); - mImplementation->mRoleNames = getChild<LLComboBox>("role_name", - recurse); - mImplementation->mGroupName = getChild<LLTextBox>("group_name_text", recurse); - mImplementation->mInvitees = - getChild<LLNameListCtrl>("invitee_list", recurse); - if ( mImplementation->mInvitees ) - { - mImplementation->mInvitees->setCommitOnSelectionChange(TRUE); - mImplementation->mInvitees->setCommitCallback(impl::callbackSelect, mImplementation); - } - - LLButton* button = getChild<LLButton>("add_button", recurse); - if ( button ) - { - // default to opening avatarpicker automatically - // (*impl::callbackClickAdd)((void*)this); - button->setClickedCallback(impl::callbackClickAdd, this); - } - - mImplementation->mRemoveButton = - getChild<LLButton>("remove_button", recurse); - if ( mImplementation->mRemoveButton ) - { - mImplementation->mRemoveButton->setClickedCallback(impl::callbackClickRemove, mImplementation); - mImplementation->mRemoveButton->setEnabled(FALSE); - } - - mImplementation->mOKButton = - getChild<LLButton>("ok_button", recurse); - if ( mImplementation->mOKButton ) - { - mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation); - mImplementation->mOKButton->setEnabled(FALSE); - } - - button = getChild<LLButton>("cancel_button", recurse); - if ( button ) - { - button->setClickedCallback(impl::callbackClickCancel, mImplementation); - } - - mImplementation->mOwnerWarning = getString("confirm_invite_owner_str"); - mImplementation->mAlreadyInGroup = getString("already_in_group"); - mImplementation->mTooManySelected = getString("invite_selection_too_large"); - - update(); - - return (mImplementation->mRoleNames && - mImplementation->mInvitees && - mImplementation->mRemoveButton); -} diff --git a/indra/newview/llpanelgroupinvite.h b/indra/newview/llpanelgroupinvite.h index 9f7b5ae9be..b87a5883b8 100755 --- a/indra/newview/llpanelgroupinvite.h +++ b/indra/newview/llpanelgroupinvite.h @@ -27,36 +27,27 @@ #define LL_LLPANELGROUPINVITE_H #include "llpanel.h" +#include "llpanelgroupbulk.h" #include "lluuid.h" class LLAvatarName; -class LLPanelGroupInvite -: public LLPanel +class LLPanelGroupInvite : public LLPanelGroupBulk { public: LLPanelGroupInvite(const LLUUID& group_id); - ~LLPanelGroupInvite(); + ~LLPanelGroupInvite() {}; - void addUsers(uuid_vec_t& agent_ids); - /** - * this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers(). - */ - void addUserCallback(const LLUUID& id, const LLAvatarName& av_name); - void clear(); - void update(); + virtual void clear(); + virtual void update(); - void setCloseCallback(void (*close_callback)(void*), void* data); - - virtual void draw(); virtual BOOL postBuild(); -protected: - class impl; - impl* mImplementation; - BOOL mPendingUpdate; - LLUUID mStoreSelected; - void updateLists(); + static void callbackClickSubmit(void* userdata); + virtual void submit(); + +private: + void addRoleNames(); }; #endif diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 61fa4ea959..2dc38f8479 100755 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpanelgrouproles.cpp * @brief Panel for roles information about a particular group. * @@ -32,6 +32,7 @@ #include "llavatarnamecache.h" #include "llbutton.h" #include "llfiltereditor.h" +#include "llfloatergroupbulkban.h" #include "llfloatergroupinvite.h" #include "llavataractions.h" #include "lliconctrl.h" @@ -109,8 +110,10 @@ bool agentCanAddToRole(const LLUUID& group_id, return false; } -// static +// LLPanelGroupRoles ///////////////////////////////////////////////////// + +// static LLPanelGroupRoles::LLPanelGroupRoles() : LLPanelGroupTab(), mCurrentTab(NULL), @@ -297,7 +300,6 @@ bool LLPanelGroupRoles::onModalClose(const LLSD& notification, const LLSD& respo return false; } - bool LLPanelGroupRoles::apply(std::string& mesg) { // Pass this along to the currently visible sub tab. @@ -334,7 +336,6 @@ void LLPanelGroupRoles::update(LLGroupChange gc) { if (mGroupID.isNull()) return; - LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (panelp) { @@ -351,39 +352,33 @@ void LLPanelGroupRoles::activate() { // Start requesting member and role data if needed. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); - //if (!gdatap || mFirstUse) + if (!gdatap || !gdatap->isMemberDataComplete() ) { - // Check member data. - - if (!gdatap || !gdatap->isMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } - - // Check role data. - if (!gdatap || !gdatap->isRoleDataComplete() ) - { - // Mildly hackish - clear all pending changes - cancel(); + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + } - LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); - } + if (!gdatap || !gdatap->isRoleDataComplete() ) + { + // Mildly hackish - clear all pending changes + cancel(); - // Check role-member mapping data. - if (!gdatap || !gdatap->isRoleMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); - } + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); + } - // Need this to get base group member powers - if (!gdatap || !gdatap->isGroupPropertiesDataComplete() ) - { - LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); - } + // Check role-member mapping data. + if (!gdatap || !gdatap->isRoleMemberDataComplete() ) + { + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + } - mFirstUse = FALSE; + // Need this to get base group member powers + if (!gdatap || !gdatap->isGroupPropertiesDataComplete() ) + { + LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); } + mFirstUse = FALSE; + LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (panelp) panelp->activate(); } @@ -412,15 +407,38 @@ BOOL LLPanelGroupRoles::hasModal() return panelp->hasModal(); } +void LLPanelGroupRoles::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); -//////////////////////////// -// LLPanelGroupSubTab -//////////////////////////// + LLPanelGroupMembersSubTab* group_members_tab = findChild<LLPanelGroupMembersSubTab>("members_sub_tab"); + LLPanelGroupRolesSubTab* group_roles_tab = findChild<LLPanelGroupRolesSubTab>("roles_sub_tab"); + LLPanelGroupActionsSubTab* group_actions_tab = findChild<LLPanelGroupActionsSubTab>("actions_sub_tab"); + LLPanelGroupBanListSubTab* group_ban_tab = findChild<LLPanelGroupBanListSubTab>("banlist_sub_tab"); + + if(group_members_tab) group_members_tab->setGroupID(id); + if(group_roles_tab) group_roles_tab->setGroupID(id); + if(group_actions_tab) group_actions_tab->setGroupID(id); + if(group_ban_tab) group_ban_tab->setGroupID(id); + + LLButton* button = getChild<LLButton>("member_invite"); + if ( button ) + button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); + + if(mSubTabContainer) + mSubTabContainer->selectTab(0); + + activate(); +} + + +// LLPanelGroupSubTab //////////////////////////////////////////////////// LLPanelGroupSubTab::LLPanelGroupSubTab() : LLPanelGroupTab(), mHeader(NULL), mFooter(NULL), mActivated(false), + mHasGroupBanPower(false), mSearchEditor(NULL) { } @@ -542,9 +560,10 @@ void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl, return; } + mHasGroupBanPower = false; + std::vector<LLRoleActionSet*>::iterator ras_it = LLGroupMgr::getInstance()->mRoleActionSets.begin(); std::vector<LLRoleActionSet*>::iterator ras_end = LLGroupMgr::getInstance()->mRoleActionSets.end(); - for ( ; ras_it != ras_end; ++ras_it) { buildActionCategory(ctrl, @@ -674,6 +693,31 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, row["columns"][column_index]["value"] = (*ra_it)->mDescription; row["columns"][column_index]["font"] = "SANSSERIF_SMALL"; + if(mHasGroupBanPower) + { + // The ban ability is being set. Prevent these abilities from being manipulated + if((*ra_it)->mPowerBit == GP_MEMBER_EJECT) + { + row["enabled"] = false; + } + else if((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + row["enabled"] = false; + } + } + else + { + // The ban ability is not set. Allow these abilities to be manipulated + if((*ra_it)->mPowerBit == GP_MEMBER_EJECT) + { + row["enabled"] = true; + } + else if((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + row["enabled"] = true; + } + } + LLScrollListItem* item = ctrl->addElement(row, ADD_BOTTOM, (*ra_it)); if (-1 != check_box_index) @@ -709,6 +753,15 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, check->setTentative(TRUE); } } + + // Regardless of whether or not this ability is allowed by all or some, we want to prevent + // the group managers from accidentally disabling either of the two additional abilities + // tied with GP_GROUP_BAN_ACCESS. + if( (allowed_by_all & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS || + (allowed_by_some & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS) + { + mHasGroupBanPower = true; + } } } @@ -728,11 +781,8 @@ void LLPanelGroupSubTab::setFooterEnabled(BOOL enable) } } -//////////////////////////// -// LLPanelGroupMembersSubTab -//////////////////////////// - +// LLPanelGroupMembersSubTab ///////////////////////////////////////////// static LLPanelInjector<LLPanelGroupMembersSubTab> t_panel_group_members_subtab("panel_group_members_subtab"); LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab() @@ -810,6 +860,13 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) mEjectBtn->setEnabled(FALSE); } + mBanBtn = parent->getChild<LLButton>("member_ban", recurse); + if(mBanBtn) + { + mBanBtn->setClickedCallback(onBanMember, this); + mBanBtn->setEnabled(FALSE); + } + return TRUE; } @@ -823,34 +880,6 @@ void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id) LLPanelGroupSubTab::setGroupID(id); } -void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id) -{ - if(mRolesList) mRolesList->deleteAllItems(); - if(mAssignedMembersList) mAssignedMembersList->deleteAllItems(); - if(mAllowedActionsList) mAllowedActionsList->deleteAllItems(); - - if(mRoleName) mRoleName->clear(); - if(mRoleDescription) mRoleDescription->clear(); - if(mRoleTitle) mRoleTitle->clear(); - - mHasRoleChange = FALSE; - - setFooterEnabled(FALSE); - - LLPanelGroupSubTab::setGroupID(id); -} -void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id) -{ - if(mActionList) mActionList->deleteAllItems(); - if(mActionRoles) mActionRoles->deleteAllItems(); - if(mActionMembers) mActionMembers->deleteAllItems(); - - if(mActionDescription) mActionDescription->clear(); - - LLPanelGroupSubTab::setGroupID(id); -} - - // static void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data) { @@ -879,7 +908,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() // Build a vector of all selected members, and gather allowed actions. uuid_vec_t selected_members; - U64 allowed_by_all = 0xffffffffffffLL; + U64 allowed_by_all = GP_ALL_POWERS; //0xFFFFffffFFFFffffLL; U64 allowed_by_some = 0; std::vector<LLScrollListItem*>::iterator itor; @@ -916,8 +945,8 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() LLGroupMgrGroupData::role_list_t::iterator iter = gdatap->mRoles.begin(); LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); - BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID, - GP_MEMBER_EJECT); + BOOL can_ban_members = gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS); + BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT); BOOL member_is_owner = FALSE; for( ; iter != end; ++iter) @@ -964,6 +993,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() { // Can't remove other owners. cb_enable = FALSE; + can_ban_members = FALSE; break; } } @@ -983,14 +1013,14 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() } // If anyone selected is in any role besides 'Everyone' then they can't be ejected. - if (role_id.notNull() && (count > 0)) - { + if (role_id.notNull() && (count > 0)) + { can_eject_members = FALSE; - if (role_id == gdatap->mOwnerRole) - { - member_is_owner = TRUE; - } - } + if (role_id == gdatap->mOwnerRole) + { + member_is_owner = TRUE; + } + } LLRoleData rd; if (gdatap->getRoleData(role_id,rd)) @@ -1047,7 +1077,10 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() mAssignedRolesList->setEnabled(TRUE); if (gAgent.isGodlike()) + { can_eject_members = TRUE; + // can_ban_members = TRUE; + } if (!can_eject_members && !member_is_owner) { @@ -1060,10 +1093,41 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() if ( member_data && member_data->isInRole(gdatap->mOwnerRole) ) { can_eject_members = TRUE; + //can_ban_members = TRUE; } } + } + // ... or we can eject them because we have all the requisite powers... + if( gAgent.hasPowerInGroup(mGroupID, GP_ROLE_REMOVE_MEMBER) && + !member_is_owner) + { + if( gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT)) + { + can_eject_members = TRUE; + } + + if( gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + can_ban_members = TRUE; + } + } + + + uuid_vec_t::const_iterator member_iter = selected_members.begin(); + uuid_vec_t::const_iterator member_end = selected_members.end(); + for ( ; member_iter != member_end; ++member_iter) + { + // Don't count the agent. + if ((*member_iter) == gAgent.getID()) + { + can_eject_members = FALSE; + can_ban_members = FALSE; + } + } + + mBanBtn->setEnabled(can_ban_members); mEjectBtn->setEnabled(can_eject_members); } @@ -1101,61 +1165,26 @@ void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata) } void LLPanelGroupMembersSubTab::handleEjectMembers() -{ +{ + //send down an eject message + uuid_vec_t selected_members; + std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); if (selection.empty()) return; - - S32 selection_count = selection.size(); - if (selection_count == 1) - { - LLSD args; - LLUUID selected_avatar = mMembersList->getValue().asUUID(); - std::string fullname = LLSLURL("agent", selected_avatar, "inspect").getSLURLString(); - args["AVATAR_NAME"] = fullname; - LLSD payload; - LLNotificationsUtil::add("EjectGroupMemberWarning", - args, - payload, - boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2)); - } - else - { - LLSD args; - args["COUNT"] = llformat("%d", selection_count); - LLSD payload; - LLNotificationsUtil::add("EjectGroupMembersWarning", - args, - payload, - boost::bind(&LLPanelGroupMembersSubTab::handleEjectCallback, this, _1, _2)); - } -} -bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) // Eject button + std::vector<LLScrollListItem*>::iterator itor; + for (itor = selection.begin() ; + itor != selection.end(); ++itor) { - //send down an eject message - uuid_vec_t selected_members; - - std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); - if (selection.empty()) return false; - - std::vector<LLScrollListItem*>::iterator itor; - for (itor = selection.begin() ; - itor != selection.end(); ++itor) - { - LLUUID member_id = (*itor)->getUUID(); - selected_members.push_back( member_id ); - } - - mMembersList->deleteSelectedItems(); - - sendEjectNotifications(mGroupID, selected_members); - - LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members); + LLUUID member_id = (*itor)->getUUID(); + selected_members.push_back( member_id ); } - return false; + + mMembersList->deleteSelectedItems(); + + sendEjectNotifications(mGroupID, selected_members); + + LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members); } void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members) @@ -1183,12 +1212,11 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, //add that the user is requesting to change the roles for selected //members - U64 powers_all_have = 0xffffffffffffLL; + U64 powers_all_have = GP_ALL_POWERS; U64 powers_some_have = 0; BOOL is_owner_role = ( gdatap->mOwnerRole == role_id ); LLUUID member_id; - std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); if (selection.empty()) @@ -1199,7 +1227,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, for (std::vector<LLScrollListItem*>::iterator itor = selection.begin() ; itor != selection.end(); ++itor) { - member_id = (*itor)->getUUID(); //see if we requested a change for this member before @@ -1265,7 +1292,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, FALSE); } - // static void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data) { @@ -1690,13 +1716,12 @@ void LLPanelGroupMembersSubTab::updateMembers() return; } - //cleanup list only for first iretation + //cleanup list only for first iteration if(mMemberProgress == gdatap->mMembers.begin()) { mMembersList->deleteAllItems(); } - LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end(); LLTimer update_time; @@ -1749,12 +1774,44 @@ void LLPanelGroupMembersSubTab::updateMembers() handleMemberSelect(); } +void LLPanelGroupMembersSubTab::onBanMember(void* user_data) +{ + LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data); + self->handleBanMember(); +} +void LLPanelGroupMembersSubTab::handleBanMember() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected(); + if(selection.empty()) + { + return; + } -//////////////////////////// -// LLPanelGroupRolesSubTab -//////////////////////////// + uuid_vec_t ban_ids; + std::vector<LLScrollListItem*>::iterator itor; + for(itor = selection.begin(); itor != selection.end(); ++itor) + { + LLUUID ban_id = (*itor)->getUUID(); + ban_ids.push_back(ban_id); + + LLGroupBanData ban_data; + gdatap->createBanEntry(ban_id, ban_data); + } + + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_CREATE, ban_ids); + handleEjectMembers(); +} + +// LLPanelGroupRolesSubTab /////////////////////////////////////////////// static LLPanelInjector<LLPanelGroupRolesSubTab> t_panel_group_roles_subtab("panel_group_roles_subtab"); LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab() @@ -1877,6 +1934,12 @@ bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg) LL_DEBUGS() << "LLPanelGroupRolesSubTab::needsApply()" << LL_ENDL; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + llwarns << "Unable to get group data for group " << mGroupID << llendl; + return false; + } + return (mHasRoleChange // Text changed in current role || (gdatap && gdatap->pendingRoleChanges())); // Pending role changes in the group @@ -2047,6 +2110,9 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) void LLPanelGroupRolesSubTab::onRoleSelect(LLUICtrl* ctrl, void* user_data) { LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data); + if (!self) + return; + self->handleRoleSelect(); } @@ -2226,40 +2292,115 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata(); U64 power = rap->mPowerBit; - if (check->get()) + bool isEnablingAbility = check->get(); + LLRoleData rd; + LLSD args; + + if (isEnablingAbility && + !force && + ((GP_ROLE_ASSIGN_MEMBER == power) || (GP_ROLE_CHANGE_ACTIONS == power) )) { - if (!force && ( (GP_ROLE_ASSIGN_MEMBER == power) - || (GP_ROLE_CHANGE_ACTIONS == power) )) - { - // Uncheck the item, for now. It will be - // checked if they click 'Yes', below. - check->set(FALSE); + // Uncheck the item, for now. It will be + // checked if they click 'Yes', below. + check->set(FALSE); - LLRoleData rd; - LLSD args; + LLRoleData rd; + LLSD args; - if ( gdatap->getRoleData(role_id, rd) ) + if ( gdatap->getRoleData(role_id, rd) ) + { + args["ACTION_NAME"] = rap->mDescription; + args["ROLE_NAME"] = rd.mRoleName; + mHasModal = TRUE; + std::string warning = "AssignDangerousActionWarning"; + if (GP_ROLE_CHANGE_ACTIONS == power) { - args["ACTION_NAME"] = rap->mDescription; - args["ROLE_NAME"] = rd.mRoleName; - mHasModal = TRUE; - std::string warning = "AssignDangerousActionWarning"; - if (GP_ROLE_CHANGE_ACTIONS == power) - { - warning = "AssignDangerousAbilityWarning"; - } - LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check)); + warning = "AssignDangerousAbilityWarning"; } - else - { + LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check)); + } + else + { LL_WARNS() << "Unable to look up role information for role id: " << role_id << LL_ENDL; + } + } + + if(GP_GROUP_BAN_ACCESS == power) + { + std::string warning = isEnablingAbility ? "AssignBanAbilityWarning" : "RemoveBanAbilityWarning"; + + ////////////////////////////////////////////////////////////////////////// + // Get role data for both GP_ROLE_REMOVE_MEMBER and GP_MEMBER_EJECT + // Add description and role name to LLSD + // Pop up dialog saying "Yo, you also granted these other abilities when you did this!" + if ( gdatap->getRoleData(role_id, rd) ) + { + args["ACTION_NAME"] = rap->mDescription; + args["ROLE_NAME"] = rd.mRoleName; + mHasModal = TRUE; + + std::vector<LLScrollListItem*> all_data = mAllowedActionsList->getAllData(); + std::vector<LLScrollListItem*>::iterator ad_it = all_data.begin(); + std::vector<LLScrollListItem*>::iterator ad_end = all_data.end(); + LLRoleAction* adp; + for( ; ad_it != ad_end; ++ad_it) + { + adp = (LLRoleAction*)(*ad_it)->getUserdata(); + if(adp->mPowerBit == GP_MEMBER_EJECT) + { + args["ACTION_NAME_2"] = adp->mDescription; + } + else if(adp->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + args["ACTION_NAME_3"] = adp->mDescription; + } } + + LLNotificationsUtil::add(warning, args); } else { - gdatap->addRolePower(role_id,power); + llwarns << "Unable to look up role information for role id: " + << role_id << llendl; } + + ////////////////////////////////////////////////////////////////////////// + + LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.find(role_id); + U64 current_role_powers = GP_NO_POWERS; + if (rit != gdatap->mRoles.end()) + { + current_role_powers = ((*rit).second->getRoleData().mRolePowers); + } + + if(isEnablingAbility) + { + power |= (GP_ROLE_REMOVE_MEMBER | GP_MEMBER_EJECT); + current_role_powers |= power; + } + else + { + current_role_powers &= ~GP_GROUP_BAN_ACCESS; + } + + mAllowedActionsList->deleteAllItems(); + buildActionsList( mAllowedActionsList, + current_role_powers, + current_role_powers, + boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false), + TRUE, + FALSE, + FALSE); + + } + + ////////////////////////////////////////////////////////////////////////// + // Adding non-specific ability to role + ////////////////////////////////////////////////////////////////////////// + if(isEnablingAbility) + { + gdatap->addRolePower(role_id, power); } else { @@ -2268,6 +2409,7 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) mHasRoleChange = TRUE; notifyObservers(); + } bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check) @@ -2287,7 +2429,6 @@ bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& return false; } - // static void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_data) { @@ -2465,13 +2606,28 @@ void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role) mHasRoleChange = FALSE; } } -//////////////////////////// -// LLPanelGroupActionsSubTab -//////////////////////////// -static LLPanelInjector<LLPanelGroupActionsSubTab> t_panel_group_actions_subtab("panel_group_actions_subtab"); +void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id) +{ + if(mRolesList) mRolesList->deleteAllItems(); + if(mAssignedMembersList) mAssignedMembersList->deleteAllItems(); + if(mAllowedActionsList) mAllowedActionsList->deleteAllItems(); + + if(mRoleName) mRoleName->clear(); + if(mRoleDescription) mRoleDescription->clear(); + if(mRoleTitle) mRoleTitle->clear(); + + mHasRoleChange = FALSE; + + setFooterEnabled(FALSE); + + LLPanelGroupSubTab::setGroupID(id); +} +// LLPanelGroupActionsSubTab ///////////////////////////////////////////// +static LLPanelInjector<LLPanelGroupActionsSubTab> t_panel_group_actions_subtab("panel_group_actions_subtab"); + LLPanelGroupActionsSubTab::LLPanelGroupActionsSubTab() : LLPanelGroupSubTab() { @@ -2644,26 +2800,271 @@ void LLPanelGroupActionsSubTab::handleActionSelect() } } -void LLPanelGroupRoles::setGroupID(const LLUUID& id) +void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id) { - LLPanelGroupTab::setGroupID(id); + if(mActionList) mActionList->deleteAllItems(); + if(mActionRoles) mActionRoles->deleteAllItems(); + if(mActionMembers) mActionMembers->deleteAllItems(); + + if(mActionDescription) mActionDescription->clear(); + + LLPanelGroupSubTab::setGroupID(id); +} + + +// LLPanelGroupBanListSubTab ///////////////////////////////////////////// +static LLPanelInjector<LLPanelGroupBanListSubTab> t_panel_group_ban_subtab("panel_group_banlist_subtab"); + +LLPanelGroupBanListSubTab::LLPanelGroupBanListSubTab() + : LLPanelGroupSubTab(), + mBanList(NULL), + mCreateBanButton(NULL), + mDeleteBanButton(NULL) +{} + +BOOL LLPanelGroupBanListSubTab::postBuildSubTab(LLView* root) +{ + LLPanelGroupSubTab::postBuildSubTab(root); + + // Upcast parent so we can ask it for sibling controls. + LLPanelGroupRoles* parent = (LLPanelGroupRoles*)root; + + // Look recursively from the parent to find all our widgets. + bool recurse = true; - LLPanelGroupMembersSubTab* group_members_tab = findChild<LLPanelGroupMembersSubTab>("members_sub_tab"); - LLPanelGroupRolesSubTab* group_roles_tab = findChild<LLPanelGroupRolesSubTab>("roles_sub_tab"); - LLPanelGroupActionsSubTab* group_actions_tab = findChild<LLPanelGroupActionsSubTab>("actions_sub_tab"); + mHeader = parent->getChild<LLPanel>("banlist_header", recurse); + mFooter = parent->getChild<LLPanel>("banlist_footer", recurse); + + mBanList = parent->getChild<LLNameListCtrl>("ban_list", recurse); + + mCreateBanButton = parent->getChild<LLButton>("ban_create", recurse); + mDeleteBanButton = parent->getChild<LLButton>("ban_delete", recurse); + mRefreshBanListButton = parent->getChild<LLButton>("ban_refresh", recurse); - if(group_members_tab) group_members_tab->setGroupID(id); - if(group_roles_tab) group_roles_tab->setGroupID(id); - if(group_actions_tab) group_actions_tab->setGroupID(id); + if(!mBanList || !mCreateBanButton || !mDeleteBanButton || !mRefreshBanListButton) + return FALSE; - LLButton* button = getChild<LLButton>("member_invite"); - if ( button ) - button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); + mBanList->setCommitOnSelectionChange(TRUE); + mBanList->setCommitCallback(onBanEntrySelect, this); - if(mSubTabContainer) - mSubTabContainer->selectTab(1); + mCreateBanButton->setClickedCallback(onCreateBanEntry, this); + mCreateBanButton->setEnabled(FALSE); - activate(); + mDeleteBanButton->setClickedCallback(onDeleteBanEntry, this); + mDeleteBanButton->setEnabled(FALSE); + + mRefreshBanListButton->setClickedCallback(onRefreshBanList, this); + mRefreshBanListButton->setEnabled(FALSE); + + mBanList->setOnNameListCompleteCallback(boost::bind(&LLPanelGroupBanListSubTab::onBanListCompleted, this, _1)); + + populateBanList(); + + setFooterEnabled(FALSE); + return TRUE; +} + +void LLPanelGroupBanListSubTab::activate() +{ + LLPanelGroupSubTab::activate(); + + mBanList->deselectAllItems(); + mDeleteBanButton->setEnabled(FALSE); + + if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + mCreateBanButton->setEnabled(TRUE); + } + + // BAKER: Should I really request everytime activate() is called? + // Perhaps I should only do it on a force refresh, or if an action on the list happens... + // Because it's not going to live-update the list anyway... You'd have to refresh if you + // wanted to see someone else's additions anyway... + // + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); + + setFooterEnabled(FALSE); + update(GC_ALL); +} + +void LLPanelGroupBanListSubTab::update(LLGroupChange gc) +{ + populateBanList(); +} + +void LLPanelGroupBanListSubTab::draw() +{ + LLPanelGroupSubTab::draw(); + + // BAKER: Might be good to put it here instead of update, maybe.. See how often draw gets hit. + //if( + // populateBanList(); +} + +void LLPanelGroupBanListSubTab::onBanEntrySelect(LLUICtrl* ctrl, void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleBanEntrySelect(); +} + +void LLPanelGroupBanListSubTab::handleBanEntrySelect() +{ + if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + mDeleteBanButton->setEnabled(TRUE); + } +} + +void LLPanelGroupBanListSubTab::onCreateBanEntry(void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleCreateBanEntry(); +} + +void LLPanelGroupBanListSubTab::handleCreateBanEntry() +{ + LLFloaterGroupBulkBan::showForGroup(mGroupID); + //populateBanList(); +} + +void LLPanelGroupBanListSubTab::onDeleteBanEntry(void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleDeleteBanEntry(); +} + +void LLPanelGroupBanListSubTab::handleDeleteBanEntry() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + std::vector<LLScrollListItem*> selection = mBanList->getAllSelected(); + if(selection.empty()) + { + return; + } + + bool can_ban_members = false; + if (gAgent.isGodlike() || + gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + can_ban_members = true; + } + + // Owners can ban anyone in the group. + LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(gAgent.getID()); + if (mi != gdatap->mMembers.end()) + { + LLGroupMemberData* member_data = (*mi).second; + if ( member_data && member_data->isInRole(gdatap->mOwnerRole) ) + { + can_ban_members = true; + } + } + + if(!can_ban_members) + return; + + std::vector<LLUUID> ban_ids; + std::vector<LLScrollListItem*>::iterator itor; + for(itor = selection.begin(); itor != selection.end(); ++itor) + { + LLUUID ban_id = (*itor)->getUUID(); + ban_ids.push_back(ban_id); + + gdatap->removeBanEntry(ban_id); + mBanList->removeNameItem(ban_id); + + // Removing an item removes the selection, we shouldn't be able to click + // the button anymore until we reselect another entry. + mDeleteBanButton->setEnabled(FALSE); + } + + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_DELETE, ban_ids); +} + +void LLPanelGroupBanListSubTab::onRefreshBanList(void* user_data) +{ + LLPanelGroupBanListSubTab* self = static_cast<LLPanelGroupBanListSubTab*>(user_data); + if (!self) + return; + + self->handleRefreshBanList(); } +void LLPanelGroupBanListSubTab::handleRefreshBanList() +{ + mRefreshBanListButton->setEnabled(FALSE); + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); +} +void LLPanelGroupBanListSubTab::onBanListCompleted(bool isComplete) +{ + if(isComplete) + { + mRefreshBanListButton->setEnabled(TRUE); + populateBanList(); + } +} + +void LLPanelGroupBanListSubTab::populateBanList() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if(!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + mBanList->deleteAllItems(); + std::map<LLUUID,LLGroupBanData>::const_iterator entry = gdatap->mBanList.begin(); + for(; entry != gdatap->mBanList.end(); entry++) + { + LLNameListCtrl::NameItem ban_entry; + ban_entry.value = entry->first; + LLGroupBanData bd = entry->second; + + ban_entry.columns.add().column("name").font.name("SANSSERIF_SMALL").style("NORMAL"); + + // Check out utc_to_pacific_time() + + std::string ban_date_str = bd.mBanDate.toHTTPDateString("%Y/%m/%d"); + time_t utc_time; + utc_time = time_corrected(); + LLSD substitution; + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (ban_date_str, substitution); + + LL_INFOS("BAKER") << "[BAKER] BAN_DATE: " << bd.mBanDate.toHTTPDateString("%Y/%m/%d") << LL_ENDL; + LL_INFOS("BAKER") << "[BAKER] BAN_DATE_MODIFIED: " << ban_date_str << LL_ENDL; + + //ban_entry.columns.add().column("ban_date").value(ban_date_str.font.name("SANSSERIF_SMALL").style("NORMAL"); + ban_entry.columns.add().column("ban_date").value(bd.mBanDate.toHTTPDateString("%Y/%m/%d")).font.name("SANSSERIF_SMALL").style("NORMAL"); + + mBanList->addNameItemRow(ban_entry); + } + + mRefreshBanListButton->setEnabled(TRUE); +} + +void LLPanelGroupBanListSubTab::setGroupID(const LLUUID& id) +{ + if(mBanList) + mBanList->deleteAllItems(); + + setFooterEnabled(FALSE); + LLPanelGroupSubTab::setGroupID(id); +} diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 0cf272f3ee..26f1dff007 100755 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -39,11 +39,9 @@ class LLScrollListCtrl; class LLScrollListItem; class LLTextEditor; -// Forward declare for friend usage. -//virtual BOOL LLPanelGroupSubTab::postBuildSubTab(LLView*); - typedef std::map<std::string,std::string> icon_map_t; + class LLPanelGroupRoles : public LLPanelGroupTab { public: @@ -92,6 +90,7 @@ protected: std::string mWantApplyMesg; }; + class LLPanelGroupSubTab : public LLPanelGroupTab { public: @@ -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; @@ -218,6 +226,7 @@ protected: boost::signals2::connection mAvatarNameCacheConnection; }; + class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab { public: @@ -240,7 +249,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); @@ -280,6 +289,7 @@ protected: std::string mRemoveEveryoneTxt; }; + class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab { public: @@ -307,4 +317,44 @@ protected: }; +class LLPanelGroupBanListSubTab : public LLPanelGroupSubTab +{ +public: + LLPanelGroupBanListSubTab(); + virtual ~LLPanelGroupBanListSubTab() {} + + virtual BOOL postBuildSubTab(LLView* root); + + virtual void activate(); + virtual void update(LLGroupChange gc); + virtual void draw(); + + static void onBanEntrySelect(LLUICtrl* ctrl, void* user_data); + void handleBanEntrySelect(); + + static void onCreateBanEntry(void* user_data); + void handleCreateBanEntry(); + + static void onDeleteBanEntry(void* user_data); + void handleDeleteBanEntry(); + + static void onRefreshBanList(void* user_data); + void handleRefreshBanList(); + + void onBanListCompleted(bool isComplete); + +protected: + void populateBanList(); + +public: + virtual void setGroupID(const LLUUID& id); + +protected: + LLNameListCtrl* mBanList; + LLButton* mCreateBanButton; + LLButton* mDeleteBanButton; + LLButton* mRefreshBanListButton; + +}; + #endif // LL_LLPANELGROUPROLES_H diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 1932f4e8ce..1746aca8a8 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -2630,6 +2630,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"); diff --git a/indra/newview/roles_constants.h b/indra/newview/roles_constants.h index effd15ea72..8fd7978fa1 100755..100644 --- a/indra/newview/roles_constants.h +++ b/indra/newview/roles_constants.h @@ -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 diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 9668cfa526..ef2f158a86 100755 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -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" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 370a2af5e0..19d7cd104a 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -506,7 +506,35 @@ Add this Ability to '[ROLE_NAME]'? notext="No" yestext="Yes"/> </notification> - + + <notification + icon="alertmodal.tga" + name="AssignBanAbilityWarning" + type="alertmodal"> +You are about to add the Ability '[ACTION_NAME]' to the Role '[ROLE_NAME]'. + + *WARNING* +Any Member in a Role with this Ability will also be granted the Abilities '[ACTION_NAME_2]' and '[ACTION_NAME_3]' + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="RemoveBanAbilityWarning" + type="alertmodal"> +You are removing the Ability '[ACTION_NAME]' to the Role '[ROLE_NAME]'. + + *WARNING* +Removing this ability will NOT remove the Abilities '[ACTION_NAME_2]' and '[ACTION_NAME_3]'. + +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" diff --git a/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml b/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml new file mode 100644 index 0000000000..8dd2719926 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_group_bulk_ban.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + height="330" + label="Ban Residents" + layout="topleft" + left="0" + name="bulk_ban_panel" + top="330" + width="210"> + <panel.string + name="loading"> + (loading...) + </panel.string> + <panel.string + name="ban_selection_too_large"> + Group bans not sent: too many Residents selected. Group bans are limited to 100 per request. + </panel.string> + <text + type="string" + length="1" + height="54" + layout="topleft" + left="7" + name="help_text" + top="28" + word_wrap="true" + width="200"> + You can select multiple Residents to ban from your group. Click 'Open Resident Chooser' to start. + </text> + <button + height="20" + label="Open Resident Chooser" + layout="topleft" + left_delta="-2" + name="add_button" + top_delta="44" + width="200" /> + <name_list + allow_calling_card_drop="true" + column_padding="0" + height="174" + layout="topleft" + left_delta="0" + multi_select="true" + name="banned_agent_list" + tool_tip="Hold the Ctrl key and click Resident names to multi-select" + top_pad="4" + width="200" /> + <button + height="20" + label="Remove Selected from List" + layout="topleft" + left_delta="0" + name="remove_button" + tool_tip="Removes the Residents selected above from the ban list" + top_pad="4" + width="200" /> + <button + height="20" + label="Ban Residents" + layout="topleft" + left="4" + name="ban_button" + top_delta="30" + width="135" /> + <button + height="20" + label="Cancel" + layout="topleft" + left_pad="2" + name="cancel_button" + top_delta="0" + width="65" /> + <string + name="GroupBulkBan"> + Group Ban + </string> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_invite.xml b/indra/newview/skins/default/xui/en/panel_group_invite.xml index 124c0596c3..944a496fba 100755 --- a/indra/newview/skins/default/xui/en/panel_group_invite.xml +++ b/indra/newview/skins/default/xui/en/panel_group_invite.xml @@ -88,7 +88,7 @@ label="Send Invitations" layout="topleft" left="4" - name="ok_button" + name="invite_button" top="356" width="135" /> <button diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 9ac5b8800e..ea619e6319 100755 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -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,454 +145,522 @@ 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 'Everyone' and 'Owners' 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'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's a broad variety of Abilities. - </panel.string> - <panel.string - name="power_folder_icon" translate="false"> - Inv_FolderClosed - </panel.string> - <panel.string - name="power_all_have_icon" translate="false"> - Checkbox_On - </panel.string> - <panel.string - name="power_partial_icon" translate="false"> - Checkbox_Off - </panel.string> - <filter_editor - layout="topleft" - top="5" - left="5" - right="-5" - height="22" - search_button_visible="false" - follows="left|top|right" - label="Filter Abilities" - name="filter_input" /> - <scroll_list - column_padding="0" - draw_stripes="true" - height="200" - follows="left|top|right" - layout="topleft" - left="0" - right="-1" - name="action_list" - search_column="2" - tool_tip="Select an Ability to view more details" - top_pad="5" - width="300"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" - width="270" /> - </scroll_list> - </panel> - </tab_container> + <panel.string + name="help_text"> + Roles have a title and an allowed list of Abilities + that Members can perform. Members can belong to + one or more Roles. A group can have up to 10 Roles, + including the Everyone and Owner Roles. + </panel.string> + <panel.string + name="cant_delete_role"> + The 'Everyone' and 'Owners' Roles are special and can't be deleted. + </panel.string> + <panel.string + name="power_folder_icon" translate="false"> + Inv_FolderClosed + </panel.string> + <panel.string + name="power_all_have_icon" translate="false"> + Checkbox_On + </panel.string> + <panel.string + name="power_partial_icon" translate="false"> + Checkbox_Off + </panel.string> + <filter_editor + layout="topleft" + top="5" + left="5" + right="-5" + height="22" + search_button_visible="false" + follows="left|top|right" + label="Filter Roles" + name="filter_input" /> + <scroll_list + column_padding="0" + draw_heading="true" + draw_stripes="false" + heading_height="23" + height="132" + layout="topleft" + search_column="1" + left="0" + follows="left|top|right" + right="-1" + name="role_list" + top_pad="2" + width="310"> + <scroll_list.columns + label="Role" + name="name" + relative_width="0.45" /> + <scroll_list.columns + label="Title" + name="title" + relative_width="0.45" /> + <scroll_list.columns + label="#" + name="members" + relative_width="0.15" /> + </scroll_list> + <button + follows="top|left" + height="23" + label="New Role" + layout="topleft" + left="0" + name="role_create" + width="120" /> + <button + height="23" + follows="top|left" + label="Delete Role" + layout="topleft" + left_pad="10" + name="role_delete" + width="120" /> + </panel> <panel - height="350" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" + border="false" + height="303" + label="ABILITIES" layout="topleft" - follows="top|left|right" left="0" right="-1" - width="313" - mouse_opaque="false" - name="members_footer" - top="325" - visible="false"> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top="8" - text_color="EmphasisColor" - name="static" - width="300"> - Assigned Roles - </text> - <scroll_list - draw_stripes="true" - follows="left|top|right" - height="150" - layout="topleft" - left="0" - right="-1" - name="member_assigned_roles" - top_pad="0"> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="role" - width="270" /> - </scroll_list> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top_pad="5" - text_color="EmphasisColor" - name="static2" - width="285"> - Allowed Abilities - </text> - <scroll_list - draw_stripes="true" - follows="left|top|right" - height="150" - layout="topleft" - left="0" - right="-1" - name="member_allowed_actions" - search_column="2" - tool_tip="For details of each allowed ability see the abilities tab" - top_pad="0"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" - width="270" /> - </scroll_list> + help_topic="roles_actions_tab" + name="actions_sub_tab" + class="panel_group_actions_subtab" + tool_tip="You can view an Ability'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's a broad variety of Abilities. + </panel.string> + <panel.string + name="power_folder_icon" translate="false"> + Inv_FolderClosed + </panel.string> + <panel.string + name="power_all_have_icon" translate="false"> + Checkbox_On + </panel.string> + <panel.string + name="power_partial_icon" translate="false"> + Checkbox_Off + </panel.string> + <filter_editor + layout="topleft" + top="5" + left="5" + right="-5" + height="22" + search_button_visible="false" + follows="left|top|right" + label="Filter Abilities" + name="filter_input" /> + <scroll_list + column_padding="0" + draw_stripes="true" + height="200" + follows="left|top|right" + layout="topleft" + left="0" + right="-1" + name="action_list" + search_column="2" + tool_tip="Select an Ability to view more details" + top_pad="5" + width="300"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" + width="270" /> + </scroll_list> </panel> <panel - height="550" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" + border="false" + height="303" + label="BANNED RESIDENTS" layout="topleft" - follows="top|left|right" left="0" right="-1" - width="313" - mouse_opaque="false" - name="roles_footer" - top_delta="0" - top="209" - visible="false"> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - top="5" - name="static" - width="300"> - Role Name - </text> - <line_editor - type="string" - height="20" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length_bytes="20" - name="role_name" - top_pad="0" - width="300"> - </line_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static3" - top_pad="5" - width="300"> - Role Title - </text> - <line_editor - type="string" - height="20" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length_bytes="20" - name="role_title" - top_pad="0" - width="300"> - </line_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static2" - top_pad="5" - width="200"> - Description - </text> - <text_editor - type="string" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - max_length="295" - height="35" - name="role_description" - top_pad="0" - width="300" - word_wrap="true"> - </text_editor> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - text_color="EmphasisColor" - name="static4" - top_pad="5" - width="300"> - Assigned Members - </text> - <name_list - draw_stripes="true" - height="128" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - name="role_assigned_members" - top_pad="0" - width="300" /> - <check_box - height="15" - label="Reveal members" - left="5" - layout="topleft" - name="role_visible_in_list" - tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group." - top_pad="4" - width="300" /> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - text_color="EmphasisColor" - name="static5" - top_pad="2" - width="300"> - Allowed Abilities - </text> - <scroll_list - draw_stripes="true" - height="140" - layout="topleft" - left="0" - follows="left|top|right" - right="-1" - name="role_allowed_actions" - search_column="2" - tool_tip="For details of each allowed ability see the abilities tab" - top_pad="0" - width="300"> - <scroll_list.columns - label="" - name="icon" - width="2" /> - <scroll_list.columns - label="" - name="checkbox" - width="20" /> - <scroll_list.columns - label="" - name="action" - width="270" /> - </scroll_list> + help_topic="roles_banlist_tab" + name="banlist_sub_tab" + class="panel_group_banlist_subtab" + tool_tip="View the banned 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> + <name_list + column_padding="0" + draw_heading="true" + height="400" + follows="left|top|right" + layout="topleft" + left="0" + right="-1" + multi_select="true" + name="ban_list" + short_names="false" + top_pad="5"> + <name_list.columns + label="Resident" + name="name" + font.name="SANSSERIF_SMALL" + font.style="NORMAL" + relative_width="0.7" /> + <name_list.columns + label="Date Banned" + name="ban_date" + relative_width="0.3" /> + </name_list> + <button + follows="top|left" + height="23" + label="Ban Resident(s)" + layout="topleft" + left="3" + name="ban_create" + tool_tip="Ban residents from your group" + width="120" /> + <button + follows="top|left" + height="23" + label="Remove Ban(s)" + layout="topleft" + left_pad="5" + name="ban_delete" + tool_tip="Unban selected residents from your group" + width="120" /> + <button + follows="top|left" + height="23" + width="23" + image_overlay="Refresh_Off" + layout="topleft" + left_pad="5" + name="ban_refresh" + tool_tip="Refresh the ban list" + /> </panel> - <panel - height="424" - background_visible="false" - bg_alpha_color="FloaterUnfocusBorderColor" + </tab_container> + <panel + height="350" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" + layout="topleft" + follows="top|left|right" + left="0" + right="-1" + width="313" + mouse_opaque="false" + name="members_footer" + top="325" + visible="false"> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top="8" + text_color="EmphasisColor" + name="static" + width="300"> + Assigned Roles + </text> + <scroll_list + draw_stripes="true" + follows="left|top|right" + height="150" layout="topleft" - follows="top|left|right" left="0" right="-1" - width="313" - mouse_opaque="false" - name="actions_footer" - top_delta="0" - top="255" - visible="false"> - <text_editor - bg_readonly_color="Transparent" - text_readonly_color="EmphasisColor" - font="SansSerifSmall" - type="string" - enabled="false" - halign="left" - layout="topleft" + name="member_assigned_roles" + top_pad="0"> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="role" + width="270" /> + </scroll_list> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top_pad="5" + text_color="EmphasisColor" + name="static2" + width="285"> + Allowed Abilities + </text> + <scroll_list + draw_stripes="true" follows="left|top|right" - left="0" - right="-1" - height="90" - max_length="512" - name="action_description" - top="0" - word_wrap="true"> - This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. - </text_editor> - <text + height="150" + layout="topleft" + left="0" + right="-1" + name="member_allowed_actions" + search_column="2" + tool_tip="For details of each allowed ability see the abilities tab" + top_pad="0"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" + width="270" /> + </scroll_list> + </panel> + <panel + height="550" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" + layout="topleft" + follows="top|left|right" + left="0" + right="-1" + width="313" + mouse_opaque="false" + name="roles_footer" + top_delta="0" + top="209" + visible="false"> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + top="5" + name="static" + width="300"> + Role Name + </text> + <line_editor + type="string" + height="20" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length_bytes="20" + name="role_name" + top_pad="0" + width="300"> + </line_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static3" + top_pad="5" + width="300"> + Role Title + </text> + <line_editor + type="string" + height="20" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length_bytes="20" + name="role_title" + top_pad="0" + width="300"> + </line_editor> + <text type="string" height="16" layout="topleft" follows="left|top" left="5" name="static2" - top_pad="1" - width="300"> - Roles with this ability - </text> - <scroll_list - height="172" - layout="topleft" - follows="left|top|right" - left="5" - right="-1" - name="action_roles" - top_pad="0" - width="300" /> - <text - type="string" - height="16" - layout="topleft" - follows="left|top" - left="5" - name="static3" top_pad="5" - width="300"> - Members with this ability - </text> - <name_list - height="122" - follows="left|top|right" - layout="topleft" - left="5" - right="-1" - name="action_members" - top_pad="0" - width="300" /> - </panel> + width="200"> + Description + </text> + <text_editor + type="string" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + max_length="295" + height="35" + name="role_description" + top_pad="0" + width="300" + word_wrap="true"> + </text_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + text_color="EmphasisColor" + name="static4" + top_pad="5" + width="300"> + Assigned Members + </text> + <name_list + draw_stripes="true" + height="128" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + name="role_assigned_members" + top_pad="0" + width="300" /> + <check_box + height="15" + label="Reveal members" + left="5" + layout="topleft" + name="role_visible_in_list" + tool_tip="Sets whether members of this role are visible in the General tab to people outside of the group." + top_pad="4" + width="300" /> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + text_color="EmphasisColor" + name="static5" + top_pad="2" + width="300"> + Allowed Abilities + </text> + <scroll_list + draw_stripes="true" + height="140" + layout="topleft" + left="0" + follows="left|top|right" + right="-1" + name="role_allowed_actions" + search_column="2" + tool_tip="For details of each allowed ability see the abilities tab" + top_pad="0" + width="300"> + <scroll_list.columns + label="" + name="icon" + width="2" /> + <scroll_list.columns + label="" + name="checkbox" + width="20" /> + <scroll_list.columns + label="" + name="action" + width="270" /> + </scroll_list> + </panel> + <panel + height="424" + background_visible="false" + bg_alpha_color="FloaterUnfocusBorderColor" + layout="topleft" + follows="top|left|right" + left="0" + right="-1" + width="313" + mouse_opaque="false" + name="actions_footer" + top_delta="0" + top="255" + visible="false"> + <text_editor + bg_readonly_color="Transparent" + text_readonly_color="EmphasisColor" + font="SansSerifSmall" + type="string" + enabled="false" + halign="left" + layout="topleft" + follows="left|top|right" + left="0" + right="-1" + height="90" + max_length="512" + name="action_description" + top="0" + word_wrap="true"> + This Ability is 'Eject Members from this Group'. Only an Owner can eject another Owner. + </text_editor> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static2" + top_pad="1" + width="300"> + Roles with this ability + </text> + <scroll_list + height="172" + layout="topleft" + follows="left|top|right" + left="5" + right="-1" + name="action_roles" + top_pad="0" + width="300" /> + <text + type="string" + height="16" + layout="topleft" + follows="left|top" + left="5" + name="static3" + top_pad="5" + width="300"> + Members with this ability + </text> + <name_list + height="122" + follows="left|top|right" + layout="topleft" + left="5" + right="-1" + name="action_members" + top_pad="0" + width="300" /> + </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/role_actions.xml b/indra/newview/skins/default/xui/en/role_actions.xml index 0eeccbeac5..1044cbfd2e 100755 --- a/indra/newview/skins/default/xui/en/role_actions.xml +++ b/indra/newview/skins/default/xui/en/role_actions.xml @@ -9,7 +9,10 @@ <action description="Eject Members from this Group" longdescription="Eject Members from this Group using the 'Eject' button in the Roles section > Members tab. An Owner can eject anyone except another Owner. If you're not an Owner, a Member can be ejected from a group if, and only if, they're only in the Everyone Role, and NO other Roles. To remove Members from Roles, you need to have the 'Remove Members from Roles' 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 'Open Enrollment' and change 'Enrollment fee'" longdescription="Toggle 'Open Enrollment' to let new Members join without an invitation, and change the 'Enrollment fee' in the General section." name="member options" value="3" /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 437b7310f5..1b4a4d0aa4 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3741,6 +3741,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> |