3457 lines
107 KiB
C++
3457 lines
107 KiB
C++
/**
|
|
* @file llpanelgrouproles.cpp
|
|
* @brief Panel for roles information about a particular group.
|
|
*
|
|
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, 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 "llcheckboxctrl.h"
|
|
|
|
#include "llagent.h"
|
|
#include "llavatarnamecache.h"
|
|
#include "llbutton.h"
|
|
#include "llfiltereditor.h"
|
|
#include "llfloatergroupbulkban.h"
|
|
#include "llfloatergroupinvite.h"
|
|
#include "llavataractions.h"
|
|
#include "lliconctrl.h"
|
|
#include "lllineeditor.h"
|
|
#include "llnamelistctrl.h"
|
|
#include "llnotifications.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "llpanelgrouproles.h"
|
|
#include "llscrolllistctrl.h"
|
|
#include "llscrolllistitem.h"
|
|
#include "llscrolllistcell.h"
|
|
#include "llslurl.h"
|
|
#include "lltabcontainer.h"
|
|
#include "lltextbox.h"
|
|
#include "lltexteditor.h"
|
|
#include "lltrans.h"
|
|
#include "llviewertexturelist.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llfocusmgr.h"
|
|
#include "llviewercontrol.h"
|
|
|
|
#include "roles_constants.h"
|
|
|
|
// [FS:CR] FIRE-12276
|
|
#include "fsnamelistavatarmenu.h"
|
|
#include "llfilepicker.h"
|
|
#include "llviewermenufile.h"
|
|
|
|
static LLPanelInjector<LLPanelGroupRoles> t_panel_group_roles("panel_group_roles");
|
|
|
|
bool agentCanRemoveFromRole(const LLUUID& group_id,
|
|
const LLUUID& role_id)
|
|
{
|
|
return gAgent.hasPowerInGroup(group_id, GP_ROLE_REMOVE_MEMBER);
|
|
}
|
|
|
|
bool agentCanAddToRole(const LLUUID& group_id,
|
|
const LLUUID& role_id)
|
|
{
|
|
if (gAgent.isGodlike())
|
|
return true;
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "agentCanAddToRole "
|
|
<< "-- No group data!" << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
//make sure the agent is in the group
|
|
LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(gAgent.getID());
|
|
if (mi == gdatap->mMembers.end())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LLGroupMemberData* member_data = (*mi).second;
|
|
|
|
// Owners can add to any role.
|
|
if ( member_data->isInRole(gdatap->mOwnerRole) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// 'Limited assign members' can add to roles the user is in.
|
|
if ( gAgent.hasPowerInGroup(group_id, GP_ROLE_ASSIGN_MEMBER_LIMITED) &&
|
|
member_data->isInRole(role_id) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// 'assign members' can add to non-owner roles.
|
|
if ( gAgent.hasPowerInGroup(group_id, GP_ROLE_ASSIGN_MEMBER) &&
|
|
role_id != gdatap->mOwnerRole )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// LLPanelGroupRoles /////////////////////////////////////////////////////
|
|
|
|
// static
|
|
LLPanelGroupRoles::LLPanelGroupRoles()
|
|
: LLPanelGroupTab(),
|
|
mCurrentTab(NULL),
|
|
mRequestedTab( NULL ),
|
|
mSubTabContainer( NULL ),
|
|
mFirstUse( true )
|
|
{
|
|
}
|
|
|
|
LLPanelGroupRoles::~LLPanelGroupRoles()
|
|
{
|
|
}
|
|
|
|
bool LLPanelGroupRoles::postBuild()
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupRoles::postBuild()" << LL_ENDL;
|
|
|
|
mSubTabContainer = getChild<LLTabContainer>("roles_tab_container");
|
|
|
|
if (!mSubTabContainer) return false;
|
|
|
|
// Hook up each sub-tabs callback and widgets.
|
|
for (S32 i = 0; i < mSubTabContainer->getTabCount(); ++i)
|
|
{
|
|
LLPanel* panel = mSubTabContainer->getPanelByIndex(i);
|
|
LLPanelGroupSubTab* subtabp = dynamic_cast<LLPanelGroupSubTab*>(panel);
|
|
if (!subtabp)
|
|
{
|
|
LL_WARNS() << "Invalid subtab panel: " << panel->getName() << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
// Hand the subtab a pointer to this LLPanelGroupRoles, so that it can
|
|
// look around for the widgets it is interested in.
|
|
if (!subtabp->postBuildSubTab(this))
|
|
return false;
|
|
|
|
//subtabp->addObserver(this);
|
|
}
|
|
// Add click callbacks to tab switching.
|
|
mSubTabContainer->setValidateBeforeCommit(boost::bind(&LLPanelGroupRoles::handleSubTabSwitch, this, _1));
|
|
|
|
// Set the current tab to whatever is currently being shown.
|
|
mCurrentTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (!mCurrentTab)
|
|
{
|
|
// Need to select a tab.
|
|
mSubTabContainer->selectFirstTab();
|
|
mCurrentTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
}
|
|
|
|
if (!mCurrentTab) return false;
|
|
|
|
// Act as though this tab was just activated.
|
|
mCurrentTab->activate();
|
|
|
|
// Read apply text from the xml file.
|
|
mDefaultNeedsApplyMesg = getString("default_needs_apply_text");
|
|
mWantApplyMesg = getString("want_apply_text");
|
|
|
|
return LLPanelGroupTab::postBuild();
|
|
}
|
|
|
|
bool LLPanelGroupRoles::isVisibleByAgent(LLAgent* agentp)
|
|
{
|
|
/* This power was removed to make group roles simpler
|
|
return agentp->hasPowerInGroup(mGroupID,
|
|
GP_ROLE_CREATE |
|
|
GP_ROLE_DELETE |
|
|
GP_ROLE_PROPERTIES |
|
|
GP_ROLE_VIEW |
|
|
GP_ROLE_ASSIGN_MEMBER |
|
|
GP_ROLE_REMOVE_MEMBER |
|
|
GP_ROLE_CHANGE_ACTIONS |
|
|
GP_MEMBER_INVITE |
|
|
GP_MEMBER_EJECT |
|
|
GP_MEMBER_OPTIONS );
|
|
*/
|
|
return mAllowEdit && agentp->isInGroup(mGroupID);
|
|
|
|
}
|
|
|
|
bool LLPanelGroupRoles::handleSubTabSwitch(const LLSD& data)
|
|
{
|
|
std::string panel_name = data.asString();
|
|
|
|
if(mRequestedTab != NULL)//we already have tab change request
|
|
{
|
|
return false;
|
|
}
|
|
|
|
mRequestedTab = static_cast<LLPanelGroupTab*>(mSubTabContainer->getPanelByName(panel_name));
|
|
|
|
std::string mesg;
|
|
if (mCurrentTab && mCurrentTab->needsApply(mesg))
|
|
{
|
|
// If no message was provided, give a generic one.
|
|
if (mesg.empty())
|
|
{
|
|
mesg = mDefaultNeedsApplyMesg;
|
|
}
|
|
// Create a notify box, telling the user about the unapplied tab.
|
|
LLSD args;
|
|
args["NEEDS_APPLY_MESSAGE"] = mesg;
|
|
args["WANT_APPLY_MESSAGE"] = mWantApplyMesg;
|
|
LLNotificationsUtil::add("PanelGroupApply", args, LLSD(),
|
|
boost::bind(&LLPanelGroupRoles::handleNotifyCallback, this, _1, _2));
|
|
mHasModal = true;
|
|
|
|
// Returning false will block a close action from finishing until
|
|
// we get a response back from the user.
|
|
return false;
|
|
}
|
|
|
|
transitionToTab();
|
|
return true;
|
|
}
|
|
|
|
void LLPanelGroupRoles::transitionToTab()
|
|
{
|
|
// Tell the current panel that it is being deactivated.
|
|
if (mCurrentTab)
|
|
{
|
|
mCurrentTab->deactivate();
|
|
}
|
|
|
|
// Tell the new panel that it is being activated.
|
|
if (mRequestedTab)
|
|
{
|
|
// This is now the current tab;
|
|
mCurrentTab = mRequestedTab;
|
|
mCurrentTab->activate();
|
|
mRequestedTab = 0;
|
|
}
|
|
}
|
|
|
|
bool LLPanelGroupRoles::handleNotifyCallback(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
mHasModal = false;
|
|
LLPanelGroupTab* transition_tab = mRequestedTab;
|
|
switch (option)
|
|
{
|
|
case 0: // "Apply Changes"
|
|
{
|
|
// Try to apply changes, and switch to the requested tab.
|
|
std::string apply_mesg;
|
|
if ( !apply( apply_mesg ) )
|
|
{
|
|
// There was a problem doing the apply.
|
|
if ( !apply_mesg.empty() )
|
|
{
|
|
mHasModal = true;
|
|
LLSD args;
|
|
args["MESSAGE"] = apply_mesg;
|
|
LLNotificationsUtil::add("GenericAlert", args, LLSD(), boost::bind(&LLPanelGroupRoles::onModalClose, this, _1, _2));
|
|
}
|
|
// Skip switching tabs.
|
|
break;
|
|
}
|
|
transitionToTab();
|
|
mSubTabContainer->selectTabPanel( transition_tab );
|
|
|
|
break;
|
|
}
|
|
case 1: // "Ignore Changes"
|
|
// Switch to the requested panel without applying changes
|
|
cancel();
|
|
transitionToTab();
|
|
mSubTabContainer->selectTabPanel( transition_tab );
|
|
break;
|
|
case 2: // "Cancel"
|
|
default:
|
|
mRequestedTab = NULL;
|
|
// Do nothing. The user is canceling the action.
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool LLPanelGroupRoles::onModalClose(const LLSD& notification, const LLSD& response)
|
|
{
|
|
mHasModal = false;
|
|
return false;
|
|
}
|
|
|
|
bool LLPanelGroupRoles::apply(std::string& mesg)
|
|
{
|
|
// Pass this along to the currently visible sub tab.
|
|
if (!mSubTabContainer) return false;
|
|
|
|
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (!panelp) return false;
|
|
|
|
// Ignore the needs apply message.
|
|
std::string ignore_mesg;
|
|
if ( !panelp->needsApply(ignore_mesg) )
|
|
{
|
|
// We don't need to apply anything.
|
|
// We're done.
|
|
return true;
|
|
}
|
|
|
|
// Try to do the actual apply.
|
|
return panelp->apply(mesg);
|
|
}
|
|
|
|
void LLPanelGroupRoles::cancel()
|
|
{
|
|
// Pass this along to the currently visible sub tab.
|
|
if (!mSubTabContainer) return;
|
|
|
|
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (!panelp) return;
|
|
|
|
panelp->cancel();
|
|
}
|
|
|
|
void LLPanelGroupRoles::update(LLGroupChange gc)
|
|
{
|
|
if (mGroupID.isNull()) return;
|
|
|
|
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (panelp)
|
|
{
|
|
panelp->update(gc);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS() << "LLPanelGroupRoles::update() -- No subtab to update!" << LL_ENDL;
|
|
}
|
|
|
|
}
|
|
|
|
void LLPanelGroupRoles::activate()
|
|
{
|
|
if (!gAgent.isInGroup(mGroupID)) return;
|
|
|
|
// Start requesting member and role data if needed.
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
if (!gdatap || !gdatap->isRoleDataComplete() )
|
|
{
|
|
// Mildly hackish - clear all pending changes
|
|
cancel();
|
|
|
|
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
|
|
}
|
|
|
|
// Need this to get base group member powers
|
|
if (!gdatap || !gdatap->isGroupPropertiesDataComplete() )
|
|
{
|
|
LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID);
|
|
}
|
|
|
|
mFirstUse = false;
|
|
|
|
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (panelp) panelp->activate();
|
|
}
|
|
|
|
void LLPanelGroupRoles::deactivate()
|
|
{
|
|
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (panelp) panelp->deactivate();
|
|
}
|
|
|
|
bool LLPanelGroupRoles::needsApply(std::string& mesg)
|
|
{
|
|
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (!panelp) return false;
|
|
|
|
return panelp->needsApply(mesg);
|
|
}
|
|
|
|
bool LLPanelGroupRoles::hasModal()
|
|
{
|
|
if (mHasModal) return true;
|
|
|
|
LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel();
|
|
if (!panelp) return false;
|
|
|
|
return panelp->hasModal();
|
|
}
|
|
|
|
void LLPanelGroupRoles::setGroupID(const LLUUID& id)
|
|
{
|
|
LLPanelGroupTab::setGroupID(id);
|
|
|
|
LLPanelGroupMembersSubTab* group_members_tab = findChild<LLPanelGroupMembersSubTab>("members_sub_tab");
|
|
LLPanelGroupRolesSubTab* group_roles_tab = findChild<LLPanelGroupRolesSubTab>("roles_sub_tab");
|
|
LLPanelGroupActionsSubTab* group_actions_tab = findChild<LLPanelGroupActionsSubTab>("actions_sub_tab");
|
|
LLPanelGroupBanListSubTab* group_ban_tab = findChild<LLPanelGroupBanListSubTab>("banlist_sub_tab");
|
|
|
|
if(group_members_tab) group_members_tab->setGroupID(id);
|
|
if(group_roles_tab) group_roles_tab->setGroupID(id);
|
|
if(group_actions_tab) group_actions_tab->setGroupID(id);
|
|
if(group_ban_tab) group_ban_tab->setGroupID(id);
|
|
|
|
LLButton* button = getChild<LLButton>("member_invite");
|
|
if ( button )
|
|
button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE));
|
|
// [FS:CR] FIRE-12276
|
|
button = getChild<LLButton>("export_list");
|
|
if (button)
|
|
button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_VISIBLE_IN_DIR));
|
|
// [/FS:CR]
|
|
if(mSubTabContainer)
|
|
mSubTabContainer->selectTab(1);
|
|
group_roles_tab->mFirstOpen = true;
|
|
activate();
|
|
}
|
|
|
|
// <FS:Ansariel> CTRL-F focusses local search editor
|
|
LLPanelGroupSubTab* LLPanelGroupRoles::getCurrentTab() const
|
|
{
|
|
return dynamic_cast<LLPanelGroupSubTab*>(mSubTabContainer->getCurrentPanel());
|
|
}
|
|
// </FS:Ansariel>
|
|
|
|
// LLPanelGroupSubTab ////////////////////////////////////////////////////
|
|
LLPanelGroupSubTab::LLPanelGroupSubTab()
|
|
: LLPanelGroupTab(),
|
|
mHeader(NULL),
|
|
mFooter(NULL),
|
|
mActivated(false),
|
|
mHasGroupBanPower(false),
|
|
mSearchEditor(NULL)
|
|
{
|
|
}
|
|
|
|
LLPanelGroupSubTab::~LLPanelGroupSubTab()
|
|
{
|
|
mSearchCommitConnection.disconnect();
|
|
}
|
|
|
|
bool LLPanelGroupSubTab::postBuildSubTab(LLView* root)
|
|
{
|
|
// Get icons for later use.
|
|
mActionIcons.clear();
|
|
|
|
if (hasString("power_folder_icon"))
|
|
{
|
|
mActionIcons["folder"] = getString("power_folder_icon");
|
|
}
|
|
|
|
if (hasString("power_all_have_icon"))
|
|
{
|
|
mActionIcons["full"] = getString("power_all_have_icon");
|
|
}
|
|
|
|
if (hasString("power_partial_icon"))
|
|
{
|
|
mActionIcons["partial"] = getString("power_partial_icon");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LLPanelGroupSubTab::postBuild()
|
|
{
|
|
// Hook up the search widgets.
|
|
constexpr bool recurse = true;
|
|
|
|
mSearchEditor = findChild<LLFilterEditor>("filter_input", recurse);
|
|
if (mSearchEditor) // SubTab doesn't implement this, only some of derived classes
|
|
{
|
|
// panel
|
|
mSearchCommitConnection = mSearchEditor->setCommitCallback(boost::bind(&LLPanelGroupSubTab::setSearchFilter, this, _2));
|
|
}
|
|
|
|
return LLPanelGroupTab::postBuild();
|
|
}
|
|
|
|
void LLPanelGroupSubTab::setGroupID(const LLUUID& id)
|
|
{
|
|
LLPanelGroupTab::setGroupID(id);
|
|
if(mSearchEditor)
|
|
{
|
|
mSearchEditor->clear();
|
|
setSearchFilter("");
|
|
}
|
|
|
|
mActivated = false;
|
|
}
|
|
|
|
void LLPanelGroupSubTab::setSearchFilter(const std::string& filter)
|
|
{
|
|
if(mSearchFilter == filter)
|
|
return;
|
|
mSearchFilter = filter;
|
|
LLStringUtil::toLower(mSearchFilter);
|
|
update(GC_ALL);
|
|
onFilterChanged();
|
|
}
|
|
|
|
void LLPanelGroupSubTab::activate()
|
|
{
|
|
setOthersVisible(true);
|
|
}
|
|
|
|
void LLPanelGroupSubTab::deactivate()
|
|
{
|
|
setOthersVisible(false);
|
|
}
|
|
|
|
void LLPanelGroupSubTab::setOthersVisible(bool b)
|
|
{
|
|
if (mHeader)
|
|
{
|
|
mHeader->setVisible( b );
|
|
}
|
|
|
|
if (mFooter)
|
|
{
|
|
mFooter->setVisible( b );
|
|
}
|
|
}
|
|
|
|
bool LLPanelGroupSubTab::matchesActionSearchFilter(std::string action)
|
|
{
|
|
// If the search filter is empty, everything passes.
|
|
if (mSearchFilter.empty()) return true;
|
|
|
|
LLStringUtil::toLower(action);
|
|
std::string::size_type match = action.find(mSearchFilter);
|
|
|
|
if (std::string::npos == match)
|
|
{
|
|
// not found
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl,
|
|
U64 allowed_by_some,
|
|
U64 allowed_by_all,
|
|
LLUICtrl::commit_callback_t commit_callback,
|
|
bool show_all,
|
|
bool filter,
|
|
bool is_owner_role)
|
|
{
|
|
if (LLGroupMgr::getInstance()->mRoleActionSets.empty())
|
|
{
|
|
LL_WARNS() << "Can't build action list - no actions found." << LL_ENDL;
|
|
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,
|
|
allowed_by_some,
|
|
allowed_by_all,
|
|
(*ras_it),
|
|
commit_callback,
|
|
show_all,
|
|
filter,
|
|
is_owner_role);
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl,
|
|
U64 allowed_by_some,
|
|
U64 allowed_by_all,
|
|
LLRoleActionSet* action_set,
|
|
LLUICtrl::commit_callback_t commit_callback,
|
|
bool show_all,
|
|
bool filter,
|
|
bool is_owner_role)
|
|
{
|
|
LL_DEBUGS() << "Building role list for: " << action_set->mActionSetData->mName << LL_ENDL;
|
|
// See if the allow mask matches anything in this category.
|
|
if (show_all || (allowed_by_some & action_set->mActionSetData->mPowerBit))
|
|
{
|
|
// List all the actions in this category that at least some members have.
|
|
LLSD row;
|
|
|
|
row["columns"][0]["column"] = "icon";
|
|
row["columns"][0]["type"] = "icon";
|
|
|
|
icon_map_t::iterator iter = mActionIcons.find("folder");
|
|
if (iter != mActionIcons.end())
|
|
{
|
|
row["columns"][0]["value"] = (*iter).second;
|
|
}
|
|
|
|
row["columns"][1]["column"] = "action";
|
|
row["columns"][1]["type"] = "text";
|
|
row["columns"][1]["value"] = LLTrans::getString(action_set->mActionSetData->mName);
|
|
row["columns"][1]["font"]["name"] = "SANSSERIF_SMALL";
|
|
|
|
|
|
LLScrollListItem* title_row = ctrl->addElement(row, ADD_BOTTOM, action_set->mActionSetData);
|
|
|
|
LLScrollListText* name_textp = dynamic_cast<LLScrollListText*>(title_row->getColumn(2)); //?? I have no idea fix getColumn(1) return column spacer...
|
|
if (name_textp)
|
|
name_textp->setFontStyle(LLFontGL::BOLD);
|
|
|
|
bool category_matches_filter = (filter) ? matchesActionSearchFilter(action_set->mActionSetData->mName) : true;
|
|
|
|
std::vector<LLRoleAction*>::iterator ra_it = action_set->mActions.begin();
|
|
std::vector<LLRoleAction*>::iterator ra_end = action_set->mActions.end();
|
|
|
|
bool items_match_filter = false;
|
|
bool can_change_actions = (!is_owner_role && gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CHANGE_ACTIONS));
|
|
|
|
for ( ; ra_it != ra_end; ++ra_it)
|
|
{
|
|
// See if anyone has these action.
|
|
if (!show_all && !(allowed_by_some & (*ra_it)->mPowerBit))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// See if we are filtering out these actions
|
|
// If we aren't using filters, category_matches_filter will be true.
|
|
if (!category_matches_filter
|
|
&& !matchesActionSearchFilter((*ra_it)->mDescription))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
items_match_filter = true;
|
|
|
|
// See if everyone has these actions.
|
|
bool show_full_strength = false;
|
|
if ( (allowed_by_some & (*ra_it)->mPowerBit) == (allowed_by_all & (*ra_it)->mPowerBit) )
|
|
{
|
|
show_full_strength = true;
|
|
}
|
|
|
|
LLSD row;
|
|
|
|
S32 column_index = 0;
|
|
row["columns"][column_index]["column"] = "icon";
|
|
++column_index;
|
|
|
|
|
|
S32 check_box_index = -1;
|
|
if (commit_callback)
|
|
{
|
|
row["columns"][column_index]["column"] = "checkbox";
|
|
row["columns"][column_index]["type"] = "checkbox";
|
|
check_box_index = column_index;
|
|
++column_index;
|
|
}
|
|
else
|
|
{
|
|
if (show_full_strength)
|
|
{
|
|
icon_map_t::iterator iter = mActionIcons.find("full");
|
|
if (iter != mActionIcons.end())
|
|
{
|
|
row["columns"][column_index]["column"] = "checkbox";
|
|
row["columns"][column_index]["type"] = "icon";
|
|
row["columns"][column_index]["value"] = (*iter).second;
|
|
++column_index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
icon_map_t::iterator iter = mActionIcons.find("partial");
|
|
if (iter != mActionIcons.end())
|
|
{
|
|
row["columns"][column_index]["column"] = "checkbox";
|
|
row["columns"][column_index]["type"] = "icon";
|
|
row["columns"][column_index]["value"] = (*iter).second;
|
|
++column_index;
|
|
}
|
|
row["enabled"] = false;
|
|
}
|
|
}
|
|
|
|
row["columns"][column_index]["column"] = "action";
|
|
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)
|
|
{
|
|
// Extract the checkbox that was created.
|
|
LLScrollListCheck* check_cell = (LLScrollListCheck*) item->getColumn(check_box_index);
|
|
LLCheckBoxCtrl* check = check_cell->getCheckBox();
|
|
check->setEnabled(can_change_actions);
|
|
check->setCommitCallback(commit_callback);
|
|
check->setToolTip( check->getLabel() );
|
|
|
|
if (show_all)
|
|
{
|
|
check->setTentative(false);
|
|
if (allowed_by_some & (*ra_it)->mPowerBit)
|
|
{
|
|
check->set(true);
|
|
}
|
|
else
|
|
{
|
|
check->set(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
check->set(true);
|
|
if (show_full_strength)
|
|
{
|
|
check->setTentative(false);
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!items_match_filter)
|
|
{
|
|
S32 title_index = ctrl->getItemIndex(title_row);
|
|
ctrl->deleteSingleItem(title_index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupSubTab::setFooterEnabled(bool enable)
|
|
{
|
|
if (mFooter)
|
|
{
|
|
mFooter->setAllChildrenEnabled(enable);
|
|
}
|
|
}
|
|
|
|
// <FS:Ansariel> CTRL-F focusses local search editor
|
|
void LLPanelGroupSubTab::setSearchFilterFocus(bool focus)
|
|
{
|
|
mSearchEditor->setFocus(focus);
|
|
}
|
|
// </FS:Ansariel>
|
|
|
|
// LLPanelGroupMembersSubTab /////////////////////////////////////////////
|
|
static LLPanelInjector<LLPanelGroupMembersSubTab> t_panel_group_members_subtab("panel_group_members_subtab");
|
|
|
|
LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab()
|
|
: LLPanelGroupSubTab(),
|
|
mMembersList(NULL),
|
|
mAssignedRolesList(NULL),
|
|
mAllowedActionsList(NULL),
|
|
mChanged(false),
|
|
mPendingMemberUpdate(false),
|
|
mHasMatch(false),
|
|
mNumOwnerAdditions(0)
|
|
{
|
|
}
|
|
|
|
LLPanelGroupMembersSubTab::~LLPanelGroupMembersSubTab()
|
|
{
|
|
for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
|
|
{
|
|
if (it->second.connected())
|
|
{
|
|
it->second.disconnect();
|
|
}
|
|
}
|
|
mAvatarNameCacheConnections.clear();
|
|
if (mMembersList)
|
|
{
|
|
gSavedSettings.setString("GroupMembersSortOrder", mMembersList->getSortColumnName());
|
|
}
|
|
}
|
|
|
|
bool LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root)
|
|
{
|
|
LLPanelGroupSubTab::postBuildSubTab(root);
|
|
|
|
// Upcast parent so we can ask it for sibling controls.
|
|
LLPanelGroupRoles* parent = (LLPanelGroupRoles*) root;
|
|
|
|
// Look recursively from the parent to find all our widgets.
|
|
bool recurse = true;
|
|
mHeader = parent->findChild<LLPanel>("members_header", recurse);
|
|
mFooter = parent->findChild<LLPanel>("members_footer", recurse);
|
|
|
|
mMembersList = parent->getChild<LLNameListCtrl>("member_list", recurse);
|
|
mAssignedRolesList = parent->getChild<LLScrollListCtrl>("member_assigned_roles", recurse);
|
|
mAllowedActionsList = parent->getChild<LLScrollListCtrl>("member_allowed_actions", recurse);
|
|
// <FS:Ansariel> Undo changes from MAINT-2929
|
|
//mActionDescription = parent->getChild<LLTextEditor>("member_action_description", recurse);
|
|
|
|
//if (!mMembersList || !mAssignedRolesList || !mAllowedActionsList || !mActionDescription) return false;
|
|
|
|
//mAllowedActionsList->setCommitOnSelectionChange(true);
|
|
//mAllowedActionsList->setCommitCallback(boost::bind(&LLPanelGroupMembersSubTab::updateActionDescription, this));
|
|
if (!mMembersList || !mAssignedRolesList || !mAllowedActionsList) return false;
|
|
// </FS:Ansariel>
|
|
|
|
// We want to be notified whenever a member is selected.
|
|
mMembersList->setCommitOnSelectionChange(true);
|
|
mMembersList->setCommitCallback(onMemberSelect, this);
|
|
// Show the member's profile on double click.
|
|
mMembersList->setDoubleClickCallback(onMemberDoubleClick, this);
|
|
// <FS:Ansariel> Special Firestorm menu also allowing multi-select action
|
|
//mMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
|
|
mMembersList->setContextMenu(&gFSNameListAvatarMenu);
|
|
// </FS:Ansariel>
|
|
mMembersList->setIsFriendCallback(LLAvatarActions::isFriend);
|
|
|
|
LLSD row;
|
|
row["columns"][0]["column"] = "name";
|
|
row["columns"][1]["column"] = "donated";
|
|
row["columns"][2]["column"] = "online";
|
|
mMembersList->addElement(row);
|
|
std::string order_by = gSavedSettings.getString("GroupMembersSortOrder");
|
|
if(!order_by.empty())
|
|
{
|
|
mMembersList->sortByColumn(order_by, true);
|
|
}
|
|
|
|
LLButton* button = parent->getChild<LLButton>("member_invite", recurse);
|
|
if ( button )
|
|
{
|
|
button->setClickedCallback(onInviteMember, this);
|
|
button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE));
|
|
}
|
|
// [FS:CR] FIRE-12276
|
|
button = parent->getChild<LLButton>("export_list", recurse);
|
|
if (button)
|
|
{
|
|
button->setClickedCallback(boost::bind(&LLPanelGroupMembersSubTab::onExportMembersToXML, this));
|
|
button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_VISIBLE_IN_DIR));
|
|
}
|
|
// [/FS:CR]
|
|
|
|
mEjectBtn = parent->getChild<LLButton>("member_eject", recurse);
|
|
if ( mEjectBtn )
|
|
{
|
|
mEjectBtn->setClickedCallback(onEjectMembers, this);
|
|
mEjectBtn->setEnabled(false);
|
|
}
|
|
|
|
mBanBtn = parent->getChild<LLButton>("member_ban", recurse);
|
|
if(mBanBtn)
|
|
{
|
|
mBanBtn->setClickedCallback(onBanMember, this);
|
|
mBanBtn->setEnabled(false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id)
|
|
{
|
|
//clear members list
|
|
if(mMembersList) mMembersList->deleteAllItems();
|
|
if(mAssignedRolesList) mAssignedRolesList->deleteAllItems();
|
|
if(mAllowedActionsList) mAllowedActionsList->deleteAllItems();
|
|
|
|
LLPanelGroupSubTab::setGroupID(id);
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data)
|
|
{
|
|
LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
|
|
self->handleMemberSelect();
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::handleMemberSelect()
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupMembersSubTab::handleMemberSelect" << LL_ENDL;
|
|
|
|
mAssignedRolesList->deleteAllItems();
|
|
mAllowedActionsList->deleteAllItems();
|
|
//mActionDescription->clear(); // <FS:Ansariel> Undo changes from MAINT-2929
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupMembersSubTab::handleMemberSelect() "
|
|
<< "-- No group data!" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
// Check if there is anything selected.
|
|
std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
|
|
if (selection.empty()) return;
|
|
|
|
// Build a vector of all selected members, and gather allowed actions.
|
|
uuid_vec_t selected_members;
|
|
U64 allowed_by_all = GP_ALL_POWERS; //0xFFFFffffFFFFffffLL;
|
|
U64 allowed_by_some = 0;
|
|
|
|
std::vector<LLScrollListItem*>::iterator itor;
|
|
for (itor = selection.begin();
|
|
itor != selection.end(); ++itor)
|
|
{
|
|
LLUUID member_id = (*itor)->getUUID();
|
|
|
|
selected_members.push_back( member_id );
|
|
// Get this member's power mask including any unsaved changes
|
|
|
|
U64 powers = getAgentPowersBasedOnRoleChanges( member_id );
|
|
|
|
allowed_by_all &= powers;
|
|
allowed_by_some |= powers;
|
|
}
|
|
std::sort(selected_members.begin(), selected_members.end());
|
|
|
|
//////////////////////////////////
|
|
// Build the allowed actions list.
|
|
//////////////////////////////////
|
|
buildActionsList(mAllowedActionsList,
|
|
allowed_by_some,
|
|
allowed_by_all,
|
|
NULL,
|
|
false,
|
|
false,
|
|
false);
|
|
|
|
//////////////////////////////////
|
|
// Build the assigned roles list.
|
|
//////////////////////////////////
|
|
// Add each role to the assigned roles list.
|
|
LLGroupMgrGroupData::role_list_t::iterator iter = gdatap->mRoles.begin();
|
|
LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
|
|
|
|
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)
|
|
{
|
|
// Count how many selected users are in this role.
|
|
const LLUUID& role_id = iter->first;
|
|
LLGroupRoleData* group_role_data = iter->second;
|
|
|
|
if (group_role_data)
|
|
{
|
|
const bool needs_sort = false;
|
|
S32 count = group_role_data->getMembersInRole(
|
|
selected_members, needs_sort);
|
|
//check if the user has permissions to assign/remove
|
|
//members to/from the role (but the ability to add/remove
|
|
//should only be based on the "saved" changes to the role
|
|
//not in the temp/meta data. -jwolk
|
|
bool cb_enable = ( (count > 0) ?
|
|
agentCanRemoveFromRole(mGroupID, role_id) :
|
|
agentCanAddToRole(mGroupID, role_id) );
|
|
|
|
|
|
// Owner role has special enabling permissions for removal.
|
|
if (cb_enable && (count > 0) && role_id == gdatap->mOwnerRole)
|
|
{
|
|
// Check if any owners besides this agent are selected.
|
|
uuid_vec_t::const_iterator member_iter;
|
|
uuid_vec_t::const_iterator member_end =
|
|
selected_members.end();
|
|
for (member_iter = selected_members.begin();
|
|
member_iter != member_end;
|
|
++member_iter)
|
|
{
|
|
// Don't count the agent.
|
|
if ((*member_iter) == gAgent.getID()) continue;
|
|
|
|
// Look up the member data.
|
|
LLGroupMgrGroupData::member_list_t::iterator mi =
|
|
gdatap->mMembers.find((*member_iter));
|
|
if (mi == gdatap->mMembers.end()) continue;
|
|
LLGroupMemberData* member_data = (*mi).second;
|
|
// Is the member an owner?
|
|
if ( member_data && member_data->isInRole(gdatap->mOwnerRole) )
|
|
{
|
|
// Can't remove other owners.
|
|
cb_enable = false;
|
|
can_ban_members = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//now see if there are any role changes for the selected
|
|
//members and remember to include them
|
|
uuid_vec_t::iterator sel_mem_iter = selected_members.begin();
|
|
for (; sel_mem_iter != selected_members.end(); sel_mem_iter++)
|
|
{
|
|
LLRoleMemberChangeType type;
|
|
if ( getRoleChangeType(*sel_mem_iter, role_id, type) )
|
|
{
|
|
if ( type == RMC_ADD ) count++;
|
|
else if ( type == RMC_REMOVE ) count--;
|
|
}
|
|
}
|
|
|
|
// If anyone selected is in any role besides 'Everyone' then they can't be ejected.
|
|
if (role_id.notNull() && (count > 0))
|
|
{
|
|
can_eject_members = false;
|
|
if (role_id == gdatap->mOwnerRole)
|
|
{
|
|
member_is_owner = true;
|
|
}
|
|
}
|
|
|
|
LLRoleData rd;
|
|
if (gdatap->getRoleData(role_id,rd))
|
|
{
|
|
std::ostringstream label;
|
|
label << rd.mRoleName;
|
|
// Don't bother showing a count, if there is only 0 or 1.
|
|
if (count > 1)
|
|
{
|
|
label << ": " << count ;
|
|
}
|
|
|
|
LLSD row;
|
|
row["id"] = role_id;
|
|
|
|
row["columns"][0]["column"] = "checkbox";
|
|
row["columns"][0]["type"] = "checkbox";
|
|
|
|
row["columns"][1]["column"] = "role";
|
|
row["columns"][1]["value"] = label.str();
|
|
|
|
if (row["id"].asUUID().isNull())
|
|
{
|
|
// This is the everyone role, you can't take people out of the everyone role!
|
|
row["enabled"] = false;
|
|
}
|
|
|
|
LLScrollListItem* item = mAssignedRolesList->addElement(row);
|
|
|
|
// Extract the checkbox that was created.
|
|
LLScrollListCheck* check_cell = (LLScrollListCheck*) item->getColumn(0);
|
|
LLCheckBoxCtrl* check = check_cell->getCheckBox();
|
|
check->setCommitCallback(onRoleCheck, this);
|
|
check->set( count > 0 );
|
|
check->setTentative(
|
|
(0 != count)
|
|
&& (selected_members.size() !=
|
|
(uuid_vec_t::size_type)count));
|
|
|
|
//NOTE: as of right now a user can break the group
|
|
//by removing himself from a role if he is the
|
|
//last owner. We should check for this special case
|
|
// -jwolk
|
|
check->setEnabled(cb_enable);
|
|
item->setEnabled(cb_enable);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This could happen if changes are not synced right on sub-panel change.
|
|
LL_WARNS() << "No group role data for " << iter->second << LL_ENDL;
|
|
}
|
|
}
|
|
mAssignedRolesList->setEnabled(true);
|
|
|
|
if (gAgent.isGodlike())
|
|
{
|
|
can_eject_members = true;
|
|
// can_ban_members = true;
|
|
}
|
|
|
|
if (!can_eject_members && !member_is_owner)
|
|
{
|
|
// Maybe we can eject them because we are an owner...
|
|
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_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);
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupMembersSubTab::onMemberDoubleClick(void* user_data)
|
|
{
|
|
LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
|
|
self->handleMemberDoubleClick();
|
|
}
|
|
|
|
//static
|
|
void LLPanelGroupMembersSubTab::onInviteMember(void *userdata)
|
|
{
|
|
LLPanelGroupMembersSubTab* selfp = (LLPanelGroupMembersSubTab*) userdata;
|
|
|
|
if ( selfp )
|
|
{
|
|
selfp->handleInviteMember();
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::handleInviteMember()
|
|
{
|
|
LLFloaterGroupInvite::showForGroup(mGroupID, NULL, false);
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::onEjectMembers(void *userdata)
|
|
{
|
|
LLPanelGroupMembersSubTab* selfp = (LLPanelGroupMembersSubTab*) userdata;
|
|
|
|
if ( selfp )
|
|
{
|
|
selfp->confirmEjectMembers();
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::confirmEjectMembers()
|
|
{
|
|
std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
|
|
if (selection.empty()) return;
|
|
|
|
auto selection_count = selection.size();
|
|
if (selection_count == 1)
|
|
{
|
|
LLSD args;
|
|
// <FS:Ansariel> FIRE-19529: Group eject dialog doesn't show avatar name
|
|
//LLAvatarName av_name;
|
|
//LLAvatarNameCache::get(mMembersList->getValue(), &av_name);
|
|
//args["AVATAR_NAME"] = av_name.getUserName();
|
|
args["AVATAR_NAME"] = LLSLURL("agent", mMembersList->getValue().asUUID(), "completename").getSLURLString();
|
|
// <FS:Ansariel>
|
|
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));
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::handleEjectMembers()
|
|
{
|
|
//send down an eject message
|
|
uuid_vec_t selected_members;
|
|
|
|
std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
|
|
if (selection.empty()) return;
|
|
|
|
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);
|
|
}
|
|
|
|
bool LLPanelGroupMembersSubTab::handleEjectCallback(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
if (0 == option) // Eject button
|
|
{
|
|
handleEjectMembers();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members)
|
|
{
|
|
LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id);
|
|
|
|
if (group_data)
|
|
{
|
|
for (uuid_vec_t::const_iterator i = selected_members.begin(); i != selected_members.end(); ++i)
|
|
{
|
|
LLSD args;
|
|
args["AVATAR_NAME"] = LLSLURL("agent", *i, "completename").getSLURLString();
|
|
args["GROUP_NAME"] = group_data->mName;
|
|
|
|
LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args));
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id,
|
|
LLRoleMemberChangeType type)
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap) return;
|
|
|
|
//add that the user is requesting to change the roles for selected
|
|
//members
|
|
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())
|
|
{
|
|
return;
|
|
}
|
|
|
|
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
|
|
if ( mMemberRoleChangeData.find(member_id) == mMemberRoleChangeData.end() )
|
|
{
|
|
mMemberRoleChangeData[member_id] = new role_change_data_map_t;
|
|
}
|
|
role_change_data_map_t* role_change_datap = mMemberRoleChangeData[member_id];
|
|
|
|
//now check to see if the selected group member
|
|
//had changed his association with the selected role before
|
|
|
|
role_change_data_map_t::iterator role = role_change_datap->find(role_id);
|
|
if ( role != role_change_datap->end() )
|
|
{
|
|
//see if the new change type cancels out the previous change
|
|
if (role->second != type)
|
|
{
|
|
role_change_datap->erase(role_id);
|
|
if ( is_owner_role ) mNumOwnerAdditions--;
|
|
}
|
|
//else do nothing
|
|
|
|
if ( role_change_datap->empty() )
|
|
{
|
|
//the current member now has no role changes
|
|
//so erase the role change and erase the member's entry
|
|
delete role_change_datap;
|
|
role_change_datap = NULL;
|
|
|
|
mMemberRoleChangeData.erase(member_id);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//a previously unchanged role is being changed
|
|
(*role_change_datap)[role_id] = type;
|
|
if ( is_owner_role && type == RMC_ADD ) mNumOwnerAdditions++;
|
|
}
|
|
|
|
//we need to calculate what powers the selected members
|
|
//have (including the role changes we're making)
|
|
//so that we can rebuild the action list
|
|
U64 new_powers = getAgentPowersBasedOnRoleChanges(member_id);
|
|
|
|
powers_all_have &= new_powers;
|
|
powers_some_have |= new_powers;
|
|
}
|
|
|
|
|
|
mChanged = !mMemberRoleChangeData.empty();
|
|
notifyObservers();
|
|
|
|
//alrighty now we need to update the actions list
|
|
//to reflect the changes
|
|
mAllowedActionsList->deleteAllItems();
|
|
buildActionsList(mAllowedActionsList,
|
|
powers_some_have,
|
|
powers_all_have,
|
|
NULL,
|
|
false,
|
|
false,
|
|
false);
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data)
|
|
{
|
|
LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
|
|
LLCheckBoxCtrl* check_box = static_cast<LLCheckBoxCtrl*>(ctrl);
|
|
if (!check_box || !self) return;
|
|
|
|
LLScrollListItem* first_selected =
|
|
self->mAssignedRolesList->getFirstSelected();
|
|
if (first_selected)
|
|
{
|
|
LLUUID role_id = first_selected->getUUID();
|
|
LLRoleMemberChangeType change_type = (check_box->get() ?
|
|
RMC_ADD :
|
|
RMC_REMOVE);
|
|
|
|
self->handleRoleCheck(role_id, change_type);
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::handleMemberDoubleClick()
|
|
{
|
|
LLScrollListItem* selected = mMembersList->getFirstSelected();
|
|
if (selected)
|
|
{
|
|
LLUUID member_id = selected->getUUID();
|
|
LLAvatarActions::showProfile( member_id );
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::activate()
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
LLPanelGroupSubTab::activate();
|
|
if(!mActivated)
|
|
{
|
|
if (!gdatap || !gdatap->isMemberDataComplete())
|
|
{
|
|
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
|
|
}
|
|
|
|
if (!gdatap || !gdatap->isRoleMemberDataComplete())
|
|
{
|
|
LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID);
|
|
}
|
|
|
|
update(GC_ALL);
|
|
mActivated = true;
|
|
}
|
|
else
|
|
{
|
|
// Members can be removed outside of this tab, checking changes
|
|
if (!gdatap || (gdatap->isMemberDataComplete() && gdatap->mMembers.size() != mMembersList->getItemCount()))
|
|
{
|
|
update(GC_MEMBER_DATA);
|
|
}
|
|
}
|
|
//mActionDescription->clear(); // <FS:Ansariel> Undo changes from MAINT-2929
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::deactivate()
|
|
{
|
|
LLPanelGroupSubTab::deactivate();
|
|
}
|
|
|
|
bool LLPanelGroupMembersSubTab::needsApply(std::string& mesg)
|
|
{
|
|
return mChanged;
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::cancel()
|
|
{
|
|
if ( mChanged )
|
|
{
|
|
std::for_each(mMemberRoleChangeData.begin(),
|
|
mMemberRoleChangeData.end(),
|
|
DeletePairedPointer());
|
|
mMemberRoleChangeData.clear();
|
|
|
|
mChanged = false;
|
|
notifyObservers();
|
|
}
|
|
}
|
|
|
|
bool LLPanelGroupMembersSubTab::apply(std::string& mesg)
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "Unable to get group data for group " << mGroupID << LL_ENDL;
|
|
|
|
mesg.assign("Unable to save member data. Try again later.");
|
|
return false;
|
|
}
|
|
|
|
if (mChanged)
|
|
{
|
|
//figure out if we are somehow adding an owner or not and alert
|
|
//the user...possibly make it ignorable
|
|
if ( mNumOwnerAdditions > 0 )
|
|
{
|
|
LLRoleData rd;
|
|
LLSD args;
|
|
|
|
if ( gdatap->getRoleData(gdatap->mOwnerRole, rd) )
|
|
{
|
|
mHasModal = true;
|
|
args["ROLE_NAME"] = rd.mRoleName;
|
|
LLNotificationsUtil::add("AddGroupOwnerWarning",
|
|
args,
|
|
LLSD(),
|
|
boost::bind(&LLPanelGroupMembersSubTab::addOwnerCB, this, _1, _2));
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS() << "Unable to get role information for the owner role in group " << mGroupID << LL_ENDL;
|
|
|
|
mesg.assign("Unable to retried specific group information. Try again later");
|
|
return false;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
applyMemberChanges();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LLPanelGroupMembersSubTab::addOwnerCB(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
mHasModal = false;
|
|
|
|
if (0 == option)
|
|
{
|
|
// User clicked "Yes"
|
|
applyMemberChanges();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::applyMemberChanges()
|
|
{
|
|
//sucks to do a find again here, but it is in constant time, so, could
|
|
//be worse
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "Unable to get group data for group " << mGroupID << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
//we need to add all of the changed roles data
|
|
//for each member whose role changed
|
|
for (member_role_changes_map_t::iterator member = mMemberRoleChangeData.begin();
|
|
member != mMemberRoleChangeData.end(); ++member)
|
|
{
|
|
for (role_change_data_map_t::iterator role = member->second->begin();
|
|
role != member->second->end(); ++role)
|
|
{
|
|
gdatap->changeRoleMember(role->first, //role_id
|
|
member->first, //member_id
|
|
role->second); //add/remove
|
|
}
|
|
|
|
member->second->clear();
|
|
delete member->second;
|
|
}
|
|
mMemberRoleChangeData.clear();
|
|
|
|
LLGroupMgr::getInstance()->sendGroupRoleMemberChanges(mGroupID);
|
|
//force a UI update
|
|
handleMemberSelect();
|
|
|
|
mChanged = false;
|
|
mNumOwnerAdditions = 0;
|
|
notifyObservers();
|
|
}
|
|
|
|
bool LLPanelGroupMembersSubTab::matchesSearchFilter(const std::string& fullname)
|
|
{
|
|
// If the search filter is empty, everything passes.
|
|
if (mSearchFilter.empty()) return true;
|
|
|
|
// Create a full name, and compare it to the search filter.
|
|
std::string fullname_lc(fullname);
|
|
LLStringUtil::toLower(fullname_lc);
|
|
|
|
std::string::size_type match = fullname_lc.find(mSearchFilter);
|
|
|
|
if (std::string::npos == match)
|
|
{
|
|
// not found
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
U64 LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges(const LLUUID& agent_id)
|
|
{
|
|
//we loop over all of the changes
|
|
//if we are adding a role, then we simply add the role's powers
|
|
//if we are removing a role, we store that role id away
|
|
//and then we have to build the powers up bases on the roles the agent
|
|
//is in
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No group data!" << LL_ENDL;
|
|
return GP_NO_POWERS;
|
|
}
|
|
|
|
LLGroupMgrGroupData::member_list_t::iterator iter = gdatap->mMembers.find(agent_id);
|
|
if ( iter == gdatap->mMembers.end() )
|
|
{
|
|
LL_WARNS() << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No member data for member with UUID " << agent_id << LL_ENDL;
|
|
return GP_NO_POWERS;
|
|
}
|
|
|
|
LLGroupMemberData* member_data = (*iter).second;
|
|
if (!member_data)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- Null member data for member with UUID " << agent_id << LL_ENDL;
|
|
return GP_NO_POWERS;
|
|
}
|
|
|
|
//see if there are unsaved role changes for this agent
|
|
role_change_data_map_t* role_change_datap = NULL;
|
|
member_role_changes_map_t::iterator member = mMemberRoleChangeData.find(agent_id);
|
|
if ( member != mMemberRoleChangeData.end() )
|
|
{
|
|
//this member has unsaved role changes
|
|
//so grab them
|
|
role_change_datap = (*member).second;
|
|
}
|
|
|
|
U64 new_powers = GP_NO_POWERS;
|
|
|
|
if ( role_change_datap )
|
|
{
|
|
uuid_vec_t roles_to_be_removed;
|
|
|
|
for (role_change_data_map_t::iterator role = role_change_datap->begin();
|
|
role != role_change_datap->end(); ++ role)
|
|
{
|
|
if ( role->second == RMC_ADD )
|
|
{
|
|
new_powers |= gdatap->getRolePowers(role->first);
|
|
}
|
|
else
|
|
{
|
|
roles_to_be_removed.push_back(role->first);
|
|
}
|
|
}
|
|
|
|
//loop over the member's current roles, summing up
|
|
//the powers (not including the role we are removing)
|
|
for (LLGroupMemberData::role_list_t::iterator current_role = member_data->roleBegin();
|
|
current_role != member_data->roleEnd(); ++current_role)
|
|
{
|
|
bool role_in_remove_list =
|
|
(std::find(roles_to_be_removed.begin(),
|
|
roles_to_be_removed.end(),
|
|
current_role->second->getID()) !=
|
|
roles_to_be_removed.end());
|
|
|
|
if ( !role_in_remove_list )
|
|
{
|
|
new_powers |=
|
|
current_role->second->getRoleData().mRolePowers;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//there are no changes for this member
|
|
//the member's powers are just the ones stored in the group
|
|
//manager
|
|
new_powers = member_data->getAgentPowers();
|
|
}
|
|
|
|
return new_powers;
|
|
}
|
|
|
|
//If there is no change, returns false be sure to verify
|
|
//that there is a role change before attempting to get it or else
|
|
//the data will make no sense. Stores the role change type
|
|
bool LLPanelGroupMembersSubTab::getRoleChangeType(const LLUUID& member_id,
|
|
const LLUUID& role_id,
|
|
LLRoleMemberChangeType& type)
|
|
{
|
|
member_role_changes_map_t::iterator member_changes_iter = mMemberRoleChangeData.find(member_id);
|
|
if ( member_changes_iter != mMemberRoleChangeData.end() )
|
|
{
|
|
role_change_data_map_t::iterator role_changes_iter = member_changes_iter->second->find(role_id);
|
|
if ( role_changes_iter != member_changes_iter->second->end() )
|
|
{
|
|
type = role_changes_iter->second;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::draw()
|
|
{
|
|
LLPanelGroupSubTab::draw();
|
|
|
|
if (mPendingMemberUpdate)
|
|
{
|
|
updateMembers();
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::update(LLGroupChange gc)
|
|
{
|
|
if (mGroupID.isNull()) return;
|
|
|
|
if ( GC_TITLES == gc || GC_PROPERTIES == gc )
|
|
{
|
|
// Don't care about title or general group properties updates.
|
|
return;
|
|
}
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupMembersSubTab::update() -- No group data!" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
// Wait for both all data to be retrieved before displaying anything.
|
|
if ( gdatap->isMemberDataComplete()
|
|
&& gdatap->isRoleDataComplete()
|
|
&& gdatap->isRoleMemberDataComplete())
|
|
{
|
|
mMemberProgress = gdatap->mMembers.begin();
|
|
mPendingMemberUpdate = true;
|
|
mHasMatch = false;
|
|
}
|
|
else
|
|
{
|
|
// Build a string with info on retrieval progress.
|
|
std::ostringstream retrieved;
|
|
|
|
if ( gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && !gdatap->mMembers.size() )
|
|
{
|
|
// MAINT-5237
|
|
retrieved << "Member list not available.";
|
|
}
|
|
else if ( !gdatap->isMemberDataComplete() )
|
|
{
|
|
// Still busy retreiving member list.
|
|
retrieved << "Retrieving member list (" << gdatap->mMembers.size()
|
|
<< " / " << gdatap->mMemberCount << ")...";
|
|
}
|
|
else if( !gdatap->isRoleDataComplete() )
|
|
{
|
|
// Still busy retreiving role list.
|
|
retrieved << "Retrieving role list (" << gdatap->mRoles.size()
|
|
<< " / " << gdatap->mRoleCount << ")...";
|
|
}
|
|
else // (!gdatap->isRoleMemberDataComplete())
|
|
{
|
|
// Still busy retreiving role/member mappings.
|
|
retrieved << "Retrieving role member mappings...";
|
|
}
|
|
mMembersList->setEnabled(false);
|
|
mMembersList->setCommentText(retrieved.str());
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::addMemberToList(LLGroupMemberData* data)
|
|
{
|
|
if (!data) return;
|
|
LLUIString donated = getString("donation_area");
|
|
donated.setArg("[AREA]", llformat("%d", data->getContribution()));
|
|
|
|
LLNameListCtrl::NameItem item_params;
|
|
item_params.value = data->getID();
|
|
|
|
item_params.columns.add().column("name").font.name("SANSSERIF_SMALL").style("NORMAL");
|
|
|
|
item_params.columns.add().column("donated").value(donated.getString())
|
|
.font.name("SANSSERIF_SMALL").style("NORMAL");
|
|
|
|
item_params.columns.add().column("online").value(data->getOnlineStatus())
|
|
.font.name("SANSSERIF_SMALL").style("NORMAL");
|
|
|
|
item_params.columns.add().column("title").value(data->getTitle()).font.name("SANSSERIF_SMALL").style("NORMAL");;
|
|
|
|
mMembersList->addNameItemRow(item_params);
|
|
|
|
mHasMatch = true;
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name, const LLUUID& av_id)
|
|
{
|
|
avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(av_id);
|
|
if (it != mAvatarNameCacheConnections.end())
|
|
{
|
|
if (it->second.connected())
|
|
{
|
|
it->second.disconnect();
|
|
}
|
|
mAvatarNameCacheConnections.erase(it);
|
|
}
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap
|
|
|| gdatap->getMemberVersion() != update_id
|
|
|| !member)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// trying to avoid unnecessary hash lookups
|
|
// <FS:CR> FIRE-11350
|
|
//if (matchesSearchFilter(av_name.getAccountName()))
|
|
if (matchesSearchFilter(av_name.getCompleteName()))
|
|
// </FS:CR>
|
|
{
|
|
addMemberToList(member);
|
|
if(!mMembersList->getEnabled())
|
|
{
|
|
mMembersList->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::updateMembers()
|
|
{
|
|
mPendingMemberUpdate = false;
|
|
|
|
// Rebuild the members list.
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
// Make sure all data is still complete. Incomplete data
|
|
// may occur if we refresh.
|
|
if ( !gdatap->isMemberDataComplete()
|
|
|| !gdatap->isRoleDataComplete()
|
|
|| !gdatap->isRoleMemberDataComplete())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//cleanup list only for first iteration
|
|
if(mMemberProgress == gdatap->mMembers.begin())
|
|
{
|
|
mMembersList->deleteAllItems();
|
|
}
|
|
|
|
// <FS:Ansariel> Clear old callbacks so we don't end up adding people twice
|
|
for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
|
|
{
|
|
if (it->second.connected())
|
|
{
|
|
it->second.disconnect();
|
|
}
|
|
}
|
|
mAvatarNameCacheConnections.clear();
|
|
// </FS:Ansariel>
|
|
|
|
LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
|
|
|
|
LLTimer update_time;
|
|
update_time.setTimerExpirySec(UPDATE_MEMBERS_SECONDS_PER_FRAME);
|
|
|
|
for( ; mMemberProgress != end && !update_time.hasExpired(); ++mMemberProgress)
|
|
{
|
|
if (!mMemberProgress->second)
|
|
continue;
|
|
|
|
// Do filtering on name if it is already in the cache.
|
|
LLAvatarName av_name;
|
|
if (LLAvatarNameCache::get(mMemberProgress->first, &av_name))
|
|
{
|
|
// <FS:CR> FIRE-11350
|
|
//if (matchesSearchFilter(av_name.getAccountName()))
|
|
if (matchesSearchFilter(av_name.getCompleteName()))
|
|
// </FS:CR>
|
|
{
|
|
addMemberToList(mMemberProgress->second);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If name is not cached, onNameCache() should be called when it is cached and add this member to list.
|
|
avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(mMemberProgress->first);
|
|
if (it != mAvatarNameCacheConnections.end())
|
|
{
|
|
if (it->second.connected())
|
|
{
|
|
it->second.disconnect();
|
|
}
|
|
mAvatarNameCacheConnections.erase(it);
|
|
}
|
|
mAvatarNameCacheConnections[mMemberProgress->first] = LLAvatarNameCache::get(mMemberProgress->first, boost::bind(&LLPanelGroupMembersSubTab::onNameCache, this, gdatap->getMemberVersion(), mMemberProgress->second, _2, _1));
|
|
}
|
|
}
|
|
|
|
if (mMemberProgress == end)
|
|
{
|
|
if (mHasMatch)
|
|
{
|
|
mMembersList->setEnabled(true);
|
|
}
|
|
else if (gdatap->mMembers.size())
|
|
{
|
|
mMembersList->setEnabled(false);
|
|
mMembersList->setCommentText(std::string("No match."));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mPendingMemberUpdate = true;
|
|
}
|
|
|
|
// This should clear the other two lists, since nothing is selected.
|
|
handleMemberSelect();
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::onBanMember(void* user_data)
|
|
{
|
|
LLPanelGroupMembersSubTab* self = static_cast<LLPanelGroupMembersSubTab*>(user_data);
|
|
self->confirmBanMembers();
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::confirmBanMembers()
|
|
{
|
|
std::vector<LLScrollListItem*> selection = mMembersList->getAllSelected();
|
|
if (selection.empty()) return;
|
|
|
|
auto selection_count = selection.size();
|
|
if (selection_count == 1)
|
|
{
|
|
LLSD args;
|
|
LLAvatarName av_name;
|
|
LLAvatarNameCache::get(mMembersList->getValue(), &av_name);
|
|
args["AVATAR_NAME"] = av_name.getUserName();
|
|
LLSD payload;
|
|
LLNotificationsUtil::add("BanGroupMemberWarning",
|
|
args,
|
|
payload,
|
|
boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
|
|
}
|
|
else
|
|
{
|
|
LLSD args;
|
|
args["COUNT"] = llformat("%d", selection_count);
|
|
LLSD payload;
|
|
LLNotificationsUtil::add("BanGroupMembersWarning",
|
|
args,
|
|
payload,
|
|
boost::bind(&LLPanelGroupMembersSubTab::handleBanCallback, this, _1, _2));
|
|
}
|
|
}
|
|
|
|
bool LLPanelGroupMembersSubTab::handleBanCallback(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
if (0 == option) // Eject button
|
|
{
|
|
handleBanMember();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::updateActionDescription()
|
|
{
|
|
mActionDescription->setText(std::string());
|
|
LLScrollListItem* action_item = mAllowedActionsList->getFirstSelected();
|
|
if (!action_item || !mAllowedActionsList->getCanSelect())
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata();
|
|
if (rap)
|
|
{
|
|
std::string desc = rap->mLongDescription.empty() ? rap->mDescription : rap->mLongDescription;
|
|
mActionDescription->setText(desc);
|
|
}
|
|
}
|
|
|
|
// [FS:CR] FIRE-12276
|
|
void LLPanelGroupMembersSubTab::onExportMembersToXML()
|
|
{
|
|
if (mPendingMemberUpdate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
LLFilePickerReplyThread::startPicker(boost::bind(&LLPanelGroupMembersSubTab::onExportMembersToXMLCallback, this, _1),
|
|
LLFilePicker::FFSAVE_CSV, LLDir::getScrubbedFileName(gdatap->mName + "_members.csv"));
|
|
}
|
|
|
|
void LLPanelGroupMembersSubTab::onExportMembersToXMLCallback(const std::vector<std::string>& filenames)
|
|
{
|
|
std::string fullpath = filenames[0];
|
|
|
|
LLAPRFile outfile;
|
|
outfile.open(fullpath, LL_APR_WB);
|
|
LLAPRFile::tFiletype* file = outfile.getFileHandle();
|
|
if (!file)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
apr_file_printf(file, "Group membership record for %s (avatar key, avatar name, last online, land contribution)", gdatap->mName.c_str());
|
|
|
|
LLSD memberlist;
|
|
for (LLGroupMgrGroupData::member_list_t::const_iterator member_itr = gdatap->mMembers.begin();
|
|
member_itr != gdatap->mMembers.end();
|
|
++member_itr)
|
|
{
|
|
/// *FIXME: Making an assumption that we already have the names in cache and getting names from
|
|
/// LLAvatarNameCache directly because I am lazy and don't want bugger with avatarname cache this morning.
|
|
/// When the group membership is fully loaded, this works fine as is.
|
|
LLAvatarName av_name;
|
|
LLAvatarNameCache::get(member_itr->first, &av_name);
|
|
apr_file_printf(file, "\n%s,%s,%s,%s",
|
|
member_itr->first.asString().c_str(),
|
|
av_name.getCompleteName().c_str(),
|
|
member_itr->second->getOnlineStatus().c_str(),
|
|
llformat("%d", member_itr->second->getContribution()).c_str());
|
|
}
|
|
apr_file_printf(file, "\n");
|
|
}
|
|
// [/FS:CR] FIRE-12276
|
|
|
|
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;
|
|
}
|
|
|
|
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()
|
|
: LLPanelGroupSubTab(),
|
|
mRolesList(NULL),
|
|
mAssignedMembersList(NULL),
|
|
mAllowedActionsList(NULL),
|
|
mRoleName(NULL),
|
|
mRoleTitle(NULL),
|
|
mRoleDescription(NULL),
|
|
mMemberVisibleCheck(NULL),
|
|
mDeleteRoleButton(NULL),
|
|
mCopyRoleButton(NULL),
|
|
mCreateRoleButton(NULL),
|
|
mFirstOpen(true),
|
|
mHasRoleChange(false)
|
|
{
|
|
}
|
|
|
|
LLPanelGroupRolesSubTab::~LLPanelGroupRolesSubTab()
|
|
{
|
|
}
|
|
|
|
bool LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root)
|
|
{
|
|
LLPanelGroupSubTab::postBuildSubTab(root);
|
|
|
|
// Upcast parent so we can ask it for sibling controls.
|
|
LLPanelGroupRoles* parent = (LLPanelGroupRoles*) root;
|
|
|
|
// Look recursively from the parent to find all our widgets.
|
|
bool recurse = true;
|
|
mHeader = parent->findChild<LLPanel>("roles_header", recurse);
|
|
mFooter = parent->findChild<LLPanel>("roles_footer", recurse);
|
|
|
|
|
|
mRolesList = parent->getChild<LLScrollListCtrl>("role_list", recurse);
|
|
mAssignedMembersList = parent->getChild<LLNameListCtrl>("role_assigned_members", recurse);
|
|
mAllowedActionsList = parent->getChild<LLScrollListCtrl>("role_allowed_actions", recurse);
|
|
//mActionDescription = parent->getChild<LLTextEditor>("role_action_description", recurse); // <FS:Ansariel> Undo changes from MAINT-2929
|
|
|
|
mRoleName = parent->getChild<LLLineEditor>("role_name", recurse);
|
|
mRoleTitle = parent->getChild<LLLineEditor>("role_title", recurse);
|
|
mRoleDescription = parent->getChild<LLTextEditor>("role_description", recurse);
|
|
|
|
mMemberVisibleCheck = parent->getChild<LLCheckBoxCtrl>("role_visible_in_list", recurse);
|
|
|
|
if (!mRolesList || !mAssignedMembersList || !mAllowedActionsList //|| !mActionDescription // <FS:Ansariel> Undo changes from MAINT-2929
|
|
|| !mRoleName || !mRoleTitle || !mRoleDescription || !mMemberVisibleCheck)
|
|
{
|
|
LL_WARNS() << "ARG! element not found." << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
mRemoveEveryoneTxt = getString("cant_delete_role");
|
|
|
|
mCreateRoleButton =
|
|
parent->getChild<LLButton>("role_create", recurse);
|
|
if ( mCreateRoleButton )
|
|
{
|
|
mCreateRoleButton->setClickedCallback(onCreateRole, this);
|
|
mCreateRoleButton->setEnabled(false);
|
|
}
|
|
|
|
mCopyRoleButton =
|
|
parent->getChild<LLButton>("role_copy", recurse);
|
|
if ( mCopyRoleButton )
|
|
{
|
|
mCopyRoleButton->setClickedCallback(onCopyRole, this);
|
|
mCopyRoleButton->setEnabled(false);
|
|
}
|
|
|
|
mDeleteRoleButton =
|
|
parent->getChild<LLButton>("role_delete", recurse);
|
|
if ( mDeleteRoleButton )
|
|
{
|
|
mDeleteRoleButton->setClickedCallback(onDeleteRole, this);
|
|
mDeleteRoleButton->setEnabled(false);
|
|
}
|
|
|
|
mRolesList->setCommitOnSelectionChange(true);
|
|
mRolesList->setCommitCallback(onRoleSelect, this);
|
|
|
|
// <FS:Ansariel> Special Firestorm menu also allowing multi-select action
|
|
//mAssignedMembersList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
|
|
mAssignedMembersList->setContextMenu(&gFSNameListAvatarMenu);
|
|
|
|
mMemberVisibleCheck->setCommitCallback(onMemberVisibilityChange, this);
|
|
|
|
mAllowedActionsList->setCommitOnSelectionChange(true);
|
|
//mAllowedActionsList->setCommitCallback(boost::bind(&LLPanelGroupRolesSubTab::updateActionDescription, this)); // <FS:Ansariel> Undo changes from MAINT-2929
|
|
|
|
mRoleName->setCommitOnFocusLost(true);
|
|
mRoleName->setKeystrokeCallback(onPropertiesKey, this);
|
|
|
|
mRoleTitle->setCommitOnFocusLost(true);
|
|
mRoleTitle->setKeystrokeCallback(onPropertiesKey, this);
|
|
|
|
mRoleDescription->setCommitOnFocusLost(true);
|
|
mRoleDescription->setKeystrokeCallback(boost::bind(&LLPanelGroupRolesSubTab::onDescriptionKeyStroke, this, _1));
|
|
|
|
setFooterEnabled(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::activate()
|
|
{
|
|
LLPanelGroupSubTab::activate();
|
|
|
|
//mActionDescription->clear(); // <FS:Ansariel> Undo changes from MAINT-2929
|
|
mRolesList->deselectAllItems();
|
|
mAssignedMembersList->deleteAllItems();
|
|
mAllowedActionsList->deleteAllItems();
|
|
mRoleName->clear();
|
|
mRoleDescription->clear();
|
|
mRoleTitle->clear();
|
|
|
|
setFooterEnabled(false);
|
|
|
|
mHasRoleChange = false;
|
|
update(GC_ALL);
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::deactivate()
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupRolesSubTab::deactivate()" << LL_ENDL;
|
|
|
|
LLPanelGroupSubTab::deactivate();
|
|
mFirstOpen = false;
|
|
}
|
|
|
|
bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg)
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupRolesSubTab::needsApply()" << LL_ENDL;
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if(!gdatap)
|
|
{
|
|
LL_WARNS() << "Unable to get group data for group " << mGroupID << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
|
|
return (mHasRoleChange // Text changed in current role
|
|
|| (gdatap && gdatap->pendingRoleChanges())); // Pending role changes in the group
|
|
}
|
|
|
|
bool LLPanelGroupRolesSubTab::apply(std::string& mesg)
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupRolesSubTab::apply()" << LL_ENDL;
|
|
|
|
saveRoleChanges(true);
|
|
mFirstOpen = false;
|
|
LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID);
|
|
|
|
notifyObservers();
|
|
|
|
return true;
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::cancel()
|
|
{
|
|
mHasRoleChange = false;
|
|
LLGroupMgr::getInstance()->cancelGroupRoleChanges(mGroupID);
|
|
|
|
notifyObservers();
|
|
}
|
|
|
|
LLSD LLPanelGroupRolesSubTab::createRoleItem(const LLUUID& role_id,
|
|
std::string name,
|
|
std::string title,
|
|
S32 members)
|
|
{
|
|
LLSD row;
|
|
row["id"] = role_id;
|
|
|
|
row["columns"][0]["column"] = "name";
|
|
row["columns"][0]["value"] = name;
|
|
|
|
row["columns"][1]["column"] = "title";
|
|
row["columns"][1]["value"] = title;
|
|
|
|
row["columns"][2]["column"] = "members";
|
|
row["columns"][2]["value"] = members;
|
|
|
|
return row;
|
|
}
|
|
|
|
bool LLPanelGroupRolesSubTab::matchesSearchFilter(std::string rolename, std::string roletitle)
|
|
{
|
|
// If the search filter is empty, everything passes.
|
|
if (mSearchFilter.empty()) return true;
|
|
|
|
LLStringUtil::toLower(rolename);
|
|
LLStringUtil::toLower(roletitle);
|
|
std::string::size_type match_name = rolename.find(mSearchFilter);
|
|
std::string::size_type match_title = roletitle.find(mSearchFilter);
|
|
|
|
if ( (std::string::npos == match_name)
|
|
&& (std::string::npos == match_title))
|
|
{
|
|
// not found
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::update(LLGroupChange gc)
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupRolesSubTab::update()" << LL_ENDL;
|
|
|
|
if (mGroupID.isNull()) return;
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
if (!gdatap || !gdatap->isRoleDataComplete())
|
|
{
|
|
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
|
|
}
|
|
else
|
|
{
|
|
bool had_selection = false;
|
|
LLUUID last_selected;
|
|
if (mRolesList->getFirstSelected())
|
|
{
|
|
last_selected = mRolesList->getFirstSelected()->getUUID();
|
|
had_selection = true;
|
|
}
|
|
mRolesList->deleteAllItems();
|
|
|
|
LLScrollListItem* item = NULL;
|
|
|
|
LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.begin();
|
|
LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
|
|
|
|
for ( ; rit != end; ++rit)
|
|
{
|
|
LLRoleData rd;
|
|
if (gdatap->getRoleData((*rit).first,rd))
|
|
{
|
|
if (matchesSearchFilter(rd.mRoleName, rd.mRoleTitle))
|
|
{
|
|
// If this is the everyone role, then EVERYONE is in it.
|
|
S32 members_in_role = (*rit).first.isNull() ? static_cast<S32>(gdatap->mMembers.size()) : (*rit).second->getTotalMembersInRole();
|
|
LLSD row = createRoleItem((*rit).first,rd.mRoleName, rd.mRoleTitle, members_in_role);
|
|
item = mRolesList->addElement(row, ((*rit).first.isNull()) ? ADD_TOP : ADD_BOTTOM, this);
|
|
if (had_selection && ((*rit).first == last_selected))
|
|
{
|
|
item->setSelected(true);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS() << "LLPanelGroupRolesSubTab::update() No role data for role " << (*rit).first << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
mRolesList->sortByColumn(std::string("name"), true);
|
|
|
|
if ( (gdatap->mRoles.size() < (U32)MAX_ROLES)
|
|
&& gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE) )
|
|
{
|
|
mCreateRoleButton->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
mCreateRoleButton->setEnabled(false);
|
|
}
|
|
|
|
if (had_selection)
|
|
{
|
|
handleRoleSelect();
|
|
}
|
|
else
|
|
{
|
|
mAssignedMembersList->deleteAllItems();
|
|
mAllowedActionsList->deleteAllItems();
|
|
mRoleName->clear();
|
|
mRoleDescription->clear();
|
|
mRoleTitle->clear();
|
|
setFooterEnabled(false);
|
|
mDeleteRoleButton->setEnabled(false);
|
|
mCopyRoleButton->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc)
|
|
&& gdatap
|
|
&& gdatap->isMemberDataComplete()
|
|
&& gdatap->isRoleMemberDataComplete())
|
|
{
|
|
buildMembersList();
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupRolesSubTab::onRoleSelect(LLUICtrl* ctrl, void* user_data)
|
|
{
|
|
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
|
|
if (!self)
|
|
return;
|
|
|
|
self->handleRoleSelect();
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::handleRoleSelect()
|
|
{
|
|
bool can_delete = true;
|
|
LL_DEBUGS() << "LLPanelGroupRolesSubTab::handleRoleSelect()" << LL_ENDL;
|
|
|
|
mAssignedMembersList->deleteAllItems();
|
|
mAllowedActionsList->deleteAllItems();
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() "
|
|
<< "-- No group data!" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
saveRoleChanges(false);
|
|
|
|
// Check if there is anything selected.
|
|
LLScrollListItem* item = mRolesList->getFirstSelected();
|
|
if (!item)
|
|
{
|
|
setFooterEnabled(false);
|
|
return;
|
|
}
|
|
|
|
setFooterEnabled(true);
|
|
|
|
LLRoleData rd;
|
|
if (gdatap->getRoleData(item->getUUID(),rd))
|
|
{
|
|
bool is_owner_role = ( gdatap->mOwnerRole == item->getUUID() );
|
|
mRoleName->setText(rd.mRoleName);
|
|
mRoleTitle->setText(rd.mRoleTitle);
|
|
mRoleDescription->setText(rd.mRoleDescription);
|
|
|
|
mAllowedActionsList->setEnabled(gAgent.hasPowerInGroup(mGroupID,
|
|
GP_ROLE_CHANGE_ACTIONS));
|
|
buildActionsList(mAllowedActionsList,
|
|
rd.mRolePowers,
|
|
0LL,
|
|
boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false),
|
|
true,
|
|
false,
|
|
is_owner_role);
|
|
|
|
|
|
mMemberVisibleCheck->set((rd.mRolePowers & GP_MEMBER_VISIBLE_IN_DIR) == GP_MEMBER_VISIBLE_IN_DIR);
|
|
mRoleName->setEnabled(!is_owner_role &&
|
|
gAgent.hasPowerInGroup(mGroupID, GP_ROLE_PROPERTIES));
|
|
mRoleTitle->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_ROLE_PROPERTIES));
|
|
mRoleDescription->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_ROLE_PROPERTIES));
|
|
|
|
if ( is_owner_role )
|
|
{
|
|
// you can't delete the owner role
|
|
can_delete = false;
|
|
// ... or hide members with this role
|
|
mMemberVisibleCheck->setEnabled(false);
|
|
}
|
|
else
|
|
{
|
|
mMemberVisibleCheck->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_ROLE_PROPERTIES));
|
|
}
|
|
|
|
if (item->getUUID().isNull())
|
|
{
|
|
// Everyone role, can't edit description or name or delete
|
|
mRoleDescription->setEnabled(false);
|
|
mRoleName->setEnabled(false);
|
|
can_delete = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mRolesList->deselectAllItems();
|
|
mAssignedMembersList->deleteAllItems();
|
|
mAllowedActionsList->deleteAllItems();
|
|
mRoleName->clear();
|
|
mRoleDescription->clear();
|
|
mRoleTitle->clear();
|
|
setFooterEnabled(false);
|
|
|
|
can_delete = false;
|
|
}
|
|
mSelectedRole = item->getUUID();
|
|
buildMembersList();
|
|
|
|
mCopyRoleButton->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE));
|
|
can_delete = can_delete && gAgent.hasPowerInGroup(mGroupID,
|
|
GP_ROLE_DELETE);
|
|
mDeleteRoleButton->setEnabled(can_delete);
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::buildMembersList()
|
|
{
|
|
mAssignedMembersList->deleteAllItems();
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() "
|
|
<< "-- No group data!" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
// Check if there is anything selected.
|
|
LLScrollListItem* item = mRolesList->getFirstSelected();
|
|
if (!item) return;
|
|
|
|
if (item->getUUID().isNull())
|
|
{
|
|
// Special cased 'Everyone' role
|
|
LLGroupMgrGroupData::member_list_t::iterator mit = gdatap->mMembers.begin();
|
|
LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
|
|
for ( ; mit != end; ++mit)
|
|
{
|
|
mAssignedMembersList->addNameItem((*mit).first);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.find(item->getUUID());
|
|
if (rit != gdatap->mRoles.end())
|
|
{
|
|
LLGroupRoleData* rdatap = (*rit).second;
|
|
if (rdatap)
|
|
{
|
|
uuid_vec_t::const_iterator mit = rdatap->getMembersBegin();
|
|
uuid_vec_t::const_iterator end = rdatap->getMembersEnd();
|
|
for ( ; mit != end; ++mit)
|
|
{
|
|
mAssignedMembersList->addNameItem((*mit));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ActionCBData
|
|
{
|
|
LLPanelGroupRolesSubTab* mSelf;
|
|
LLCheckBoxCtrl* mCheck;
|
|
};
|
|
|
|
void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force)
|
|
{
|
|
LLCheckBoxCtrl* check = dynamic_cast<LLCheckBoxCtrl*>(ctrl);
|
|
if (!check)
|
|
return;
|
|
|
|
LL_DEBUGS() << "LLPanelGroupRolesSubTab::handleActionSelect()" << LL_ENDL;
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() "
|
|
<< "-- No group data!" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
LLScrollListItem* action_item = mAllowedActionsList->getFirstSelected();
|
|
if (!action_item)
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLScrollListItem* role_item = mRolesList->getFirstSelected();
|
|
if (!role_item)
|
|
{
|
|
return;
|
|
}
|
|
LLUUID role_id = role_item->getUUID();
|
|
|
|
LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata();
|
|
U64 power = rap->mPowerBit;
|
|
|
|
bool isEnablingAbility = check->get();
|
|
LLRoleData rd;
|
|
LLSD args;
|
|
|
|
if (isEnablingAbility &&
|
|
!force &&
|
|
((GP_ROLE_ASSIGN_MEMBER == power) || (GP_ROLE_CHANGE_ACTIONS == power) ))
|
|
{
|
|
// Uncheck the item, for now. It will be
|
|
// checked if they click 'Yes', below.
|
|
check->set(false);
|
|
|
|
LLRoleData rd;
|
|
LLSD args;
|
|
|
|
if ( gdatap->getRoleData(role_id, rd) )
|
|
{
|
|
args["ACTION_NAME"] = rap->mDescription;
|
|
args["ROLE_NAME"] = rd.mRoleName;
|
|
mHasModal = true;
|
|
std::string warning = "AssignDangerousActionWarning";
|
|
if (GP_ROLE_CHANGE_ACTIONS == power)
|
|
{
|
|
warning = "AssignDangerousAbilityWarning";
|
|
}
|
|
LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check));
|
|
}
|
|
else
|
|
{
|
|
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
|
|
{
|
|
LL_WARNS() << "Unable to look up role information for role id: "
|
|
<< role_id << LL_ENDL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
U64 current_role_powers = gdatap->getRolePowers(role_id);
|
|
|
|
if(isEnablingAbility)
|
|
{
|
|
power |= (GP_ROLE_REMOVE_MEMBER | GP_MEMBER_EJECT);
|
|
current_role_powers |= power;
|
|
}
|
|
else
|
|
{
|
|
current_role_powers &= ~GP_GROUP_BAN_ACCESS;
|
|
}
|
|
|
|
mAllowedActionsList->deleteAllItems();
|
|
buildActionsList( mAllowedActionsList,
|
|
current_role_powers,
|
|
current_role_powers,
|
|
boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false),
|
|
true,
|
|
false,
|
|
false);
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Adding non-specific ability to role
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if(isEnablingAbility)
|
|
{
|
|
gdatap->addRolePower(role_id, power);
|
|
}
|
|
else
|
|
{
|
|
gdatap->removeRolePower(role_id,power);
|
|
}
|
|
|
|
mHasRoleChange = true;
|
|
notifyObservers();
|
|
|
|
}
|
|
|
|
bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check)
|
|
{
|
|
if (!check) return false;
|
|
|
|
mHasModal = false;
|
|
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
if (0 == option)
|
|
{
|
|
// User clicked "Yes"
|
|
check->set(true);
|
|
const bool force_add = true;
|
|
handleActionCheck(check, force_add);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_data)
|
|
{
|
|
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
|
|
if (!self) return;
|
|
|
|
self->mHasRoleChange = true;
|
|
self->notifyObservers();
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::onDescriptionKeyStroke(LLTextEditor* caller)
|
|
{
|
|
mHasRoleChange = true;
|
|
notifyObservers();
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupRolesSubTab::onDescriptionCommit(LLUICtrl* ctrl, void* user_data)
|
|
{
|
|
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
|
|
if (!self) return;
|
|
|
|
self->mHasRoleChange = true;
|
|
self->notifyObservers();
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupRolesSubTab::onMemberVisibilityChange(LLUICtrl* ctrl, void* user_data)
|
|
{
|
|
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
|
|
LLCheckBoxCtrl* check = static_cast<LLCheckBoxCtrl*>(ctrl);
|
|
if (!check || !self) return;
|
|
|
|
self->handleMemberVisibilityChange(check->get());
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::handleMemberVisibilityChange(bool value)
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupRolesSubTab::handleMemberVisibilityChange()" << LL_ENDL;
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (!gdatap)
|
|
{
|
|
LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() "
|
|
<< "-- No group data!" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
LLScrollListItem* role_item = mRolesList->getFirstSelected();
|
|
if (!role_item)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (value)
|
|
{
|
|
gdatap->addRolePower(role_item->getUUID(),GP_MEMBER_VISIBLE_IN_DIR);
|
|
}
|
|
else
|
|
{
|
|
gdatap->removeRolePower(role_item->getUUID(),GP_MEMBER_VISIBLE_IN_DIR);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupRolesSubTab::onCreateRole(void* user_data)
|
|
{
|
|
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
|
|
if (!self) return;
|
|
|
|
self->handleCreateRole();
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::handleCreateRole()
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
if (!gdatap) return;
|
|
|
|
LLUUID new_role_id;
|
|
new_role_id.generate();
|
|
|
|
LLRoleData rd;
|
|
rd.mRoleName = "New Role";
|
|
gdatap->createRole(new_role_id,rd);
|
|
|
|
mRolesList->deselectAllItems(true);
|
|
LLSD row;
|
|
row["id"] = new_role_id;
|
|
row["columns"][0]["column"] = "name";
|
|
row["columns"][0]["value"] = rd.mRoleName;
|
|
mRolesList->addElement(row, ADD_BOTTOM, this);
|
|
mRolesList->selectByID(new_role_id);
|
|
|
|
// put focus on name field and select its contents
|
|
if(mRoleName)
|
|
{
|
|
mRoleName->setFocus(true);
|
|
mRoleName->onTabInto();
|
|
gFocusMgr.triggerFocusFlash();
|
|
}
|
|
|
|
notifyObservers();
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupRolesSubTab::onCopyRole(void* user_data)
|
|
{
|
|
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
|
|
if (!self) return;
|
|
|
|
self->handleCopyRole();
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::handleCopyRole()
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
if (!gdatap) return;
|
|
|
|
LLScrollListItem* role_item = mRolesList->getFirstSelected();
|
|
if (!role_item || role_item->getUUID().isNull())
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLRoleData rd;
|
|
if (!gdatap->getRoleData(role_item->getUUID(), rd))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLUUID new_role_id;
|
|
new_role_id.generate();
|
|
rd.mRoleName += "(Copy)";
|
|
gdatap->createRole(new_role_id,rd);
|
|
|
|
mRolesList->deselectAllItems(true);
|
|
LLSD row;
|
|
row["id"] = new_role_id;
|
|
row["columns"][0]["column"] = "name";
|
|
row["columns"][0]["value"] = rd.mRoleName;
|
|
mRolesList->addElement(row, ADD_BOTTOM, this);
|
|
mRolesList->selectByID(new_role_id);
|
|
|
|
// put focus on name field and select its contents
|
|
if(mRoleName)
|
|
{
|
|
mRoleName->setFocus(true);
|
|
mRoleName->onTabInto();
|
|
gFocusMgr.triggerFocusFlash();
|
|
}
|
|
|
|
notifyObservers();
|
|
}
|
|
|
|
// static
|
|
void LLPanelGroupRolesSubTab::onDeleteRole(void* user_data)
|
|
{
|
|
LLPanelGroupRolesSubTab* self = static_cast<LLPanelGroupRolesSubTab*>(user_data);
|
|
if (!self) return;
|
|
|
|
self->handleDeleteRole();
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::handleDeleteRole()
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
if (!gdatap) return;
|
|
|
|
LLScrollListItem* role_item = mRolesList->getFirstSelected();
|
|
if (!role_item)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (role_item->getUUID().isNull() || role_item->getUUID() == gdatap->mOwnerRole)
|
|
{
|
|
LLSD args;
|
|
args["MESSAGE"] = mRemoveEveryoneTxt;
|
|
LLNotificationsUtil::add("GenericAlert", args);
|
|
return;
|
|
}
|
|
|
|
gdatap->deleteRole(role_item->getUUID());
|
|
mRolesList->deleteSingleItem(mRolesList->getFirstSelectedIndex());
|
|
mRolesList->selectFirstItem();
|
|
|
|
notifyObservers();
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role)
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
if (!gdatap) return;
|
|
|
|
if (mHasRoleChange)
|
|
{
|
|
LLRoleData rd;
|
|
if (!gdatap->getRoleData(mSelectedRole,rd)) return;
|
|
|
|
rd.mRoleName = mRoleName->getText();
|
|
rd.mRoleDescription = mRoleDescription->getText();
|
|
rd.mRoleTitle = mRoleTitle->getText();
|
|
|
|
S32 role_members_count = 0;
|
|
if (mSelectedRole.isNull())
|
|
{
|
|
role_members_count = gdatap->mMemberCount;
|
|
}
|
|
else if(LLGroupRoleData* grd = get_ptr_in_map(gdatap->mRoles, mSelectedRole))
|
|
{
|
|
role_members_count = grd->getTotalMembersInRole();
|
|
}
|
|
|
|
gdatap->setRoleData(mSelectedRole,rd);
|
|
|
|
mRolesList->deleteSingleItem(mRolesList->getItemIndex(mSelectedRole));
|
|
|
|
LLSD row = createRoleItem(mSelectedRole,rd.mRoleName,rd.mRoleTitle,role_members_count);
|
|
LLScrollListItem* item = mRolesList->addElement(row, ADD_BOTTOM, this);
|
|
item->setSelected(select_saved_role);
|
|
|
|
mHasRoleChange = false;
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupRolesSubTab::updateActionDescription()
|
|
{
|
|
mActionDescription->setText(std::string());
|
|
LLScrollListItem* action_item = mAllowedActionsList->getFirstSelected();
|
|
if (!action_item || !mAllowedActionsList->getCanSelect())
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata();
|
|
if (rap)
|
|
{
|
|
std::string desc = rap->mLongDescription.empty() ? rap->mDescription : rap->mLongDescription;
|
|
mActionDescription->setText(desc);
|
|
}
|
|
}
|
|
|
|
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()
|
|
{
|
|
}
|
|
|
|
LLPanelGroupActionsSubTab::~LLPanelGroupActionsSubTab()
|
|
{
|
|
}
|
|
|
|
bool LLPanelGroupActionsSubTab::postBuildSubTab(LLView* root)
|
|
{
|
|
LLPanelGroupSubTab::postBuildSubTab(root);
|
|
|
|
// Upcast parent so we can ask it for sibling controls.
|
|
LLPanelGroupRoles* parent = (LLPanelGroupRoles*) root;
|
|
|
|
// Look recursively from the parent to find all our widgets.
|
|
bool recurse = true;
|
|
mHeader = parent->findChild<LLPanel>("actions_header", recurse);
|
|
mFooter = parent->findChild<LLPanel>("actions_footer", recurse);
|
|
|
|
mActionDescription = parent->getChild<LLTextEditor>("action_description", recurse);
|
|
|
|
mActionList = parent->getChild<LLScrollListCtrl>("action_list",recurse);
|
|
mActionRoles = parent->getChild<LLScrollListCtrl>("action_roles",recurse);
|
|
mActionMembers = parent->getChild<LLNameListCtrl>("action_members",recurse);
|
|
|
|
if (!mActionList || !mActionDescription || !mActionRoles || !mActionMembers) return false;
|
|
|
|
mActionList->setCommitOnSelectionChange(true);
|
|
mActionList->setCommitCallback(boost::bind(&LLPanelGroupActionsSubTab::handleActionSelect, this));
|
|
// <FS:Ansariel> Special Firestorm menu also allowing multi-select action
|
|
//mActionList->setContextMenu(LLScrollListCtrl::MENU_AVATAR);
|
|
mActionMembers->setContextMenu(&gFSNameListAvatarMenu);
|
|
|
|
update(GC_ALL);
|
|
|
|
return true;
|
|
}
|
|
|
|
void LLPanelGroupActionsSubTab::activate()
|
|
{
|
|
LLPanelGroupSubTab::activate();
|
|
|
|
update(GC_ALL);
|
|
mActionDescription->clear();
|
|
mActionList->deselectAllItems();
|
|
mActionList->deleteAllItems();
|
|
buildActionsList(mActionList,
|
|
GP_ALL_POWERS,
|
|
GP_ALL_POWERS,
|
|
NULL,
|
|
false,
|
|
true,
|
|
false);
|
|
}
|
|
|
|
void LLPanelGroupActionsSubTab::deactivate()
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupActionsSubTab::deactivate()" << LL_ENDL;
|
|
|
|
LLPanelGroupSubTab::deactivate();
|
|
}
|
|
|
|
bool LLPanelGroupActionsSubTab::needsApply(std::string& mesg)
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupActionsSubTab::needsApply()" << LL_ENDL;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool LLPanelGroupActionsSubTab::apply(std::string& mesg)
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupActionsSubTab::apply()" << LL_ENDL;
|
|
return true;
|
|
}
|
|
|
|
void LLPanelGroupActionsSubTab::update(LLGroupChange gc)
|
|
{
|
|
LL_DEBUGS() << "LLPanelGroupActionsSubTab::update()" << LL_ENDL;
|
|
|
|
if (mGroupID.isNull()) return;
|
|
|
|
mActionMembers->deleteAllItems();
|
|
mActionRoles->deleteAllItems();
|
|
|
|
if(mActionList->hasSelectedItem())
|
|
{
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (gdatap && gdatap->isMemberDataComplete() && gdatap->isRoleDataComplete())
|
|
{
|
|
handleActionSelect();
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupActionsSubTab::onFilterChanged()
|
|
{
|
|
mActionDescription->clear();
|
|
mActionList->deselectAllItems();
|
|
mActionList->deleteAllItems();
|
|
buildActionsList(mActionList,
|
|
GP_ALL_POWERS,
|
|
GP_ALL_POWERS,
|
|
NULL,
|
|
false,
|
|
true,
|
|
false);
|
|
}
|
|
|
|
void LLPanelGroupActionsSubTab::handleActionSelect()
|
|
{
|
|
mActionMembers->deleteAllItems();
|
|
mActionRoles->deleteAllItems();
|
|
|
|
U64 power_mask = GP_NO_POWERS;
|
|
std::vector<LLScrollListItem*> selection =
|
|
mActionList->getAllSelected();
|
|
if (selection.empty()) return;
|
|
|
|
LLRoleAction* rap;
|
|
|
|
std::vector<LLScrollListItem*>::iterator itor;
|
|
for (itor = selection.begin() ;
|
|
itor != selection.end(); ++itor)
|
|
{
|
|
rap = (LLRoleAction*)( (*itor)->getUserdata() );
|
|
power_mask |= rap->mPowerBit;
|
|
}
|
|
|
|
if (selection.size() == 1)
|
|
{
|
|
LLScrollListItem* item = selection[0];
|
|
rap = (LLRoleAction*)(item->getUserdata());
|
|
|
|
if (rap->mLongDescription.empty())
|
|
{
|
|
mActionDescription->setText(rap->mDescription);
|
|
}
|
|
else
|
|
{
|
|
mActionDescription->setText(rap->mLongDescription);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mActionDescription->clear();
|
|
}
|
|
|
|
LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
|
|
if (!gdatap) return;
|
|
|
|
if (gdatap->isMemberDataComplete())
|
|
{
|
|
LLGroupMgrGroupData::member_list_t::iterator it = gdatap->mMembers.begin();
|
|
LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
|
|
LLGroupMemberData* gmd;
|
|
|
|
for ( ; it != end; ++it)
|
|
{
|
|
gmd = (*it).second;
|
|
if (!gmd) continue;
|
|
if ((gmd->getAgentPowers() & power_mask) == power_mask)
|
|
{
|
|
mActionMembers->addNameItem(gmd->getID());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID);
|
|
}
|
|
|
|
if (gdatap->isRoleDataComplete())
|
|
{
|
|
LLGroupMgrGroupData::role_list_t::iterator it = gdatap->mRoles.begin();
|
|
LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end();
|
|
LLGroupRoleData* rmd;
|
|
|
|
for ( ; it != end; ++it)
|
|
{
|
|
rmd = (*it).second;
|
|
if (!rmd) continue;
|
|
if ((rmd->getRoleData().mRolePowers & power_mask) == power_mask)
|
|
{
|
|
mActionRoles->addSimpleElement(rmd->getRoleData().mRoleName);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID);
|
|
}
|
|
}
|
|
|
|
void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id)
|
|
{
|
|
if(mActionList) mActionList->deleteAllItems();
|
|
if(mActionRoles) mActionRoles->deleteAllItems();
|
|
if(mActionMembers) mActionMembers->deleteAllItems();
|
|
|
|
if(mActionDescription) mActionDescription->clear();
|
|
|
|
LLPanelGroupSubTab::setGroupID(id);
|
|
}
|
|
|
|
|
|
// LLPanelGroupBanListSubTab /////////////////////////////////////////////
|
|
static 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;
|
|
|
|
mHeader = parent->findChild<LLPanel>("banlist_header", recurse);
|
|
mFooter = parent->findChild<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);
|
|
mBanCountText = parent->getChild<LLTextBase>("ban_count", recurse);
|
|
|
|
if(!mBanList || !mCreateBanButton || !mDeleteBanButton || !mRefreshBanListButton || !mBanCountText)
|
|
return false;
|
|
|
|
mBanList->setCommitOnSelectionChange(true);
|
|
mBanList->setCommitCallback(onBanEntrySelect, this);
|
|
mBanList->setFilterColumn(0); // <FS:Zi> FIRE-31653: add banlist filter editor
|
|
|
|
mCreateBanButton->setClickedCallback(onCreateBanEntry, this);
|
|
mCreateBanButton->setEnabled(false);
|
|
|
|
mDeleteBanButton->setClickedCallback(onDeleteBanEntry, this);
|
|
mDeleteBanButton->setEnabled(false);
|
|
|
|
mRefreshBanListButton->setClickedCallback(onRefreshBanList, this);
|
|
mRefreshBanListButton->setEnabled(false);
|
|
|
|
setBanCount(0);
|
|
|
|
// <FS:Ansariel> Fix Baker's NameListCtrl un-fix
|
|
//mBanList->setOnNameListCompleteCallback(boost::bind(&LLPanelGroupBanListSubTab::onBanListCompleted, this, _1));
|
|
|
|
// <FS:Ansariel> Don't do this - it will cause populateBanList() being called twice because activate() is being called when switching to a tab, also calling populateBanList()
|
|
//populateBanList();
|
|
|
|
setFooterEnabled(false);
|
|
return true;
|
|
}
|
|
|
|
void LLPanelGroupBanListSubTab::activate()
|
|
{
|
|
LLPanelGroupSubTab::activate();
|
|
|
|
mBanList->deselectAllItems();
|
|
mDeleteBanButton->setEnabled(false);
|
|
|
|
LLGroupMgrGroupData * group_datap = LLGroupMgr::getInstance()->getGroupData(mGroupID);
|
|
if (group_datap)
|
|
{
|
|
mCreateBanButton->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS) &&
|
|
group_datap->mBanList.size() < GB_MAX_BANNED_AGENTS);
|
|
setBanCount(static_cast<U32>(group_datap->mBanList.size()));
|
|
}
|
|
else
|
|
{
|
|
mCreateBanButton->setEnabled(false);
|
|
setBanCount(0);
|
|
}
|
|
|
|
// 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()
|
|
{
|
|
// <FS:Zi> FIRE-31653: disable remove ban button when no entry is selected
|
|
if (!mBanList->getNumSelected())
|
|
{
|
|
mDeleteBanButton->setEnabled(false);
|
|
return;
|
|
}
|
|
// </FS:Zi>
|
|
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);
|
|
}
|
|
|
|
// update ban-count related elements
|
|
mCreateBanButton->setEnabled(true);
|
|
setBanCount(static_cast<U32>(gdatap->mBanList.size()));
|
|
|
|
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);
|
|
}
|
|
|
|
// <FS:Ansariel> Fix Baker's NameListCtrl un-fix
|
|
//void LLPanelGroupBanListSubTab::onBanListCompleted(bool isComplete)
|
|
//{
|
|
// if(isComplete)
|
|
// {
|
|
// mRefreshBanListButton->setEnabled(true);
|
|
// populateBanList();
|
|
// }
|
|
//}
|
|
// </FS:Ansariel>
|
|
|
|
void LLPanelGroupBanListSubTab::setBanCount(U32 ban_count)
|
|
{
|
|
LLStringUtil::format_map_t args;
|
|
args["[COUNT]"] = llformat("%d", ban_count);
|
|
args["[LIMIT]"] = llformat("%d", GB_MAX_BANNED_AGENTS);
|
|
mBanCountText->setText(getString("ban_count_template", args));
|
|
}
|
|
|
|
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");
|
|
|
|
// Baker TODO: MAINT-
|
|
// 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);
|
|
mCreateBanButton->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS) &&
|
|
gdatap->mBanList.size() < GB_MAX_BANNED_AGENTS);
|
|
setBanCount(static_cast<U32>(gdatap->mBanList.size()));
|
|
}
|
|
|
|
void LLPanelGroupBanListSubTab::setGroupID(const LLUUID& id)
|
|
{
|
|
if(mBanList)
|
|
mBanList->deleteAllItems();
|
|
|
|
setFooterEnabled(false);
|
|
LLPanelGroupSubTab::setGroupID(id);
|
|
}
|
|
|
|
// <FS:Zi> FIRE-31653: add banlist filter editor
|
|
void LLPanelGroupBanListSubTab::onFilterChanged()
|
|
{
|
|
mBanList->setFilterString(mSearchFilter);
|
|
|
|
// disable remove ban button as a change of filter will deselect all entries
|
|
mDeleteBanButton->setEnabled(false);
|
|
}
|
|
// </FS:Zi> add banlist filter editor
|