Implemented EXT-6724(normal task) - Implement flat list view of filtered inventory for "add wearables" panel of outfit editor

1. Modified LLInventoryItemsList - implemented delayed item construction. Items are added during draw, not more than 50 items will be added in single draw. This lets us reduce system overload during multiple panel construction.
2. Implemented LLFilteredWearableListManager to populate inventory flat list with data. This class filters entire inventory according to specified filter and populates specified inventory list with data.
3. Created LLCommonUtil::computeDifference() to avoid code copy-pasting(will use it in all appropriate places in next review request)

Reviewed by Mike Antipov - https://codereview.productengine.com/secondlife/r/301/

--HG--
branch : product-engine
master
Dmitry Zaporozhan 2010-04-22 15:48:48 +03:00
parent 29801ac52b
commit b15e2beabf
11 changed files with 460 additions and 17 deletions

View File

@ -35,6 +35,7 @@ set(llcommon_SOURCE_FILES
llbase32.cpp
llbase64.cpp
llcommon.cpp
llcommonutils.cpp
llcoros.cpp
llcrc.cpp
llcriticaldamp.cpp
@ -124,6 +125,7 @@ set(llcommon_HEADER_FILES
llchat.h
llclickaction.h
llcommon.h
llcommonutils.h
llcoros.h
llcrc.h
llcriticaldamp.h

View File

@ -0,0 +1,61 @@
/**
* @file llcommonutils.h
* @brief Commin utils
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, 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 "linden_common.h"
#include "llcommonutils.h"
void LLCommonUtils::computeDifference(
const uuid_vec_t& vnew,
const uuid_vec_t& vcur,
uuid_vec_t& vadded,
uuid_vec_t& vremoved)
{
uuid_vec_t vnew_copy(vnew);
uuid_vec_t vcur_copy(vcur);
std::sort(vnew_copy.begin(), vnew_copy.end());
std::sort(vcur_copy.begin(), vcur_copy.end());
size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size());
vadded.resize(maxsize);
vremoved.resize(maxsize);
uuid_vec_t::iterator it;
// what was removed
it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin());
vremoved.erase(it, vremoved.end());
// what was added
it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin());
vadded.erase(it, vadded.end());
}
// EOF

View File

@ -0,0 +1,51 @@
/**
* @file llcommonutils.h
* @brief Common utils
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, 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$
*/
#ifndef LL_LLCOMMONUTILS_H
#define LL_LLCOMMONUTILS_H
namespace LLCommonUtils
{
/**
* Computes difference between 'vnew' and 'vcur' vectors.
* Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded'
* Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved'
*/
LL_COMMON_API void computeDifference(
const uuid_vec_t& vnew,
const uuid_vec_t& vcur,
uuid_vec_t& vadded,
uuid_vec_t& vremoved);
};
#endif //LL_LLCOMMONUTILS_H
// EOF

View File

@ -142,6 +142,7 @@ set(viewer_SOURCE_FILES
llfavoritesbar.cpp
llfeaturemanager.cpp
llfilepicker.cpp
llfilteredwearablelist.cpp
llfirstuse.cpp
llflexibleobject.cpp
llfloaterabout.cpp
@ -651,6 +652,7 @@ set(viewer_HEADER_FILES
llfavoritesbar.h
llfeaturemanager.h
llfilepicker.h
llfilteredwearablelist.h
llfirstuse.h
llflexibleobject.h
llfloaterabout.h

View File

@ -0,0 +1,113 @@
/**
* @file llfilteredwearablelist.cpp
* @brief Functionality for showing filtered wearable flat list
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, 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 "llfilteredwearablelist.h"
// newview
#include "llinventoryfunctions.h"
#include "llinventoryitemslist.h"
#include "llinventorymodel.h"
class LLFindItemsByMask : public LLInventoryCollectFunctor
{
public:
LLFindItemsByMask(U64 mask)
: mFilterMask(mask)
{}
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(item)
{
if( mFilterMask & (1LL << item->getInventoryType()) )
{
return TRUE;
}
}
return FALSE;
}
private:
U64 mFilterMask;
};
//////////////////////////////////////////////////////////////////////////
LLFilteredWearableListManager::LLFilteredWearableListManager(LLInventoryItemsList* list, U64 filter_mask)
: mWearableList(list)
, mFilterMask(filter_mask)
{
llassert(mWearableList);
gInventory.addObserver(this);
gInventory.fetchDescendentsOf(gInventory.getRootFolderID());
}
LLFilteredWearableListManager::~LLFilteredWearableListManager()
{
gInventory.removeObserver(this);
}
void LLFilteredWearableListManager::changed(U32 mask)
{
if(!gInventory.isInventoryUsable())
{
return;
}
populateList();
}
void LLFilteredWearableListManager::setFilterMask(U64 mask)
{
mFilterMask = mask;
populateList();
}
void LLFilteredWearableListManager::populateList()
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
LLFindItemsByMask collector(mFilterMask);
gInventory.collectDescendentsIf(
gInventory.getRootFolderID(),
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH,
collector);
// Probably will also need to get items from Library (waiting for reply in EXT-6724).
mWearableList->refreshList(item_array);
}
// EOF

View File

@ -0,0 +1,70 @@
/**
* @file llfilteredwearablelist.h
* @brief Functionality for showing filtered wearable flat list
*
* $LicenseInfo:firstyear=2010&license=viewergpl$
*
* Copyright (c) 2010, 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$
*/
#ifndef LL_LLFILTEREDWEARABLELIST_H
#define LL_LLFILTEREDWEARABLELIST_H
#include "llinventoryobserver.h"
class LLInventoryItemsList;
// Class that fills LLInventoryItemsList with filtered data.
class LLFilteredWearableListManager : public LLInventoryObserver
{
LOG_CLASS(LLFilteredWearableListManager);
public:
LLFilteredWearableListManager(LLInventoryItemsList* list, U64 filter_mask);
~LLFilteredWearableListManager();
/** LLInventoryObserver implementation
*
*/
/*virtual*/ void changed(U32 mask);
/**
* Sets new filter and applies it immediately
*/
void setFilterMask(U64 mask);
/**
* Populates wearable list with filtered data.
*/
void populateList();
private:
LLInventoryItemsList* mWearableList;
U64 mFilterMask;
};
#endif //LL_LLFILTEREDWEARABLELIST_H
// EOF

View File

@ -33,6 +33,9 @@
#include "llinventoryitemslist.h"
// llcommon
#include "llcommonutils.h"
#include "lliconctrl.h"
#include "llinventoryfunctions.h"
@ -112,6 +115,7 @@ void LLPanelInventoryItem::onMouseLeave(S32 x, S32 y, MASK mask)
LLInventoryItemsList::LLInventoryItemsList(const LLFlatListView::Params& p)
: LLFlatListView(p)
, mNeedsRefresh(false)
{}
// virtual
@ -120,22 +124,88 @@ LLInventoryItemsList::~LLInventoryItemsList()
void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item_array)
{
clear();
for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
iter != item_array.end();
iter++)
getIDs().clear();
LLInventoryModel::item_array_t::const_iterator it = item_array.begin();
for( ; item_array.end() != it; ++it)
{
LLViewerInventoryItem *item = (*iter);
getIDs().push_back((*it)->getUUID());
}
mNeedsRefresh = true;
}
LLPanelInventoryItem *list_item = new LLPanelInventoryItem(item->getType(),
item->getInventoryType(),
item->getFlags(),
item->getName(),
LLStringUtil::null);
if (!addItem(list_item, item->getUUID()))
{
llerrs << "Couldn't add flat item." << llendl;
}
void LLInventoryItemsList::draw()
{
LLFlatListView::draw();
if(mNeedsRefresh)
{
refresh();
}
}
void LLInventoryItemsList::refresh()
{
static const unsigned ADD_LIMIT = 50;
uuid_vec_t added_items;
uuid_vec_t removed_items;
computeDifference(getIDs(), added_items, removed_items);
bool add_limit_exceeded = false;
unsigned nadded = 0;
uuid_vec_t::const_iterator it = added_items.begin();
for( ; added_items.end() != it; ++it)
{
if(nadded >= ADD_LIMIT)
{
add_limit_exceeded = true;
break;
}
LLViewerInventoryItem* item = gInventory.getItem(*it);
addNewItem(item);
++nadded;
}
it = removed_items.begin();
for( ; removed_items.end() != it; ++it)
{
removeItemByUUID(*it);
}
bool needs_refresh = add_limit_exceeded;
setNeedsRefresh(needs_refresh);
}
void LLInventoryItemsList::computeDifference(
const uuid_vec_t& vnew,
uuid_vec_t& vadded,
uuid_vec_t& vremoved)
{
uuid_vec_t vcur;
{
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());
}
LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
}
void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item)
{
llassert(item);
LLPanelInventoryItem *list_item = new LLPanelInventoryItem(item->getType(),
item->getInventoryType(), item->getFlags(), item->getName(), LLStringUtil::null);
if (!addItem(list_item, item->getUUID()))
{
llwarns << "Couldn't add flat list item." << llendl;
llassert(!"Couldn't add flat list item.");
}
}
// EOF

