diff options
Diffstat (limited to 'indra/newview/llavatarlist.cpp')
-rw-r--r-- | indra/newview/llavatarlist.cpp | 546 |
1 files changed, 149 insertions, 397 deletions
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 2e64c10bb2..36f9780ad0 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -37,481 +37,233 @@ // newview #include "llcallingcard.h" // for LLAvatarTracker #include "llcachename.h" -#include "lloutputmonitorctrl.h" #include "llvoiceclient.h" static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list"); -static LLDefaultChildRegistry::Register<LLAvatarListTmp> r_tmp("avatar_list_tmp"); -static const std::string COMMENT_TEXTBOX = "comment_text"; +// 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) +volume_column_width("volume_column_width", 0) +, online_go_first("online_go_first", true) { - draw_heading = true; - draw_stripes = false; - multi_select = false; - column_padding = 0; - search_column = COL_NAME; - sort_column = COL_NAME; } + + LLAvatarList::LLAvatarList(const Params& p) -: LLScrollListCtrl(p) - , mHaveVolumeColumn(p.volume_column_width > 0) - , mOnlineGoFirst(p.online_go_first) +: LLFlatListView(p) +, mOnlineGoFirst(p.online_go_first) +, mContextMenu(NULL) +, mDirty(true) // to force initial update { - setCommitOnSelectionChange(TRUE); // there's no such param in LLScrollListCtrl::Params - - // display a context menu appropriate for a list of avatar names - setContextMenu(LLScrollListCtrl::MENU_AVATAR); - - // "volume" column - { - LLScrollListColumn::Params col_params; - col_params.name = "volume"; - col_params.header.label = "Volume"; // *TODO: localize or remove the header - col_params.width.pixel_width = p.volume_column_width; - addColumn(col_params); - } - - // "name" column - { - LLScrollListColumn::Params col_params; - col_params.name = "name"; - col_params.header.label = "Name"; // *TODO: localize or remove the header - col_params.width.dynamic_width = true; - addColumn(col_params); - } - - // "online status" column - { - LLScrollListColumn::Params col_params; - col_params.name = "online"; - col_params.header.label = "Online"; // *TODO: localize or remove the header - col_params.width.pixel_width = 0; // invisible column - addColumn(col_params); - } - - - // invisible "id" column - { - LLScrollListColumn::Params col_params; - col_params.name = "id"; - col_params.header.label = "ID"; // *TODO: localize or remove the header - col_params.width.pixel_width = 0; - addColumn(col_params); - } - - // Primary sort = online status, secondary sort = name - // The corresponding parameters don't work because we create columns dynamically. - sortByColumnIndex(COL_NAME, TRUE); - if (mOnlineGoFirst) - sortByColumnIndex(COL_ONLINE, FALSE); - setSearchColumn(COL_NAME); + setCommitOnSelectionChange(true); + + // Set default sort order. + setComparator(&NAME_COMPARATOR); } // virtual void LLAvatarList::draw() { - LLScrollListCtrl::draw(); - if (mHaveVolumeColumn) - { - updateVolume(); - } -} + if (mDirty) + refresh(); -std::vector<LLUUID> LLAvatarList::getSelectedIDs() -{ - LLUUID selected_id; - std::vector<LLUUID> avatar_ids; - std::vector<LLScrollListItem*> selected = getAllSelected(); - for(std::vector<LLScrollListItem*>::iterator itr = selected.begin(); itr != selected.end(); ++itr) - { - avatar_ids.push_back((*itr)->getUUID()); - } - return avatar_ids; + LLFlatListView::draw(); } -void LLAvatarList::addItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos) +void LLAvatarList::setNameFilter(const std::string& filter) { - std::string fullname; - - // Populate list item. - LLSD element; - element["id"] = id; - - // Update volume column (if we have one) - { - std::string icon = mHaveVolumeColumn ? getVolumeIcon(id) : ""; - LLSD& volume_column = element["columns"][COL_VOLUME]; - volume_column["column"] = "volume"; - volume_column["type"] = "icon"; - volume_column["value"] = icon; - } - - LLSD& friend_column = element["columns"][COL_NAME]; - friend_column["column"] = "name"; - friend_column["value"] = name; - - LLSD& online_column = element["columns"][COL_ONLINE]; - online_column["column"] = "online"; - online_column["value"] = is_bold ? "1" : "0"; - - LLScrollListItem* new_itemp = addElement(element, pos); - - // Indicate buddy online status. - // (looks like parsing font parameters from LLSD is broken) - if (is_bold) + if (mNameFilter != filter) { - LLScrollListText* name_textp = dynamic_cast<LLScrollListText*>(new_itemp->getColumn(COL_NAME)); - if (name_textp) - name_textp->setFontStyle(LLFontGL::BOLD); - else - { - llwarns << "Name column not found" << llendl; - } + mNameFilter = filter; + setDirty(); } } -static bool findInsensitive(std::string haystack, const std::string& needle_upper) +void LLAvatarList::sortByName() { - LLStringUtil::toUpper(haystack); - return haystack.find(needle_upper) != std::string::npos; + setComparator(&NAME_COMPARATOR); + sort(); } -BOOL LLAvatarList::update(const std::vector<LLUUID>& all_buddies, const std::string& name_filter) +////////////////////////////////////////////////////////////////////////// +// PROTECTED SECTION +////////////////////////////////////////////////////////////////////////// + +void LLAvatarList::refresh() { - BOOL have_names = TRUE; - + bool have_names = TRUE; + bool add_limit_exceeded = false; + bool modified = false; + bool have_filter = !mNameFilter.empty(); + // Save selection. - std::vector<LLUUID> selected_ids = getSelectedIDs(); - LLUUID current_id = getCurrentID(); - S32 pos = getScrollPos(); - - std::vector<LLUUID>::const_iterator buddy_it = all_buddies.begin(); - deleteAllItems(); - for(; buddy_it != all_buddies.end(); ++buddy_it) - { - std::string name; - const LLUUID& buddy_id = *buddy_it; - have_names &= gCacheName->getFullName(buddy_id, name); - if (name_filter != LLStringUtil::null && !findInsensitive(name, name_filter)) - continue; - addItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); - } + std::vector<LLUUID> selected_ids; + getSelectedUUIDs(selected_ids); + LLUUID current_id = getSelectedUUID(); - // 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 - updateSort(); + // Determine what to add and what to remove. + std::vector<LLUUID> added, removed; + LLAvatarList::computeDifference(getIDs(), added, removed); - // re-select items - selectMultiple(selected_ids); - setCurrentByID(current_id); -#if 0 - // Restore selection. - if(selected_ids.size() > 0) + // Handle added items. + unsigned nadded = 0; + for (std::vector<LLUUID>::const_iterator it=added.begin(); it != added.end(); it++) { - // 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. - for(std::vector<LLUUID>::iterator itr = selected_ids.begin(); itr != selected_ids.end(); ++itr) + std::string name; + const LLUUID& buddy_id = *it; + have_names &= (bool)gCacheName->getFullName(buddy_id, name); + if (!have_filter || findInsensitive(name, mNameFilter)) { - setSelectedByValue(*itr, true); + if (nadded >= ADD_LIMIT) + { + add_limit_exceeded = true; + break; + } + else + { + addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); + modified = true; + nadded++; + } } } -#endif - setScrollPos(pos); - - updateLineHeight(); - LLRect rect = getRequiredRect(); - - LLSD params; - params["action"] = "size_changes"; - params["width"] = rect.getWidth(); - params["height"] = llmax(rect.getHeight(),20) + 5; - - getParent()->notifyParent(params); - - return have_names; -} - -// static -std::string LLAvatarList::getVolumeIcon(const LLUUID& id) -{ - // - // Determine icon appropriate for the current avatar volume. - // - // *TODO: remove this in favor of LLOutputMonitorCtrl - // when ListView widget is implemented - // which is capable of containing arbitrary widgets. - // - static LLOutputMonitorCtrl::Params default_monitor_params(LLUICtrlFactory::getDefaultParams<LLOutputMonitorCtrl>()); - bool muted = gVoiceClient->getIsModeratorMuted(id) || gVoiceClient->getOnMuteList(id); - F32 power = gVoiceClient->getCurrentPower(id); - std::string icon; - if (muted) - { - icon = default_monitor_params.image_mute.name; - } - else if (power == 0.f) - { - icon = default_monitor_params.image_off.name; - } - else if (power < LLVoiceClient::OVERDRIVEN_POWER_LEVEL) + // Handle removed items. + for (std::vector<LLUUID>::const_iterator it=removed.begin(); it != removed.end(); it++) { - S32 icon_image_idx = llmin(2, llfloor((power / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f)); - switch(icon_image_idx) - { - default: - case 0: - icon = default_monitor_params.image_on.name; - break; - case 1: - icon = default_monitor_params.image_level_1.name; - break; - case 2: - icon = default_monitor_params.image_level_2.name; - break; - } + removeItemByUUID(*it); + modified = true; } - else - { - // overdriven - icon = default_monitor_params.image_level_3.name; - } - - return icon; -} - -// Update volume column for all list rows. -void LLAvatarList::updateVolume() -{ - item_list& items = getItemList(); - for (item_list::iterator item_it = items.begin(); - item_it != items.end(); - ++item_it) + // Handle filter. + if (have_filter) { - LLScrollListItem* itemp = (*item_it); - LLUUID speaker_id = itemp->getUUID(); + std::vector<LLSD> cur_values; + getValues(cur_values); - LLScrollListCell* icon_cell = itemp->getColumn(COL_VOLUME); - if (icon_cell) - icon_cell->setValue(getVolumeIcon(speaker_id)); + 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; + } + } } -} - - - - -#include "llavatarlistitem.h" - -LLAvatarListTmp::Params::Params() -: -volume_column_width("volume_column_width", 0) -, online_go_first("online_go_first", 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(); -LLAvatarListTmp::LLAvatarListTmp(const Params& p) -: LLFlatListView(p) -, mHaveVolumeColumn(p.volume_column_width > 0) -, mOnlineGoFirst(p.online_go_first) -{ - LLRect item_list_rect = getLocalRect(); - item_list_rect.stretch( -getBorderWidth()); - - LLTextBox::Params text_p; - text_p.name(COMMENT_TEXTBOX); - text_p.border_visible(false); - text_p.rect(item_list_rect); - text_p.follows.flags(FOLLOWS_ALL); - addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); -} + // re-select items + // selectMultiple(selected_ids); // TODO: implement in LLFlatListView if need + selectItemByUUID(current_id); -// virtual -void LLAvatarListTmp::draw() -{ - LLFlatListView::draw(); - if (mHaveVolumeColumn) - { - updateVolume(); - } + // 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(); } -std::vector<LLUUID> LLAvatarListTmp::getSelectedIDs() -{ - LLUUID selected_id; - std::vector<LLUUID> avatar_ids; - - getSelectedUUIDs(avatar_ids); - return avatar_ids; -} - -void LLAvatarListTmp::addNewItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos) +void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos) { LLAvatarListItem* item = new LLAvatarListItem(); - item->showStatus(true); + 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); - - setCommentVisible(false); } -BOOL LLAvatarListTmp::update(const std::vector<LLUUID>& all_buddies, const std::string& name_filter) +void LLAvatarList::computeDifference( + const std::vector<LLUUID>& vnew_unsorted, + std::vector<LLUUID>& vadded, + std::vector<LLUUID>& vremoved) { - BOOL have_names = TRUE; - - // Save selection. - std::vector<LLUUID> selected_ids = getSelectedIDs(); - LLUUID current_id = getSelectedUUID(); - LLRect pos = getScrolledViewRect(); + std::vector<LLUUID> vcur; + std::vector<LLUUID> vnew = vnew_unsorted; - std::vector<LLUUID>::const_iterator buddy_it = all_buddies.begin(); - clear(); - for(; buddy_it != all_buddies.end(); ++buddy_it) + // Convert LLSDs to LLUUIDs. { - std::string name; - const LLUUID& buddy_id = *buddy_it; - have_names &= gCacheName->getFullName(buddy_id, name); - if (name_filter != LLStringUtil::null && !findInsensitive(name, name_filter)) - continue; - addNewItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); - } - - // 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 - // updateSort(); // TODO: implement sorting + std::vector<LLSD> vcur_values; + getValues(vcur_values); - // re-select items - // selectMultiple(selected_ids); // TODO: implement in LLFlatListView if need - selectItemByUUID(current_id); - - scrollToShowRect(pos); - - - setCommentVisible(false); - - return have_names; -} - - -const LLUUID LLAvatarListTmp::getCurrentID() const -{ - return getSelectedUUID(); -} + for (size_t i=0; i<vcur_values.size(); i++) + vcur.push_back(vcur_values[i].asUUID()); + } -void LLAvatarListTmp::setCommentText(const std::string& comment_text) -{ - getChild<LLTextBox>(COMMENT_TEXTBOX)->setValue(comment_text); -} + 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); -////////////////////////////////////////////////////////////////////////// -// PROTECTED SECTION -////////////////////////////////////////////////////////////////////////// + // what to remove + it = set_difference(vcur.begin(), vcur.end(), vnew.begin(), vnew.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); -// virtual overridden -bool LLAvatarListTmp::removeItemPair(item_pair_t* item_pair) -{ - bool removed = LLFlatListView::removeItemPair(item_pair); - setCommentVisible(size() == 0); - return removed; + // what to add + it = set_difference(vnew.begin(), vnew.end(), vcur.begin(), vcur.end(), vadded.begin()); + vadded.erase(it, vadded.end()); } - -////////////////////////////////////////////////////////////////////////// -// PRIVATE SECTION -////////////////////////////////////////////////////////////////////////// - -// static -std::string LLAvatarListTmp::getVolumeIcon(const LLUUID& id) +bool LLAvatarItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const { - // - // Determine icon appropriate for the current avatar volume. - // - // *TODO: remove this in favor of LLOutputMonitorCtrl - // when ListView widget is implemented - // which is capable of containing arbitrary widgets. - // - static LLOutputMonitorCtrl::Params default_monitor_params(LLUICtrlFactory::getDefaultParams<LLOutputMonitorCtrl>()); - bool muted = gVoiceClient->getIsModeratorMuted(id) || gVoiceClient->getOnMuteList(id); - F32 power = gVoiceClient->getCurrentPower(id); - std::string icon; - - if (muted) - { - icon = default_monitor_params.image_mute.name; - } - else if (power == 0.f) - { - icon = default_monitor_params.image_off.name; - } - else if (power < LLVoiceClient::OVERDRIVEN_POWER_LEVEL) - { - S32 icon_image_idx = llmin(2, llfloor((power / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f)); - switch(icon_image_idx) - { - default: - case 0: - icon = default_monitor_params.image_on.name; - break; - case 1: - icon = default_monitor_params.image_level_1.name; - break; - case 2: - icon = default_monitor_params.image_level_2.name; - break; - } - } - else + const LLAvatarListItem* avatar_item1 = dynamic_cast<const LLAvatarListItem*>(item1); + const LLAvatarListItem* avatar_item2 = dynamic_cast<const LLAvatarListItem*>(item2); + + if (!avatar_item1 || !avatar_item2) { - // overdriven - icon = default_monitor_params.image_level_3.name; + llerror("item1 and item2 cannot be null", 0); + return true; } - return icon; + return doCompare(avatar_item1, avatar_item2); } -// Update volume column for all list rows. -void LLAvatarListTmp::updateVolume() +bool LLAvatarItemNameComparator::doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const { - // TODO: implement via Listener - /* - item_list& items = getItemList(); + std::string name1 = avatar_item1->getAvatarName(); + std::string name2 = avatar_item2->getAvatarName(); - for (item_list::iterator item_it = items.begin(); - item_it != items.end(); - ++item_it) - { - LLScrollListItem* itemp = (*item_it); - LLUUID speaker_id = itemp->getUUID(); + LLStringUtil::toUpper(name1); + LLStringUtil::toUpper(name2); - LLScrollListCell* icon_cell = itemp->getColumn(COL_VOLUME); - if (icon_cell) - icon_cell->setValue(getVolumeIcon(speaker_id)); - } - */ + return name1 < name2; } - -void LLAvatarListTmp::setCommentVisible(bool visible) const -{ - getChildView(COMMENT_TEXTBOX)->setVisible(visible); -} - -// EOF |