1541 lines
44 KiB
C++
1541 lines
44 KiB
C++
/**
|
|
* @file llfloaterfriends.cpp
|
|
* @author Phoenix
|
|
* @date 2005-01-13
|
|
* @brief Implementation of the friends floater
|
|
*
|
|
* $LicenseInfo:firstyear=2005&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2005-2009, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "llfloaterfriends.h"
|
|
|
|
#include <sstream>
|
|
|
|
#include "lldir.h"
|
|
|
|
#include "llagent.h"
|
|
#include "llappviewer.h" // for gLastVersionChannel
|
|
|
|
// [Ansariel: Display name support]
|
|
#include "llavatarname.h"
|
|
#include "llavatarnamecache.h"
|
|
// [/Ansariel: Display name support]
|
|
|
|
#include "llfloateravatarpicker.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llbutton.h"
|
|
#include "llfloateravatarinfo.h"
|
|
#include "llinventorymodel.h"
|
|
#include "llnamelistctrl.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "llresmgr.h"
|
|
#include "llimview.h"
|
|
#include "lluictrlfactory.h"
|
|
#include "llmenucommands.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llviewermessage.h"
|
|
#include "lleventtimer.h"
|
|
#include "lltextbox.h"
|
|
#include "llvoiceclient.h"
|
|
|
|
#include "llsdserialize.h"
|
|
#include "statemachine/aifilepicker.h"
|
|
|
|
#include "llviewermenufile.h"
|
|
#include "llviewermenu.h"
|
|
#include "llviewernetwork.h"
|
|
#include "hippogridmanager.h"
|
|
|
|
#include "llchat.h"
|
|
#include "llfloaterchat.h"
|
|
|
|
// <dogmode> stuff for Contact groups
|
|
#include "ascentfloatercontactgroups.h"
|
|
|
|
//Maximum number of people you can select to do an operation on at once.
|
|
#define MAX_FRIEND_SELECT 20
|
|
#define DEFAULT_PERIOD 5.0
|
|
#define RIGHTS_CHANGE_TIMEOUT 5.0
|
|
#define OBSERVER_TIMEOUT 0.5
|
|
|
|
#define ONLINE_SIP_ICON_NAME "slim_icon_16_viewer.tga"
|
|
|
|
// simple class to observe the calling cards.
|
|
class LLLocalFriendsObserver : public LLFriendObserver, public LLEventTimer
|
|
{
|
|
public:
|
|
LLLocalFriendsObserver(LLPanelFriends* floater) : mFloater(floater), LLEventTimer(OBSERVER_TIMEOUT)
|
|
{
|
|
mEventTimer.stop();
|
|
}
|
|
virtual ~LLLocalFriendsObserver()
|
|
{
|
|
mFloater = NULL;
|
|
}
|
|
virtual void changed(U32 mask)
|
|
{
|
|
// events can arrive quickly in bulk - we need not process EVERY one of them -
|
|
// so we wait a short while to let others pile-in, and process them in aggregate.
|
|
mEventTimer.start();
|
|
|
|
// save-up all the mask-bits which have come-in
|
|
mMask |= mask;
|
|
}
|
|
virtual BOOL tick()
|
|
{
|
|
mFloater->populateContactGroupSelect();
|
|
mFloater->updateFriends(mMask);
|
|
|
|
mEventTimer.stop();
|
|
mMask = 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
protected:
|
|
LLPanelFriends* mFloater;
|
|
U32 mMask;
|
|
};
|
|
|
|
LLPanelFriends::LLPanelFriends() :
|
|
LLPanel(),
|
|
LLEventTimer(DEFAULT_PERIOD),
|
|
mObserver(NULL),
|
|
mShowMaxSelectWarning(TRUE),
|
|
mAllowRightsChange(TRUE),
|
|
mNumRightsChanged(0),
|
|
mNumOnline(0)
|
|
{
|
|
mEventTimer.stop();
|
|
mObserver = new LLLocalFriendsObserver(this);
|
|
LLAvatarTracker::instance().addObserver(mObserver);
|
|
// For notification when SIP online status changes.
|
|
LLVoiceClient::getInstance()->addObserver(mObserver);
|
|
}
|
|
|
|
LLPanelFriends::~LLPanelFriends()
|
|
{
|
|
// For notification when SIP online status changes.
|
|
LLVoiceClient::getInstance()->removeObserver(mObserver);
|
|
LLAvatarTracker::instance().removeObserver(mObserver);
|
|
delete mObserver;
|
|
}
|
|
|
|
BOOL LLPanelFriends::tick()
|
|
{
|
|
mEventTimer.stop();
|
|
mPeriod = DEFAULT_PERIOD;
|
|
mAllowRightsChange = TRUE;
|
|
updateFriends(LLFriendObserver::ADD);
|
|
return FALSE;
|
|
}
|
|
|
|
void LLPanelFriends::updateFriends(U32 changed_mask)
|
|
{
|
|
LLUUID selected_id;
|
|
LLCtrlListInterface *friends_list = childGetListInterface("friend_list");
|
|
if (!friends_list) return;
|
|
LLCtrlScrollInterface *friends_scroll = childGetScrollInterface("friend_list");
|
|
if (!friends_scroll) return;
|
|
|
|
// We kill the selection warning, otherwise we'll spam with warning popups
|
|
// if the maximum amount of friends are selected
|
|
mShowMaxSelectWarning = false;
|
|
|
|
LLDynamicArray<LLUUID> selected_friends = getSelectedIDs();
|
|
if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
|
|
{
|
|
refreshNames(changed_mask);
|
|
}
|
|
else if(changed_mask & LLFriendObserver::POWERS)
|
|
{
|
|
--mNumRightsChanged;
|
|
if(mNumRightsChanged > 0)
|
|
{
|
|
mPeriod = RIGHTS_CHANGE_TIMEOUT;
|
|
mEventTimer.start();
|
|
mAllowRightsChange = FALSE;
|
|
}
|
|
else
|
|
{
|
|
tick();
|
|
}
|
|
}
|
|
if(selected_friends.size() > 0)
|
|
{
|
|
// only non-null if friends was already found. This may fail,
|
|
// but we don't really care here, because refreshUI() will
|
|
// clean up the interface.
|
|
friends_list->setCurrentByID(selected_id);
|
|
for(LLDynamicArray<LLUUID>::iterator itr = selected_friends.begin(); itr != selected_friends.end(); ++itr)
|
|
{
|
|
friends_list->setSelectedByValue(*itr, true);
|
|
}
|
|
}
|
|
|
|
refreshUI();
|
|
mShowMaxSelectWarning = true;
|
|
}
|
|
|
|
// <dogmode>
|
|
// Contact search and group system.
|
|
// 09/05/2010 - Charley Levenque
|
|
std::string LLPanelFriends::cleanFileName(std::string filename)
|
|
{
|
|
std::string invalidChars = "\"\'\\/?*:<>|";
|
|
S32 position = filename.find_first_of(invalidChars);
|
|
while (position != filename.npos)
|
|
{
|
|
filename[position] = '_';
|
|
position = filename.find_first_of(invalidChars, position);
|
|
}
|
|
return filename;
|
|
}
|
|
|
|
void LLPanelFriends::populateContactGroupSelect()
|
|
{
|
|
LLComboBox* combo = getChild<LLComboBox>("buddy_group_combobox");
|
|
|
|
if (combo)
|
|
{
|
|
combo->removeall();
|
|
combo->add("All", ADD_BOTTOM);
|
|
|
|
LLSD groups = gSavedPerAccountSettings.getLLSD("AscentContactGroups");
|
|
|
|
S32 count = groups["ASC_MASTER_GROUP_LIST"].size();
|
|
S32 index;
|
|
for (index = 0; index < count; index++)
|
|
{
|
|
combo->addSimpleElement(groups["ASC_MASTER_GROUP_LIST"][index].asString(), ADD_BOTTOM);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLChat msg("Null combo");
|
|
LLFloaterChat::addChat(msg);
|
|
}
|
|
}
|
|
|
|
void LLPanelFriends::setContactGroup(std::string contact_grp)
|
|
{
|
|
LLChat msg("Group set to " + contact_grp);
|
|
LLFloaterChat::addChat(msg);
|
|
refreshNames(LLFriendObserver::ADD);
|
|
refreshUI();
|
|
categorizeContacts();
|
|
}
|
|
|
|
void LLPanelFriends::categorizeContacts()
|
|
{
|
|
LLSD contact_groups = gSavedPerAccountSettings.getLLSD("AscentContactGroups");
|
|
std::string group_name = "All";
|
|
|
|
LLComboBox* combo = getChild<LLComboBox>("buddy_group_combobox");
|
|
if (combo)
|
|
{
|
|
group_name = combo->getValue().asString();
|
|
|
|
if (group_name != "All")
|
|
{
|
|
std::vector<LLScrollListItem*> vFriends = mFriendsList->getAllData(); // all of it.
|
|
for (std::vector<LLScrollListItem*>::iterator itr = vFriends.begin(); itr != vFriends.end(); ++itr)
|
|
{
|
|
BOOL show_entry = false;//contact_groups[group_name].has((*itr)->getUUID().asString());
|
|
|
|
S32 count = contact_groups[group_name].size();
|
|
int i;
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
if (contact_groups[group_name][i].asString() == (*itr)->getUUID().asString())
|
|
{
|
|
show_entry = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!show_entry)
|
|
{
|
|
LLChat msg("False: contact_groups['" + group_name + "'].has('" + (*itr)->getUUID().asString() + "');");
|
|
LLFloaterChat::addChat(msg);
|
|
mFriendsList->deleteItems((*itr)->getValue());
|
|
}
|
|
else
|
|
{
|
|
LLChat msg("True: contact_groups['" + group_name + "'].has('" + (*itr)->getUUID().asString() + "');");
|
|
LLFloaterChat::addChat(msg);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLChat msg("Group set to all.");
|
|
LLFloaterChat::addChat(msg);
|
|
}
|
|
|
|
refreshUI();
|
|
}
|
|
else
|
|
{
|
|
LLChat msg("Null combo.");
|
|
LLFloaterChat::addChat(msg);
|
|
}
|
|
}
|
|
|
|
void LLPanelFriends::filterContacts(const std::string& search_name)
|
|
{
|
|
std::string friend_name;
|
|
|
|
if ((search_name != "" /*&& search_name != mLastContactSearch*/))
|
|
{
|
|
if (search_name.find(mLastContactSearch) == std::string::npos)
|
|
{
|
|
refreshNames(LLFriendObserver::ADD);
|
|
}
|
|
|
|
//llinfos << "search_name = " << search_name <<llendl;
|
|
|
|
std::vector<LLScrollListItem*> vFriends = mFriendsList->getAllData(); // all of it.
|
|
for (std::vector<LLScrollListItem*>::iterator itr = vFriends.begin(); itr != vFriends.end(); ++itr)
|
|
{
|
|
friend_name = utf8str_tolower((*itr)->getColumn(LIST_FRIEND_NAME)->getValue().asString());
|
|
BOOL show_entry = (friend_name.find(utf8str_tolower(search_name)) != std::string::npos);
|
|
//llinfos << "friend_name = " << friend_name << (show_entry?" (shown)":"") <<llendl;
|
|
if (!show_entry)
|
|
{
|
|
mFriendsList->deleteItems((*itr)->getValue());
|
|
}
|
|
}
|
|
|
|
mFriendsList->updateLayout();
|
|
refreshUI();
|
|
}
|
|
else if (search_name == "" && search_name != mLastContactSearch) refreshNames(LLFriendObserver::ADD);
|
|
mLastContactSearch = search_name;
|
|
}
|
|
|
|
//static
|
|
void LLPanelFriends::onContactSearchEdit(const std::string& search_string, void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
if (panelp)
|
|
{
|
|
panelp->filterContacts(search_string);
|
|
}
|
|
}
|
|
|
|
void LLPanelFriends::onChangeContactGroup(LLUICtrl* ctrl, void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
|
|
if(panelp)
|
|
{
|
|
LLComboBox* combo = panelp->getChild<LLComboBox>("buddy_group_combobox");
|
|
panelp->setContactGroup(combo->getValue().asString());
|
|
}
|
|
}
|
|
// --
|
|
|
|
// virtual
|
|
BOOL LLPanelFriends::postBuild()
|
|
{
|
|
mFriendsList = getChild<LLScrollListCtrl>("friend_list");
|
|
mFriendsList->setMaxSelectable(MAX_FRIEND_SELECT);
|
|
mFriendsList->setMaximumSelectCallback(onMaximumSelect);
|
|
mFriendsList->setCommitOnSelectionChange(TRUE);
|
|
childSetCommitCallback("friend_list", onSelectName, this);
|
|
childSetCommitCallback("buddy_group_combobox", onChangeContactGroup, this);
|
|
childSetDoubleClickCallback("friend_list", onClickIM);
|
|
|
|
// <dogmode>
|
|
// Contact search and group system.
|
|
// 09/05/2010 - Charley Levenque
|
|
LLSearchEditor* contact = getChild<LLSearchEditor>("buddy_search_lineedit");
|
|
if (contact)
|
|
{
|
|
contact->setSearchCallback(&onContactSearchEdit, this);
|
|
}
|
|
|
|
getChild<LLTextBox>("s_num")->setValue("0");
|
|
getChild<LLTextBox>("f_num")->setValue(llformat("%d", mFriendsList->getItemCount()));
|
|
|
|
U32 changed_mask = LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE;
|
|
refreshNames(changed_mask);
|
|
|
|
childSetAction("im_btn", onClickIM, this);
|
|
childSetAction("assign_btn", onClickAssign, this);
|
|
childSetAction("expand_collapse_btn", onClickExpand, this);
|
|
childSetAction("profile_btn", onClickProfile, this);
|
|
childSetAction("offer_teleport_btn", onClickOfferTeleport, this);
|
|
childSetAction("pay_btn", onClickPay, this);
|
|
childSetAction("add_btn", onClickAddFriend, this);
|
|
childSetAction("remove_btn", onClickRemove, this);
|
|
//childSetAction("export_btn", onClickExport, this); Making Dummy View -HgB
|
|
//childSetAction("import_btn", onClickImport, this); Making Dummy View -HgB
|
|
|
|
setDefaultBtn("im_btn");
|
|
|
|
updateFriends(LLFriendObserver::ADD);
|
|
refreshUI();
|
|
|
|
// primary sort = online status, secondary sort = name
|
|
mFriendsList->sortByColumn(std::string("friend_name"), TRUE);
|
|
mFriendsList->sortByColumn(std::string("icon_online_status"), FALSE);
|
|
|
|
updateColumns(this);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLPanelFriends::addFriend(const LLUUID& agent_id)
|
|
{
|
|
LLAvatarTracker& at = LLAvatarTracker::instance();
|
|
const LLRelationship* relationInfo = at.getBuddyInfo(agent_id);
|
|
if(!relationInfo) return FALSE;
|
|
|
|
bool isOnlineSIP = LLVoiceClient::getInstance()->isOnlineSIP(agent_id);
|
|
bool isOnline = relationInfo->isOnline();
|
|
|
|
std::string fullname;
|
|
// [Ansariel: Display name support]
|
|
//BOOL have_name = gCacheName->getFullName(agent_id, fullname);
|
|
LLAvatarName avatar_name;
|
|
BOOL have_name;
|
|
if (LLAvatarNameCache::get(agent_id, &avatar_name))
|
|
{
|
|
static const LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0);
|
|
switch (phoenix_name_system)
|
|
{
|
|
case 0 : fullname = avatar_name.getLegacyName(); break;
|
|
case 1 : fullname = (avatar_name.mIsDisplayNameDefault ? avatar_name.mDisplayName : avatar_name.getCompleteName()); break;
|
|
case 2 : fullname = avatar_name.mDisplayName; break;
|
|
default : fullname = avatar_name.getCompleteName(); break;
|
|
}
|
|
|
|
have_name = TRUE;
|
|
}
|
|
else have_name = FALSE;
|
|
// [/Ansariel: Display name support]
|
|
|
|
LLSD element;
|
|
element["id"] = agent_id;
|
|
LLSD& friend_column = element["columns"][LIST_FRIEND_NAME];
|
|
friend_column["column"] = "friend_name";
|
|
friend_column["value"] = fullname;
|
|
friend_column["font"] = "SANSSERIF";
|
|
friend_column["font-style"] = "NORMAL";
|
|
|
|
LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS];
|
|
online_status_column["column"] = "icon_online_status";
|
|
online_status_column["type"] = "icon";
|
|
|
|
if (isOnline)
|
|
{
|
|
mNumOnline++;
|
|
friend_column["font-style"] = "BOLD";
|
|
online_status_column["value"] = "icon_avatar_online.tga";
|
|
}
|
|
else if(isOnlineSIP)
|
|
{
|
|
mNumOnline++;
|
|
friend_column["font-style"] = "BOLD";
|
|
online_status_column["value"] = ONLINE_SIP_ICON_NAME;
|
|
}
|
|
|
|
LLSD& online_column = element["columns"][LIST_VISIBLE_ONLINE];
|
|
online_column["column"] = "icon_visible_online";
|
|
online_column["type"] = "checkbox";
|
|
online_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS);
|
|
|
|
LLSD& visible_map_column = element["columns"][LIST_VISIBLE_MAP];
|
|
visible_map_column["column"] = "icon_visible_map";
|
|
visible_map_column["type"] = "checkbox";
|
|
visible_map_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION);
|
|
|
|
LLSD& edit_my_object_column = element["columns"][LIST_EDIT_MINE];
|
|
edit_my_object_column["column"] = "icon_edit_mine";
|
|
edit_my_object_column["type"] = "checkbox";
|
|
edit_my_object_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS);
|
|
|
|
LLSD& see_online_them_column = element["columns"][LIST_VISIBLE_ONLINE_THEIRS];
|
|
see_online_them_column["column"] = "icon_visible_online_theirs";
|
|
see_online_them_column["type"] = "checkbox";
|
|
see_online_them_column["enabled"] = "";
|
|
see_online_them_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS);
|
|
|
|
|
|
|
|
LLSD& mapstalk_them_column = element["columns"][LIST_VISIBLE_MAP_THEIRS];
|
|
mapstalk_them_column["column"] = "icon_visible_map_theirs";
|
|
mapstalk_them_column["type"] = "checkbox";
|
|
mapstalk_them_column["enabled"] = "";
|
|
mapstalk_them_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION);
|
|
|
|
LLSD& edit_their_object_column = element["columns"][LIST_EDIT_THEIRS];
|
|
edit_their_object_column["column"] = "icon_edit_theirs";
|
|
edit_their_object_column["type"] = "checkbox";
|
|
edit_their_object_column["enabled"] = "";
|
|
edit_their_object_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS);
|
|
|
|
LLSD& update_gen_column = element["columns"][LIST_FRIEND_UPDATE_GEN];
|
|
update_gen_column["column"] = "friend_last_update_generation";
|
|
update_gen_column["value"] = have_name ? relationInfo->getChangeSerialNum() : -1;
|
|
|
|
mFriendsList->addElement(element, ADD_BOTTOM);
|
|
return have_name;
|
|
}
|
|
|
|
// propagate actual relationship to UI.
|
|
// Does not resort the UI list because it can be called frequently. JC
|
|
BOOL LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationship* info)
|
|
{
|
|
if (!info) return FALSE;
|
|
LLScrollListItem* itemp = mFriendsList->getItem(agent_id);
|
|
if (!itemp) return FALSE;
|
|
|
|
bool isOnlineSIP = LLVoiceClient::getInstance()->isOnlineSIP(itemp->getUUID());
|
|
bool isOnline = info->isOnline();
|
|
|
|
std::string fullname;
|
|
// [Ansariel: Display name support]
|
|
//BOOL have_name = gCacheName->getFullName(agent_id, fullname);
|
|
LLAvatarName avatar_name;
|
|
BOOL have_name;
|
|
if (LLAvatarNameCache::get(agent_id, &avatar_name))
|
|
{
|
|
static const LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0);
|
|
switch (phoenix_name_system)
|
|
{
|
|
case 0 : fullname = avatar_name.getLegacyName(); break;
|
|
case 1 : fullname = (avatar_name.mIsDisplayNameDefault ? avatar_name.mDisplayName : avatar_name.getCompleteName()); break;
|
|
case 2 : fullname = avatar_name.mDisplayName; break;
|
|
default : fullname = avatar_name.getCompleteName(); break;
|
|
}
|
|
|
|
have_name = TRUE;
|
|
}
|
|
else have_name = FALSE;
|
|
// [/Ansariel: Display name support]
|
|
|
|
// Name of the status icon to use
|
|
std::string statusIcon;
|
|
|
|
if(isOnline)
|
|
{
|
|
mNumOnline++;
|
|
statusIcon = "icon_avatar_online.tga";
|
|
}
|
|
else if(isOnlineSIP)
|
|
{
|
|
mNumOnline++;
|
|
statusIcon = ONLINE_SIP_ICON_NAME;
|
|
}
|
|
else
|
|
{
|
|
mNumOnline--;
|
|
}
|
|
|
|
itemp->getColumn(LIST_ONLINE_STATUS)->setValue(statusIcon);
|
|
|
|
itemp->getColumn(LIST_FRIEND_NAME)->setValue(fullname);
|
|
// render name of online friends in bold text
|
|
((LLScrollListText*)itemp->getColumn(LIST_FRIEND_NAME))->setFontStyle((isOnline || isOnlineSIP) ? LLFontGL::BOLD : LLFontGL::NORMAL);
|
|
itemp->getColumn(LIST_VISIBLE_ONLINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS));
|
|
itemp->getColumn(LIST_VISIBLE_MAP)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION));
|
|
itemp->getColumn(LIST_EDIT_MINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS));
|
|
//Notes in the original code imply this may not always work. Good to know. -HgB
|
|
itemp->getColumn(LIST_VISIBLE_ONLINE_THEIRS)->setValue(info->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS));
|
|
|
|
|
|
itemp->getColumn(LIST_VISIBLE_MAP_THEIRS)->setValue(info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION));
|
|
itemp->getColumn(LIST_EDIT_THEIRS)->setValue(info->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS));
|
|
|
|
S32 change_generation = have_name ? info->getChangeSerialNum() : -1;
|
|
itemp->getColumn(LIST_FRIEND_UPDATE_GEN)->setValue(change_generation);
|
|
|
|
// enable this item, in case it was disabled after user input
|
|
itemp->setEnabled(TRUE);
|
|
|
|
// Do not resort, this function can be called frequently.
|
|
return have_name;
|
|
}
|
|
|
|
void LLPanelFriends::refreshRightsChangeList()
|
|
{
|
|
|
|
LLDynamicArray<LLUUID> friends = getSelectedIDs();
|
|
|
|
S32 num_selected = friends.size();
|
|
bool can_offer_teleport = num_selected >= 1;
|
|
bool selected_friends_online = true;
|
|
|
|
/*LLTextBox* processing_label = getChild<LLTextBox>("process_rights_label");
|
|
|
|
if(!mAllowRightsChange)
|
|
{
|
|
if(processing_label)
|
|
{
|
|
processing_label->setVisible(true);
|
|
// ignore selection for now
|
|
friends.clear();
|
|
num_selected = 0;
|
|
}
|
|
}
|
|
else if(processing_label)
|
|
{
|
|
processing_label->setVisible(false);
|
|
} Making Dummy View -HgB */
|
|
const LLRelationship* friend_status = NULL;
|
|
for(LLDynamicArray<LLUUID>::iterator itr = friends.begin(); itr != friends.end(); ++itr)
|
|
{
|
|
friend_status = LLAvatarTracker::instance().getBuddyInfo(*itr);
|
|
if (friend_status)
|
|
{
|
|
if(!friend_status->isOnline())
|
|
{
|
|
can_offer_teleport = false;
|
|
selected_friends_online = false;
|
|
}
|
|
}
|
|
else // missing buddy info, don't allow any operations
|
|
{
|
|
can_offer_teleport = false;
|
|
}
|
|
}
|
|
|
|
//Stuff for the online/total/select counts.
|
|
|
|
getChild<LLTextBox>("s_num")->setValue(llformat("%d", num_selected));
|
|
getChild<LLTextBox>("f_num")->setValue(llformat("%d / %d", mNumOnline, mFriendsList->getItemCount()));
|
|
|
|
if (num_selected == 0) // nothing selected
|
|
{
|
|
childSetEnabled("im_btn", FALSE);
|
|
childSetEnabled("assign_btn", FALSE);
|
|
childSetEnabled("offer_teleport_btn", FALSE);
|
|
}
|
|
else // we have at least one friend selected...
|
|
{
|
|
// only allow IMs to groups when everyone in the group is online
|
|
// to be consistent with context menus in inventory and because otherwise
|
|
// offline friends would be silently dropped from the session
|
|
childSetEnabled("im_btn", selected_friends_online || num_selected == 1);
|
|
childSetEnabled("assign_btn", num_selected == 1);
|
|
childSetEnabled("offer_teleport_btn", can_offer_teleport);
|
|
}
|
|
}
|
|
|
|
struct SortFriendsByID
|
|
{
|
|
bool operator() (const LLScrollListItem* const a, const LLScrollListItem* const b) const
|
|
{
|
|
return a->getValue().asUUID() < b->getValue().asUUID();
|
|
}
|
|
};
|
|
|
|
void LLPanelFriends::refreshNames(U32 changed_mask)
|
|
{
|
|
LLDynamicArray<LLUUID> selected_ids = getSelectedIDs();
|
|
S32 pos = mFriendsList->getScrollPos();
|
|
|
|
// get all buddies we know about
|
|
LLAvatarTracker::buddy_map_t all_buddies;
|
|
LLAvatarTracker::instance().copyBuddyList(all_buddies);
|
|
|
|
BOOL have_names = TRUE;
|
|
|
|
if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE))
|
|
{
|
|
have_names &= refreshNamesSync(all_buddies);
|
|
}
|
|
|
|
if(changed_mask & LLFriendObserver::ONLINE)
|
|
{
|
|
have_names &= refreshNamesPresence(all_buddies);
|
|
}
|
|
|
|
if (!have_names)
|
|
{
|
|
mEventTimer.start();
|
|
}
|
|
// Changed item in place, need to request sort and update columns
|
|
// because we might have changed data in a column on which the user
|
|
// has already sorted. JC
|
|
mFriendsList->sortItems();
|
|
|
|
// re-select items
|
|
mFriendsList->selectMultiple(selected_ids);
|
|
mFriendsList->setScrollPos(pos);
|
|
}
|
|
|
|
BOOL LLPanelFriends::refreshNamesSync(const LLAvatarTracker::buddy_map_t & all_buddies)
|
|
{
|
|
mNumOnline = 0;
|
|
mFriendsList->deleteAllItems();
|
|
|
|
BOOL have_names = TRUE;
|
|
LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin();
|
|
|
|
for(; buddy_it != all_buddies.end(); ++buddy_it)
|
|
{
|
|
have_names &= addFriend(buddy_it->first);
|
|
}
|
|
|
|
return have_names;
|
|
}
|
|
|
|
BOOL LLPanelFriends::refreshNamesPresence(const LLAvatarTracker::buddy_map_t & all_buddies)
|
|
{
|
|
|
|
std::vector<LLScrollListItem*> items = mFriendsList->getAllData();
|
|
std::sort(items.begin(), items.end(), SortFriendsByID());
|
|
|
|
LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin();
|
|
std::vector<LLScrollListItem*>::const_iterator item_it = items.begin();
|
|
BOOL have_names = TRUE;
|
|
|
|
while(true)
|
|
{
|
|
if(item_it == items.end() || buddy_it == all_buddies.end())
|
|
{
|
|
break;
|
|
}
|
|
|
|
const LLUUID & buddy_uuid = buddy_it->first;
|
|
const LLUUID & item_uuid = (*item_it)->getValue().asUUID();
|
|
if(item_uuid == buddy_uuid)
|
|
{
|
|
const LLRelationship* info = buddy_it->second;
|
|
if (!info)
|
|
{
|
|
++item_it;
|
|
continue;
|
|
}
|
|
|
|
S32 last_change_generation = (*item_it)->getColumn(LIST_FRIEND_UPDATE_GEN)->getValue().asInteger();
|
|
if (last_change_generation < info->getChangeSerialNum())
|
|
{
|
|
// update existing item in UI
|
|
have_names &= updateFriendItem(buddy_it->first, info);
|
|
}
|
|
|
|
++buddy_it;
|
|
++item_it;
|
|
}
|
|
else if(item_uuid < buddy_uuid)
|
|
{
|
|
++item_it;
|
|
}
|
|
else //if(item_uuid > buddy_uuid)
|
|
{
|
|
++buddy_it;
|
|
}
|
|
}
|
|
|
|
return have_names;
|
|
}
|
|
// meal disk
|
|
void LLPanelFriends::refreshUI()
|
|
{
|
|
BOOL single_selected = FALSE;
|
|
BOOL multiple_selected = FALSE;
|
|
int num_selected = mFriendsList->getAllSelected().size();
|
|
if(num_selected > 0)
|
|
{
|
|
single_selected = TRUE;
|
|
if(num_selected > 1)
|
|
{
|
|
multiple_selected = TRUE;
|
|
}
|
|
}
|
|
|
|
//Options that can only be performed with one friend selected
|
|
childSetEnabled("profile_btn", single_selected && !multiple_selected);
|
|
childSetEnabled("pay_btn", single_selected && !multiple_selected);
|
|
childSetEnabled("assign_btn", single_selected && !multiple_selected);
|
|
|
|
//Options that can be performed with up to MAX_FRIEND_SELECT friends selected
|
|
//(single_selected will always be true in this situations)
|
|
childSetEnabled("remove_btn", single_selected);
|
|
childSetEnabled("im_btn", single_selected);
|
|
//childSetEnabled("friend_rights", single_selected); Making Dummy View -HgB
|
|
|
|
refreshRightsChangeList();
|
|
}
|
|
|
|
LLDynamicArray<LLUUID> LLPanelFriends::getSelectedIDs()
|
|
{
|
|
LLUUID selected_id;
|
|
LLDynamicArray<LLUUID> friend_ids;
|
|
std::vector<LLScrollListItem*> selected = mFriendsList->getAllSelected();
|
|
for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
|
|
{
|
|
friend_ids.push_back((*itr)->getUUID());
|
|
}
|
|
return friend_ids;
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onSelectName(LLUICtrl* ctrl, void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
|
|
if(panelp)
|
|
{
|
|
panelp->refreshUI();
|
|
// check to see if rights have changed
|
|
panelp->applyRightsToFriends();
|
|
}
|
|
}
|
|
|
|
//static
|
|
void LLPanelFriends::onMaximumSelect(void* user_data)
|
|
{
|
|
LLSD args;
|
|
args["MAX_SELECT"] = llformat("%d", MAX_FRIEND_SELECT);
|
|
LLNotificationsUtil::add("MaxListSelectMessage", args);
|
|
};
|
|
|
|
// static
|
|
void LLPanelFriends::onClickProfile(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
|
|
//llinfos << "LLPanelFriends::onClickProfile()" << llendl;
|
|
LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
|
|
if(ids.size() > 0)
|
|
{
|
|
LLUUID agent_id = ids[0];
|
|
BOOL online;
|
|
online = LLAvatarTracker::instance().isBuddyOnline(agent_id);
|
|
LLFloaterAvatarInfo::showFromFriend(agent_id, online);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onClickAssign(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
if (panelp)
|
|
{
|
|
LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
|
|
ASFloaterContactGroups::show(ids);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onClickExpand(void* user_data)
|
|
{
|
|
BOOL collapsed = gSavedSettings.getBOOL("ContactListCollapsed");
|
|
gSavedSettings.setBOOL("ContactListCollapsed", !collapsed);
|
|
updateColumns(user_data);
|
|
}
|
|
|
|
void LLPanelFriends::updateColumns(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
if (panelp)
|
|
{
|
|
LLButton* expand_button = panelp->getChild<LLButton>("expand_collapse_btn");
|
|
LLScrollListCtrl* list = panelp->getChild<LLScrollListCtrl>("friend_list");
|
|
//llinfos << "Refreshing UI" << llendl;
|
|
S32 width = 22;
|
|
std::string button = ">";
|
|
if (gSavedSettings.getBOOL("ContactListCollapsed"))
|
|
{
|
|
width = 0;
|
|
button = "<";
|
|
}
|
|
expand_button->setLabel(button);
|
|
LLScrollListColumn* column = list->getColumn(5);
|
|
list->updateStaticColumnWidth(column, width);
|
|
column->setWidth(width);
|
|
column = list->getColumn(6);
|
|
list->updateStaticColumnWidth(column, width);
|
|
column->setWidth(width);
|
|
column = list->getColumn(7);
|
|
list->updateStaticColumnWidth(column, width);
|
|
column->setWidth(width);
|
|
list->updateLayout();
|
|
if (!gSavedSettings.getBOOL("ContactListCollapsed"))
|
|
{
|
|
panelp->updateFriends(LLFriendObserver::ADD);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLPanelFriends::onClickIM(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
|
|
//llinfos << "LLPanelFriends::onClickIM()" << llendl;
|
|
LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
|
|
if(ids.size() > 0)
|
|
{
|
|
if(ids.size() == 1)
|
|
{
|
|
LLUUID agent_id = ids[0];
|
|
const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(agent_id);
|
|
// [Ansariel: Display name support]
|
|
//std::string fullname;
|
|
//if(info && gCacheName->getFullName(agent_id, fullname))
|
|
//{
|
|
// gIMMgr->setFloaterOpen(TRUE);
|
|
// gIMMgr->addSession(fullname, IM_NOTHING_SPECIAL, agent_id);
|
|
//}
|
|
LLAvatarName avatar_name;
|
|
if (info && LLAvatarNameCache::get(agent_id, &avatar_name))
|
|
{
|
|
gIMMgr->setFloaterOpen(TRUE);
|
|
gIMMgr->addSession(LLCacheName::cleanFullName(avatar_name.getLegacyName()),IM_NOTHING_SPECIAL,agent_id);
|
|
}
|
|
// [/Ansariel: Display name support]
|
|
}
|
|
else
|
|
{
|
|
gIMMgr->setFloaterOpen(TRUE);
|
|
gIMMgr->addSession("Friends Conference", IM_SESSION_CONFERENCE_START, ids[0], ids);
|
|
}
|
|
make_ui_sound("UISndStartIM");
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message)
|
|
{
|
|
LLUUID calling_card_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
|
|
send_improved_im(target_id,
|
|
target_name,
|
|
message,
|
|
IM_ONLINE,
|
|
IM_FRIENDSHIP_OFFERED,
|
|
calling_card_folder_id);
|
|
}
|
|
|
|
// static
|
|
bool LLPanelFriends::callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
if (option == 0)
|
|
{
|
|
requestFriendship(notification["payload"]["id"].asUUID(),
|
|
notification["payload"]["name"].asString(),
|
|
response["message"].asString());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool LLPanelFriends::callbackAddFriend(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotification::getSelectedOption(notification, response);
|
|
if (option == 0)
|
|
{
|
|
// Servers older than 1.25 require the text of the message to be the
|
|
// calling card folder ID for the offering user. JC
|
|
LLUUID calling_card_folder_id =
|
|
gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
|
|
std::string message = calling_card_folder_id.asString();
|
|
requestFriendship(notification["payload"]["id"].asUUID(),
|
|
notification["payload"]["name"].asString(),
|
|
message);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onPickAvatar(const std::vector<std::string>& names,
|
|
const std::vector<LLUUID>& ids,
|
|
void* )
|
|
{
|
|
if (names.empty()) return;
|
|
if (ids.empty()) return;
|
|
requestFriendshipDialog(ids[0], names[0]);
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::requestFriendshipDialog(const LLUUID& id,
|
|
const std::string& name)
|
|
{
|
|
if(id == gAgentID)
|
|
{
|
|
LLNotificationsUtil::add("AddSelfFriend");
|
|
return;
|
|
}
|
|
|
|
LLSD args;
|
|
args["NAME"] = name;
|
|
LLSD payload;
|
|
payload["id"] = id;
|
|
payload["name"] = name;
|
|
// Look for server versions like: Second Life Server 1.24.4.95600
|
|
if (gLastVersionChannel.find(" 1.24.") != std::string::npos)
|
|
{
|
|
// Old and busted server version, doesn't support friend
|
|
// requests with messages.
|
|
LLNotificationsUtil::add("AddFriend", args, payload, &callbackAddFriend);
|
|
}
|
|
else
|
|
{
|
|
LLNotificationsUtil::add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onClickAddFriend(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
LLFloater* root_floater = gFloaterView->getParentFloater(panelp);
|
|
LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(onPickAvatar, user_data, FALSE, TRUE);
|
|
if (root_floater)
|
|
{
|
|
root_floater->addDependentFloater(picker);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onClickRemove(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
|
|
//llinfos << "LLPanelFriends::onClickRemove()" << llendl;
|
|
LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
|
|
LLSD args;
|
|
if(ids.size() > 0)
|
|
{
|
|
std::string msgType = "RemoveFromFriends";
|
|
if(ids.size() == 1)
|
|
{
|
|
LLUUID agent_id = ids[0];
|
|
// [Ansariel: Display name support]
|
|
//std::string first, last;
|
|
//if(gCacheName->getName(agent_id, first, last))
|
|
//{
|
|
// args["FIRST_NAME"] = first;
|
|
// args["LAST_NAME"] = last;
|
|
//}
|
|
|
|
LLAvatarName avatar_name;
|
|
if (LLAvatarNameCache::get(agent_id, &avatar_name))
|
|
{
|
|
std::string fullname;
|
|
static const LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0);
|
|
switch (phoenix_name_system)
|
|
{
|
|
case 0 : fullname = avatar_name.getLegacyName(); break;
|
|
case 1 : fullname = (avatar_name.mIsDisplayNameDefault ? avatar_name.mDisplayName : avatar_name.getCompleteName()); break;
|
|
case 2 : fullname = avatar_name.mDisplayName; break;
|
|
default : fullname = avatar_name.getCompleteName(); break;
|
|
}
|
|
|
|
args["NAME"] = fullname;
|
|
}
|
|
// [/Ansariel: Display name support]
|
|
}
|
|
else
|
|
{
|
|
msgType = "RemoveMultipleFromFriends";
|
|
}
|
|
LLSD payload;
|
|
|
|
for (LLDynamicArray<LLUUID>::iterator it = ids.begin();
|
|
it != ids.end();
|
|
++it)
|
|
{
|
|
payload["ids"].append(*it);
|
|
}
|
|
|
|
LLNotifications::instance().add(msgType,
|
|
args,
|
|
payload,
|
|
&handleRemove);
|
|
}
|
|
}
|
|
|
|
void LLPanelFriends::onClickExport(void* user_data)
|
|
{
|
|
std::string agn;
|
|
gAgent.getName(agn);
|
|
AIFilePicker* filepicker = AIFilePicker::create();
|
|
filepicker->open(agn + ".friendlist", FFSAVE_ALL);
|
|
filepicker->run(boost::bind(&LLPanelFriends::onClickExport_continued, user_data, filepicker));
|
|
}
|
|
|
|
void LLPanelFriends::onClickExport_continued(void* user_data, AIFilePicker* filepicker)
|
|
{
|
|
if(!filepicker->hasFilename())
|
|
{
|
|
// User canceled save.
|
|
return;
|
|
}
|
|
std::string const filename = filepicker->getFilename();
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
std::vector<LLScrollListItem*> selected = panelp->mFriendsList->getAllData();//->getAllSelected();
|
|
|
|
LLSD llsd;
|
|
//U32 count = 0;
|
|
//std::string friendlist;
|
|
for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
|
|
{
|
|
LLSD fraind;
|
|
std::string friend_name = (*itr)->getColumn(LIST_FRIEND_NAME)->getValue().asString();
|
|
std::string friend_uuid = (*itr)->getUUID().asString();
|
|
bool show_online_status = (*itr)->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean();
|
|
bool show_map_location = (*itr)->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean();
|
|
bool allow_modify_objects = (*itr)->getColumn(LIST_EDIT_MINE)->getValue().asBoolean();
|
|
fraind["name"] = friend_name;
|
|
fraind["see_online"] = show_online_status;
|
|
fraind["can_map"] = show_map_location;
|
|
fraind["can_mod"] = allow_modify_objects;
|
|
//friendlist += friend_name+"|"+friend_uuid+"|"+show_online_status+"|"+show_map_location+"|"+allow_modify_objects+"\n";
|
|
llsd[friend_uuid] = fraind;
|
|
//count += 1;
|
|
}
|
|
|
|
std::string grid_uri = gHippoGridManager->getConnectedGrid()->getLoginUri();
|
|
//LLStringUtil::toLower(uris[0]);
|
|
llsd["GRID"] = grid_uri;
|
|
|
|
llofstream export_file;
|
|
export_file.open(filename);
|
|
LLSDSerialize::toPrettyXML(llsd, export_file);
|
|
export_file.close();
|
|
}
|
|
|
|
bool LLPanelFriends::merging;
|
|
|
|
void LLPanelFriends::onClickImport(void* user_data)
|
|
{
|
|
AIFilePicker* filepicker = AIFilePicker::create();
|
|
filepicker->open();
|
|
filepicker->run(boost::bind(&LLPanelFriends::onClickImport_filepicker_continued, filepicker));
|
|
}
|
|
|
|
//THIS CODE IS DESIGNED SO THAT EXP/IMP BETWEEN GRIDS WILL FAIL
|
|
//because assuming someone having the same name on another grid is the same person is generally a bad idea
|
|
//i might add the option to query the user as to intelligently detecting matching names on a alternative grid
|
|
// jcool410
|
|
void LLPanelFriends::onClickImport_filepicker_continued(AIFilePicker* filepicker)
|
|
{
|
|
if (!filepicker->hasFilename())
|
|
return;
|
|
|
|
std::string filename = filepicker->getFilename();
|
|
llifstream importer(filename);
|
|
LLSD data;
|
|
LLSDSerialize::fromXMLDocument(data, importer);
|
|
if(data.has("GRID"))
|
|
{
|
|
std::string grid = gHippoGridManager->getConnectedGrid()->getLoginUri();
|
|
if(grid != data["GRID"])return;
|
|
data.erase("GRID");
|
|
}
|
|
|
|
#if LL_WINDOWS
|
|
std::string file = filename.substr(filename.find_last_of("\\")+1);
|
|
#else
|
|
std::string file = filename.substr(filename.find_last_of("/")+1);
|
|
#endif
|
|
|
|
std::string importstate = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "friendimportstate.dat");
|
|
|
|
llifstream stateload(importstate);
|
|
LLSD importstatellsd;
|
|
LLSDSerialize::fromXMLDocument(importstatellsd, stateload);
|
|
|
|
|
|
//LLMessageSystem* msg = gMessageSystem;
|
|
LLSD newdata;
|
|
|
|
LLSD::map_const_iterator iter;
|
|
for(iter = data.beginMap(); iter != data.endMap(); ++iter)
|
|
{//first= var second = val
|
|
LLSD content = iter->second;
|
|
if(!content.has("name"))continue;
|
|
if(!content.has("see_online"))continue;
|
|
if(!content.has("can_map"))continue;
|
|
if(!content.has("can_mod"))continue;
|
|
|
|
LLUUID agent_id = LLUUID(iter->first);
|
|
if(merging && importstatellsd.has(agent_id.asString()))continue;//dont need to request what weve already requested from another list import and have not got a reply yet
|
|
|
|
std::string agent_name = content["name"];
|
|
if(!is_agent_friend(agent_id))//dont need to request what we have
|
|
{
|
|
if(merging)importstatellsd[agent_id.asString()] = content;//MERGEEEE
|
|
requestFriendship(agent_id, agent_name, "Imported from "+file);
|
|
newdata[iter->first] = iter->second;
|
|
}else
|
|
{
|
|
//data.erase(iter->first);
|
|
//--iter;//god help us all
|
|
}
|
|
}
|
|
data = newdata;
|
|
newdata = LLSD();
|
|
|
|
if(!merging)
|
|
{
|
|
merging = true;//this hack is to support importing multiple account lists without spamming users but considering LLs fail in forcing silent declines
|
|
importstatellsd = data;
|
|
}
|
|
|
|
llofstream export_file;
|
|
export_file.open(importstate);
|
|
LLSDSerialize::toPrettyXML(importstatellsd, export_file);
|
|
export_file.close();
|
|
}
|
|
|
|
void LLPanelFriends::FriendImportState(LLUUID id, bool accepted)
|
|
{
|
|
std::string importstate = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "friendimportstate.dat");
|
|
if(LLFile::isfile(importstate))
|
|
{
|
|
llifstream importer(importstate);
|
|
LLSD data;
|
|
LLSDSerialize::fromXMLDocument(data, importer);
|
|
|
|
if(!data.has(id.asString()))return;
|
|
|
|
LLSD user = data[id.asString()];
|
|
if(accepted)
|
|
{
|
|
BOOL can_map = user["can_map"].asBoolean();
|
|
BOOL can_mod = user["can_mod"].asBoolean();
|
|
BOOL see_online = user["see_online"].asBoolean();
|
|
S32 rights = 0;
|
|
if(can_map)rights |= LLRelationship::GRANT_MAP_LOCATION;
|
|
if(can_mod)rights |= LLRelationship::GRANT_MODIFY_OBJECTS;
|
|
if(see_online)rights |= LLRelationship::GRANT_ONLINE_STATUS;
|
|
if(is_agent_friend(id))//is this legit shit yo
|
|
{
|
|
const LLRelationship* friend_status = LLAvatarTracker::instance().getBuddyInfo(id);
|
|
if(friend_status)
|
|
{
|
|
S32 tr = friend_status->getRightsGrantedTo();
|
|
if(tr != rights)
|
|
{
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
msg->newMessageFast(_PREHASH_GrantUserRights);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
|
|
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_Rights);
|
|
msg->addUUID(_PREHASH_AgentRelated, id);
|
|
msg->addS32(_PREHASH_RelatedRights, rights);
|
|
gAgent.sendReliableMessage();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
data.erase(id.asString());//if they declined then we need to forget about it, if they accepted it is done
|
|
|
|
llofstream export_file;
|
|
export_file.open(importstate);
|
|
LLSDSerialize::toPrettyXML(data, export_file);
|
|
export_file.close();
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onClickOfferTeleport(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
|
|
LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
|
|
if(ids.size() > 0)
|
|
{
|
|
handle_lure(ids);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLPanelFriends::onClickPay(void* user_data)
|
|
{
|
|
LLPanelFriends* panelp = (LLPanelFriends*)user_data;
|
|
|
|
LLDynamicArray<LLUUID> ids = panelp->getSelectedIDs();
|
|
if(ids.size() == 1)
|
|
{
|
|
handle_pay_by_id(ids[0]);
|
|
}
|
|
}
|
|
|
|
void LLPanelFriends::confirmModifyRights(rights_map_t& ids, EGrantRevoke command)
|
|
{
|
|
if (ids.empty()) return;
|
|
|
|
LLSD args;
|
|
if(ids.size() > 0)
|
|
{
|
|
rights_map_t* rights = new rights_map_t(ids);
|
|
|
|
// for single friend, show their name
|
|
if(ids.size() == 1)
|
|
{
|
|
LLUUID agent_id = ids.begin()->first;
|
|
//std::string first, last;
|
|
//if(gCacheName->getName(agent_id, first, last))
|
|
//{
|
|
// args["FIRST_NAME"] = first;
|
|
// args["LAST_NAME"] = last;
|
|
//}
|
|
|
|
LLAvatarName avatar_name;
|
|
if (LLAvatarNameCache::get(agent_id, &avatar_name))
|
|
{
|
|
std::string fullname;
|
|
static const LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0);
|
|
switch (phoenix_name_system)
|
|
{
|
|
case 0 : fullname = avatar_name.getLegacyName(); break;
|
|
case 1 : fullname = (avatar_name.mIsDisplayNameDefault ? avatar_name.mDisplayName : avatar_name.getCompleteName()); break;
|
|
case 2 : fullname = avatar_name.mDisplayName; break;
|
|
default : fullname = avatar_name.getCompleteName(); break;
|
|
}
|
|
|
|
args["NAME"] = fullname;
|
|
}
|
|
|
|
if (command == GRANT)
|
|
{
|
|
LLNotificationsUtil::add("GrantModifyRights",
|
|
args,
|
|
LLSD(),
|
|
boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
|
|
}
|
|
else
|
|
{
|
|
LLNotificationsUtil::add("RevokeModifyRights",
|
|
args,
|
|
LLSD(),
|
|
boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (command == GRANT)
|
|
{
|
|
LLNotificationsUtil::add("GrantModifyRightsMultiple",
|
|
args,
|
|
LLSD(),
|
|
boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
|
|
}
|
|
else
|
|
{
|
|
LLNotificationsUtil::add("RevokeModifyRightsMultiple",
|
|
args,
|
|
LLSD(),
|
|
boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool LLPanelFriends::modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t* rights)
|
|
{
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
if(0 == option)
|
|
{
|
|
sendRightsGrant(*rights);
|
|
}
|
|
else
|
|
{
|
|
// need to resync view with model, since user cancelled operation
|
|
rights_map_t::iterator rights_it;
|
|
for (rights_it = rights->begin(); rights_it != rights->end(); ++rights_it)
|
|
{
|
|
const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(rights_it->first);
|
|
updateFriendItem(rights_it->first, info);
|
|
}
|
|
}
|
|
refreshUI();
|
|
|
|
delete rights;
|
|
return false;
|
|
}
|
|
|
|
void LLPanelFriends::applyRightsToFriends()
|
|
{
|
|
BOOL rights_changed = FALSE;
|
|
|
|
// store modify rights separately for confirmation
|
|
rights_map_t rights_updates;
|
|
|
|
BOOL need_confirmation = FALSE;
|
|
EGrantRevoke confirmation_type = GRANT;
|
|
|
|
// this assumes that changes only happened to selected items
|
|
std::vector<LLScrollListItem*> selected = mFriendsList->getAllSelected();
|
|
for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr)
|
|
{
|
|
LLUUID id = (*itr)->getValue();
|
|
const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(id);
|
|
if (buddy_relationship == NULL) continue;
|
|
|
|
bool show_online_staus = (*itr)->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean();
|
|
bool show_map_location = (*itr)->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean();
|
|
bool allow_modify_objects = (*itr)->getColumn(LIST_EDIT_MINE)->getValue().asBoolean();
|
|
|
|
S32 rights = buddy_relationship->getRightsGrantedTo();
|
|
if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS) != show_online_staus)
|
|
{
|
|
rights_changed = TRUE;
|
|
if(show_online_staus)
|
|
{
|
|
rights |= LLRelationship::GRANT_ONLINE_STATUS;
|
|
}
|
|
else
|
|
{
|
|
// ONLINE_STATUS necessary for MAP_LOCATION
|
|
rights &= ~LLRelationship::GRANT_ONLINE_STATUS;
|
|
rights &= ~LLRelationship::GRANT_MAP_LOCATION;
|
|
// propagate rights constraint to UI
|
|
(*itr)->getColumn(LIST_VISIBLE_MAP)->setValue(FALSE);
|
|
}
|
|
}
|
|
if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION) != show_map_location)
|
|
{
|
|
rights_changed = TRUE;
|
|
if(show_map_location)
|
|
{
|
|
// ONLINE_STATUS necessary for MAP_LOCATION
|
|
rights |= LLRelationship::GRANT_MAP_LOCATION;
|
|
rights |= LLRelationship::GRANT_ONLINE_STATUS;
|
|
(*itr)->getColumn(LIST_VISIBLE_ONLINE)->setValue(TRUE);
|
|
}
|
|
else
|
|
{
|
|
rights &= ~LLRelationship::GRANT_MAP_LOCATION;
|
|
}
|
|
}
|
|
|
|
// now check for change in modify object rights, which requires confirmation
|
|
if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects)
|
|
{
|
|
rights_changed = TRUE;
|
|
need_confirmation = TRUE;
|
|
|
|
if(allow_modify_objects)
|
|
{
|
|
rights |= LLRelationship::GRANT_MODIFY_OBJECTS;
|
|
confirmation_type = GRANT;
|
|
}
|
|
else
|
|
{
|
|
rights &= ~LLRelationship::GRANT_MODIFY_OBJECTS;
|
|
confirmation_type = REVOKE;
|
|
}
|
|
}
|
|
|
|
if (rights_changed)
|
|
{
|
|
rights_updates.insert(std::make_pair(id, rights));
|
|
// disable these ui elements until response from server
|
|
// to avoid race conditions
|
|
(*itr)->setEnabled(FALSE);
|
|
}
|
|
}
|
|
|
|
// separately confirm grant and revoke of modify rights
|
|
if (need_confirmation)
|
|
{
|
|
confirmModifyRights(rights_updates, confirmation_type);
|
|
}
|
|
else
|
|
{
|
|
sendRightsGrant(rights_updates);
|
|
}
|
|
}
|
|
|
|
void LLPanelFriends::sendRightsGrant(rights_map_t& ids)
|
|
{
|
|
if (ids.empty()) return;
|
|
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
|
|
// setup message header
|
|
msg->newMessageFast(_PREHASH_GrantUserRights);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
|
|
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
|
|
|
|
rights_map_t::iterator id_it;
|
|
rights_map_t::iterator end_it = ids.end();
|
|
for(id_it = ids.begin(); id_it != end_it; ++id_it)
|
|
{
|
|
msg->nextBlockFast(_PREHASH_Rights);
|
|
msg->addUUID(_PREHASH_AgentRelated, id_it->first);
|
|
msg->addS32(_PREHASH_RelatedRights, id_it->second);
|
|
}
|
|
|
|
mNumRightsChanged = ids.size();
|
|
gAgent.sendReliableMessage();
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
bool LLPanelFriends::handleRemove(const LLSD& notification, const LLSD& response)
|
|
{
|
|
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
|
|
|
const LLSD& ids = notification["payload"]["ids"];
|
|
for(LLSD::array_const_iterator itr = ids.beginArray(); itr != ids.endArray(); ++itr)
|
|
{
|
|
LLUUID id = itr->asUUID();
|
|
const LLRelationship* ip = LLAvatarTracker::instance().getBuddyInfo(id);
|
|
if(ip)
|
|
{
|
|
switch(option)
|
|
{
|
|
case 0: // YES
|
|
if( ip->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS))
|
|
{
|
|
LLAvatarTracker::instance().empower(id, FALSE);
|
|
LLAvatarTracker::instance().notifyObservers();
|
|
}
|
|
LLAvatarTracker::instance().terminateBuddy(id);
|
|
LLAvatarTracker::instance().notifyObservers();
|
|
gInventory.addChangedMask(LLInventoryObserver::LABEL | LLInventoryObserver::CALLING_CARD, LLUUID::null);
|
|
gInventory.notifyObservers();
|
|
break;
|
|
|
|
case 1: // NO
|
|
default:
|
|
llinfos << "No removal performed." << llendl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
return false;
|
|
}
|