View File

@ -80,9 +80,43 @@ public:
void refreshList(const LLInventoryModel::item_array_t item_array);
/**
* Let list know items need to be refreshed in next draw()
*/
void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; }
bool getNeedsRefresh(){ return mNeedsRefresh; }
/*virtual*/ void draw();
protected:
friend class LLUICtrlFactory;
LLInventoryItemsList(const LLFlatListView::Params& p);
uuid_vec_t& getIDs() { return mIDs; }
/**
* Refreshes list items, adds new items and removes deleted items.
* Called from draw() until all new items are added, ,
* maximum 50 items can be added during single call.
*/
void refresh();
/**
* Compute difference between new items and current items, fills 'vadded' with added items,
* 'vremoved' with removed items. See LLCommonUtils::computeDifference
*/
void computeDifference(const uuid_vec_t& vnew, uuid_vec_t& vadded, uuid_vec_t& vremoved);
/**
* Add an item to the list
*/
void addNewItem(LLViewerInventoryItem* item);
private:
uuid_vec_t mIDs; // IDs of items that were added in refreshList().
// Will be used in refresh() to determine added and removed ids
bool mNeedsRefresh;
};
#endif //LL_LLINVENTORYITEMSLIST_H

View File

@ -38,7 +38,9 @@
#include "llagent.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
#include "llfilteredwearablelist.h"
#include "llinventory.h"
#include "llinventoryitemslist.h"
#include "llviewercontrol.h"
#include "llui.h"
#include "llfloater.h"
@ -164,6 +166,7 @@ BOOL LLPanelOutfitEdit::postBuild()
childSetCommitCallback("add_btn", boost::bind(&LLPanelOutfitEdit::showAddWearablesPanel, this), NULL);
childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredWearablesPanel, this), NULL);
mLookContents = getChild<LLScrollListCtrl>("look_items_list");
mLookContents->sortByColumn("look_item_sort", TRUE);
@ -229,6 +232,9 @@ BOOL LLPanelOutfitEdit::postBuild()
save_registar.add("Outfit.SaveAsNew.Action", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true));
mSaveMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_save_outfit.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
mWearableListManager = new LLFilteredWearableListManager(
getChild<LLInventoryItemsList>("filtered_wearables_list"), ALL_ITEMS_MASK);
return TRUE;
}
@ -242,6 +248,11 @@ void LLPanelOutfitEdit::showWearablesFilter()
childSetVisible("filter_combobox_panel", childGetValue("filter_button"));
}
void LLPanelOutfitEdit::showFilteredWearablesPanel()
{
childSetVisible("filtered_wearables_panel", !childIsVisible("filtered_wearables_panel"));
}
void LLPanelOutfitEdit::saveOutfit(bool as_new)
{
if (!as_new && LLAppearanceMgr::getInstance()->updateBaseOutfit())
@ -275,6 +286,7 @@ void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl)
{
U32 curr_filter_type = type_filter->getCurrentIndex();
mInventoryItemsPanel->setFilterTypes(mLookItemTypes[curr_filter_type].inventoryMask);
mWearableListManager->setFilterMask(mLookItemTypes[curr_filter_type].inventoryMask);
}
mSavedFolderState->setApply(TRUE);
@ -577,4 +589,4 @@ void LLPanelOutfitEdit::displayCurrentOutfit()
updateLookInfo();
}
// EOF

