270 lines
7.2 KiB
C++
270 lines
7.2 KiB
C++
/**
|
|
* @file llavatarlist.h
|
|
* @brief Generic avatar list
|
|
*
|
|
* $LicenseInfo:firstyear=2009&license=viewergpl$
|
|
*
|
|
* Copyright (c) 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 "llavatarlist.h"
|
|
|
|
// newview
|
|
#include "llcallingcard.h" // for LLAvatarTracker
|
|
#include "llcachename.h"
|
|
#include "llvoiceclient.h"
|
|
|
|
static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list");
|
|
|
|
// Maximum number of avatars that can be added to a list in one pass.
|
|
// Used to limit time spent for avatar list update per frame.
|
|
static const unsigned ADD_LIMIT = 50;
|
|
|
|
static bool findInsensitive(std::string haystack, const std::string& needle_upper)
|
|
{
|
|
LLStringUtil::toUpper(haystack);
|
|
return haystack.find(needle_upper) != std::string::npos;
|
|
}
|
|
|
|
|
|
//comparators
|
|
static const LLAvatarItemNameComparator NAME_COMPARATOR;
|
|
static const LLFlatListView::ItemReverseComparator REVERSE_NAME_COMPARATOR(NAME_COMPARATOR);
|
|
|
|
LLAvatarList::Params::Params()
|
|
:
|
|
volume_column_width("volume_column_width", 0)
|
|
, online_go_first("online_go_first", true)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
LLAvatarList::LLAvatarList(const Params& p)
|
|
: LLFlatListView(p)
|
|
, mOnlineGoFirst(p.online_go_first)
|
|
, mContextMenu(NULL)
|
|
, mDirty(true) // to force initial update
|
|
{
|
|
setCommitOnSelectionChange(true);
|
|
|
|
// Set default sort order.
|
|
setComparator(&NAME_COMPARATOR);
|
|
}
|
|
|
|
// virtual
|
|
void LLAvatarList::draw()
|
|
{
|
|
if (mDirty)
|
|
refresh();
|
|
|
|
LLFlatListView::draw();
|
|
}
|
|
|
|
void LLAvatarList::setNameFilter(const std::string& filter)
|
|
{
|
|
if (mNameFilter != filter)
|
|
{
|
|
mNameFilter = filter;
|
|
setDirty();
|
|
}
|
|
}
|
|
|
|
void LLAvatarList::sortByName()
|
|
{
|
|
setComparator(&NAME_COMPARATOR);
|
|
sort();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PROTECTED SECTION
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void LLAvatarList::refresh()
|
|
{
|
|
bool have_names = TRUE;
|
|
bool add_limit_exceeded = false;
|
|
bool modified = false;
|
|
bool have_filter = !mNameFilter.empty();
|
|
|
|
// Save selection.
|
|
std::vector<LLUUID> selected_ids;
|
|
getSelectedUUIDs(selected_ids);
|
|
LLUUID current_id = getSelectedUUID();
|
|
|
|
// Determine what to add and what to remove.
|
|
std::vector<LLUUID> added, removed;
|
|
LLAvatarList::computeDifference(getIDs(), added, removed);
|
|
|
|
// Handle added items.
|
|
unsigned nadded = 0;
|
|
for (std::vector<LLUUID>::const_iterator it=added.begin(); it != added.end(); it++)
|
|
{
|
|
std::string name;
|
|
const LLUUID& buddy_id = *it;
|
|
have_names &= (bool)gCacheName->getFullName(buddy_id, name);
|
|
if (!have_filter || findInsensitive(name, mNameFilter))
|
|
{
|
|
if (nadded >= ADD_LIMIT)
|
|
{
|
|
add_limit_exceeded = true;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id));
|
|
modified = true;
|
|
nadded++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle removed items.
|
|
for (std::vector<LLUUID>::const_iterator it=removed.begin(); it != removed.end(); it++)
|
|
{
|
|
removeItemByUUID(*it);
|
|
modified = true;
|
|
}
|
|
|
|
// Handle filter.
|
|
if (have_filter)
|
|
{
|
|
std::vector<LLSD> cur_values;
|
|
getValues(cur_values);
|
|
|
|
for (std::vector<LLSD>::const_iterator it=cur_values.begin(); it != cur_values.end(); it++)
|
|
{
|
|
std::string name;
|
|
const LLUUID& buddy_id = it->asUUID();
|
|
have_names &= (bool)gCacheName->getFullName(buddy_id, name);
|
|
if (!findInsensitive(name, mNameFilter))
|
|
{
|
|
removeItemByUUID(buddy_id);
|
|
modified = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
sort();
|
|
|
|
// re-select items
|
|
// selectMultiple(selected_ids); // TODO: implement in LLFlatListView if need
|
|
selectItemByUUID(current_id);
|
|
|
|
// If the name filter is specified and the names are incomplete,
|
|
// we need to re-update when the names are complete so that
|
|
// the filter can be applied correctly.
|
|
//
|
|
// Otherwise, if we have no filter then no need to update again
|
|
// because the items will update their names.
|
|
bool dirty = add_limit_exceeded || (have_filter && !have_names);
|
|
setDirty(dirty);
|
|
|
|
// Commit if we've added/removed items.
|
|
if (modified)
|
|
onCommit();
|
|
}
|
|
|
|
|
|
void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos)
|
|
{
|
|
LLAvatarListItem* item = new LLAvatarListItem();
|
|
item->showStatus(false);
|
|
item->showInfoBtn(true);
|
|
item->showSpeakingIndicator(true);
|
|
item->setName(name);
|
|
item->setAvatarId(id);
|
|
item->setContextMenu(mContextMenu);
|
|
|
|
item->childSetVisible("info_btn", false);
|
|
|
|
addItem(item, id, pos);
|
|
}
|
|
|
|
void LLAvatarList::computeDifference(
|
|
const std::vector<LLUUID>& vnew_unsorted,
|
|
std::vector<LLUUID>& vadded,
|
|
std::vector<LLUUID>& vremoved)
|
|
{
|
|
std::vector<LLUUID> vcur;
|
|
std::vector<LLUUID> vnew = vnew_unsorted;
|
|
|
|
// Convert LLSDs to LLUUIDs.
|
|
{
|
|
std::vector<LLSD> vcur_values;
|
|
getValues(vcur_values);
|
|
|
|
for (size_t i=0; i<vcur_values.size(); i++)
|
|
vcur.push_back(vcur_values[i].asUUID());
|
|
}
|
|
|
|
std::sort(vcur.begin(), vcur.end());
|
|
std::sort(vnew.begin(), vnew.end());
|
|
|
|
std::vector<LLUUID>::iterator it;
|
|
size_t maxsize = llmax(vcur.size(), vnew.size());
|
|
vadded.resize(maxsize);
|
|
vremoved.resize(maxsize);
|
|
|
|
// what to remove
|
|
it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin());
|
|
vremoved.erase(it, vremoved.end());
|
|
|
|
// what to add
|
|
it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin());
|
|
vadded.erase(it, vadded.end());
|
|
}
|
|
|
|
bool LLAvatarItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const
|
|
{
|
|
const LLAvatarListItem* avatar_item1 = dynamic_cast<const LLAvatarListItem*>(item1);
|
|
const LLAvatarListItem* avatar_item2 = dynamic_cast<const LLAvatarListItem*>(item2);
|
|
|
|
if (!avatar_item1 || !avatar_item2)
|
|
{
|
|
llerror("item1 and item2 cannot be null", 0);
|
|
return true;
|
|
}
|
|
|
|
return doCompare(avatar_item1, avatar_item2);
|
|
}
|
|
|
|
bool LLAvatarItemNameComparator::doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const
|
|
{
|
|
std::string name1 = avatar_item1->getAvatarName();
|
|
std::string name2 = avatar_item2->getAvatarName();
|
|
|
|
LLStringUtil::toUpper(name1);
|
|
LLStringUtil::toUpper(name2);
|
|
|
|
return name1 < name2;
|
|
}
|