View File

@ -55,6 +55,7 @@ class LLScrollListCtrl;
class LLToggleableMenu;
class LLLookFetchObserver;
class LLFilterEditor;
class LLFilteredWearableListManager;
class LLPanelOutfitEdit : public LLPanel
{
@ -88,6 +89,7 @@ public:
void showAddWearablesPanel();
void showWearablesFilter();
void showFilteredWearablesPanel();
void saveOutfit(bool as_new = false);
void showSaveMenu();
@ -122,7 +124,9 @@ private:
LLButton* mUpBtn;
LLButton* mEditWearableBtn;
LLToggleableMenu* mSaveMenu;
LLFilteredWearableListManager* mWearableListManager;
LLLookFetchObserver* mFetchLook;
LLInventoryLookObserver* mLookObserver;
std::vector<LLLookItemType> mLookItemTypes;

View File

@ -341,6 +341,30 @@
top_pad="5"
width="300"/>
<panel
name="filtered_wearables_panel"
background_opaque="true"
background_visible="true"
layout="topleft"
follows="left|top|right|bottom"
border="false"
height="155"
left="0"
mouse_opaque="false"
width="300"
top_delta="0"
visible="false">
<wearable_items_list
name="filtered_wearables_list"
allow_select="true"
layout="topleft"
follows="all"
width="300"
height="155"
left="0"
top="0" />
</panel>
<panel
background_visible="true"
bevel_style="none"