Implemented by SL EXT-6722(normal task) - Create modified inventory view for "my outfits" tab in top-level appearance sidebar (tier 1)

llui:
- Setting container panel for accordion tab control to dynamically add tabs to accordions.
- Added method to dynamically remove accordion tabs.
- Added LLIconCtrl image setter.

newview:
- Class LLOutfitsList - a list of agents's outfits from "My Outfits" inventory category which represents each outfit by an accordion tab with a list of items inside it.
- Class LLWearableItemsList - a list of wearable items used in each accordion tab of "My Outfits" tab.
- Class LLInventoryItemsList - a base class for LLWearableItemsList that represents inventory items by panels in LLFlatListView.
- Class LLPanelInventoryItem - inventory item representation for a flat list. Item icon is set according to item type.
- Class LLInventoryCategoriesObserver - an observer used in LLOutfitsList for monitoring changes to "My Outfits" inventory category and updating outfits accordion tabs and list of items for each outfit.

Known issues:
- Only first outfit tab is displayed in "My Outfits" until this tab is expanded.
- Bottom bar buttons and filter field not functioning for "My Outfits" tab since LLOutfitsList still doesn't support selection, filtering and sorting.
- "My Outfits" and "Wearing" tabs of "Appearance" side panel might need a common interface to use LLOutfitsList and LLinventoryPanel as tabs in LLPanelOutfitsInventory or "Wearing" tab should be replaces with LLOutfitsList class object i.e. a flat list.

On review - https://codereview.productengine.com/secondlife/r/285/

--HG--
branch : product-engine
meow-7.2.2
Dmitry Zaporozhan 2010-04-21 15:44:24 +03:00
parent 6b722079c4
commit 2ce7556e53
20 changed files with 989 additions and 87 deletions

View File

@ -332,11 +332,31 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view)
if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) == getChildList()->end())
addChild(accordion_tab);
mAccordionTabs.push_back(accordion_tab);
accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) );
}
void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view)
{
LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view);
if(!accordion_tab)
return;
if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) != getChildList()->end())
removeChild(accordion_tab);
for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin();
iter != mAccordionTabs.end(); ++iter)
{
if (accordion_tab == (*iter))
{
mAccordionTabs.erase(iter);
break;
}
}
}
void LLAccordionCtrl::arrangeSinge()
{
S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter

View File

@ -92,6 +92,7 @@ public:
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
void addCollapsibleCtrl(LLView* view);
void removeCollapsibleCtrl(LLView* view);
void arrange();

View File

@ -425,6 +425,9 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
setDisplayChildren(getDisplayChildren());
}
if (!mContainerPanel)
mContainerPanel = findContainerView();
return res;
}

View File

@ -73,6 +73,7 @@ public:
std::string getImageName() const;
void setColor(const LLColor4& color) { mColor = color; }
void setImage(LLPointer<LLUIImage> image) { mImagep = image; }
private:
void setIconImageDrawSize() ;

View File

@ -252,6 +252,7 @@ set(viewer_SOURCE_FILES
llinventoryclipboard.cpp
llinventoryfilter.cpp
llinventoryfunctions.cpp
llinventoryitemslist.cpp
llinventorymodel.cpp
llinventorymodelbackgroundfetch.cpp
llinventoryobserver.cpp
@ -295,6 +296,7 @@ set(viewer_SOURCE_FILES
llnotificationofferhandler.cpp
llnotificationscripthandler.cpp
llnotificationtiphandler.cpp
lloutfitslist.cpp
lloutputmonitorctrl.cpp
llpanelavatar.cpp
llpanelavatartag.cpp
@ -528,6 +530,7 @@ set(viewer_SOURCE_FILES
llwaterparamset.cpp
llwearable.cpp
llwearabledictionary.cpp
llwearableitemslist.cpp
llwearablelist.cpp
llweb.cpp
llwind.cpp
@ -756,6 +759,7 @@ set(viewer_HEADER_FILES
llinventoryclipboard.h
llinventoryfilter.h
llinventoryfunctions.h
llinventoryitemslist.h
llinventorymodel.h
llinventorymodelbackgroundfetch.h
llinventoryobserver.h
@ -795,6 +799,7 @@ set(viewer_HEADER_FILES
llnetmap.h
llnotificationhandler.h
llnotificationmanager.h
lloutfitslist.h
lloutputmonitorctrl.h
llpanelavatar.h
llpanelavatartag.h
@ -1030,6 +1035,7 @@ set(viewer_HEADER_FILES
llwaterparamset.h
llwearable.h
llwearabledictionary.h
llwearableitemslist.h
llwearablelist.h
llweb.h
llwind.h

View File

@ -1338,7 +1338,8 @@ public:
LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key);
LLPanelOutfitsInventory *outfit_panel =
dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory"));
if (outfit_panel)
// TODO: add handling "My Outfits" tab.
if (outfit_panel && outfit_panel->isCOFPanelActive())
{
outfit_panel->getRootFolder()->clearSelection();
outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE);

View File

@ -0,0 +1,141 @@
/**
* @file llinventoryitemslist.cpp
* @brief A list of inventory items represented by LLFlatListView.
*
* $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 "llinventoryitemslist.h"
#include "lliconctrl.h"
#include "llinventoryfunctions.h"
#include "lltextutil.h"
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
LLPanelInventoryItem::LLPanelInventoryItem(LLAssetType::EType asset_type,
LLInventoryType::EType inventory_type,
U32 wearable_type,
const std::string &item_name,
const std::string &hl)
: LLPanel()
,mItemName(item_name)
,mHighlightedText(hl)
,mIcon(NULL)
,mTitle(NULL)
{
mItemIcon = get_item_icon(asset_type, inventory_type, wearable_type, FALSE);
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory_item.xml");
}
LLPanelInventoryItem::~LLPanelInventoryItem()
{}
//virtual
BOOL LLPanelInventoryItem::postBuild()
{
mIcon = getChild<LLIconCtrl>("item_icon");
mTitle = getChild<LLTextBox>("item_name");
updateItem();
return TRUE;
}
//virtual
void LLPanelInventoryItem::setValue(const LLSD& value)
{
if (!value.isMap()) return;
if (!value.has("selected")) return;
childSetVisible("selected_icon", value["selected"]);
}
void LLPanelInventoryItem::updateItem()
{
if (mItemIcon.notNull())
mIcon->setImage(mItemIcon);
LLTextUtil::textboxSetHighlightedVal(
mTitle,
LLStyle::Params(),
mItemName,
mHighlightedText);
}
void LLPanelInventoryItem::onMouseEnter(S32 x, S32 y, MASK mask)
{
childSetVisible("hovered_icon", true);
LLPanel::onMouseEnter(x, y, mask);
}
void LLPanelInventoryItem::onMouseLeave(S32 x, S32 y, MASK mask)
{
childSetVisible("hovered_icon", false);
LLPanel::onMouseLeave(x, y, mask);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
LLInventoryItemsList::LLInventoryItemsList(const LLFlatListView::Params& p)
: LLFlatListView(p)
{}
// virtual
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++)
{
LLViewerInventoryItem *item = (*iter);
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;
}
}
}

View File

@ -0,0 +1,88 @@
/**
* @file llinventoryitemslist.h
* @brief A list of inventory items represented by LLFlatListView.
*
* $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_LLINVENTORYITEMSLIST_H
#define LL_LLINVENTORYITEMSLIST_H
#include "llpanel.h"
#include "llassettype.h"
#include "llinventorytype.h"
// newview
#include "llflatlistview.h"
#include "llinventorymodel.h"
class LLIconCtrl;
class LLTextBox;
class LLPanelInventoryItem : public LLPanel
{
public:
LLPanelInventoryItem(LLAssetType::EType asset_type,
LLInventoryType::EType inventory_type,
U32 wearable_type,
const std::string &item_name,
const std::string &hl);
virtual ~LLPanelInventoryItem();
/*virtual*/ BOOL postBuild();
/*virtual*/ void setValue(const LLSD& value);
void updateItem();
void onMouseEnter(S32 x, S32 y, MASK mask);
void onMouseLeave(S32 x, S32 y, MASK mask);
private:
LLIconCtrl* mIcon;
LLTextBox* mTitle;
LLUIImagePtr mItemIcon;
std::string mItemName;
std::string mHighlightedText;
};
class LLInventoryItemsList : public LLFlatListView
{
public:
virtual ~LLInventoryItemsList();
void refreshList(const LLInventoryModel::item_array_t item_array);
protected:
friend class LLUICtrlFactory;
LLInventoryItemsList(const LLFlatListView::Params& p);
};
#endif //LL_LLINVENTORYITEMSLIST_H

View File

@ -647,3 +647,35 @@ void LLInventoryTransactionObserver::changed(U32 mask)
}
}
}
void LLInventoryCategoriesObserver::changed(U32 mask)
{
if (!mCategoryMap.size())
return;
for (category_map_t::iterator iter = mCategoryMap.begin();
iter != mCategoryMap.end();
iter++)
{
// Inventory category version is used to find out if some changes
// to a category have been made.
S32 version = gInventory.getCategory((*iter).first)->getVersion();
if (version != (*iter).second.mVersion)
{
// Update category version in map.
(*iter).second.mVersion = version;
(*iter).second.mCallback();
}
}
}
void LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb)
{
S32 version = gInventory.getCategory(cat_id)->getVersion();
mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version)));
}
void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)
{
mCategoryMap.erase(mCategoryMap.find(cat_id));
}

View File

@ -262,5 +262,40 @@ protected:
uuid_vec_t mIncomplete;
};
#endif // LL_LLINVENTORYOBSERVERS_H
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryCategoriesObserver
//
// This class is used for monitoring a list of inventory categories
// and firing a callback when there are changes in any of them.
// Categories are identified by their UUIDs.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLInventoryCategoriesObserver : public LLInventoryObserver
{
public:
typedef boost::function<void()> callback_t;
LLInventoryCategoriesObserver() {};
virtual void changed(U32 mask);
void addCategory(const LLUUID& cat_id, callback_t cb);
void removeCategory(const LLUUID& cat_id);
protected:
struct LLCategoryData
{
LLCategoryData(callback_t cb, S32 version)
: mCallback(cb)
, mVersion(version)
{}
callback_t mCallback;
S32 mVersion;
};
typedef std::map<LLUUID, LLCategoryData> category_map_t;
typedef category_map_t::value_type category_map_value_t;
category_map_t mCategoryMap;
};
#endif // LL_LLINVENTORYOBSERVERS_H

View File

@ -0,0 +1,265 @@
/**
* @file lloutfitslist.cpp
* @brief List of agent's outfits for My Appearance side panel.
*
* $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 "lloutfitslist.h"
#include "llaccordionctrl.h"
#include "llaccordionctrltab.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llwearableitemslist.h"
static LLRegisterPanelClassWrapper<LLOutfitsList> t_outfits_list("outfits_list");
LLOutfitsList::LLOutfitsList()
: LLPanel()
, mAccordion(NULL)
, mListCommands(NULL)
{}
LLOutfitsList::~LLOutfitsList()
{
if (gInventory.containsObserver(mCategoriesObserver))
{
gInventory.removeObserver(mCategoriesObserver);
delete mCategoriesObserver;
}
if (gInventory.containsObserver(this))
{
gInventory.removeObserver(this);
}
}
BOOL LLOutfitsList::postBuild()
{
mAccordion = getChild<LLAccordionCtrl>("outfits_accordion");
mCategoriesObserver = new LLInventoryCategoriesObserver();
gInventory.addObserver(mCategoriesObserver);
gInventory.addObserver(this);
return TRUE;
}
//virtual
void LLOutfitsList::changed(U32 mask)
{
if (!gInventory.isInventoryUsable())
return;
// Start observing changes in "My Outfits" category.
const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
mCategoriesObserver->addCategory(outfits,
boost::bind(&LLOutfitsList::refreshList, this, outfits));
LLViewerInventoryCategory* category = gInventory.getCategory(outfits);
if (!category)
return;
// Fetch "My Outfits" contents and refresh the list to display
// initially fetched items. If not all items are fetched now
// the observer will refresh the list as soon as the new items
// arrive.
category->fetch();
refreshList(outfits);
// This observer is used to start the initial outfits fetch
// when inventory becomes usable. It is no longer needed because
// "My Outfits" category is now observed by
// LLInventoryCategoriesObserver.
gInventory.removeObserver(this);
}
void LLOutfitsList::refreshList(const LLUUID& category_id)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
// Collect all sub-categories of a given category.
LLIsType is_category(LLAssetType::AT_CATEGORY);
gInventory.collectDescendentsIf(
category_id,
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH,
is_category);
uuid_vec_t vnew;
// Creating a vector of newly collected sub-categories UUIDs.
for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();
iter != cat_array.end();
iter++)
{
vnew.push_back((*iter)->getUUID());
}
uuid_vec_t vcur;
// Creating a vector of currently displayed sub-categories UUIDs.
for (outfits_map_t::const_iterator iter = mOutfitsMap.begin();
iter != mOutfitsMap.end();
iter++)
{
vcur.push_back((*iter).first);
}
// Sorting both vectors to compare.
std::sort(vcur.begin(), vcur.end());
std::sort(vnew.begin(), vnew.end());
uuid_vec_t vadded;
uuid_vec_t vremoved;
uuid_vec_t::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());
// Handle added tabs.
for (uuid_vec_t::const_iterator iter = vadded.begin();
iter != vadded.end();
iter++)
{
const LLUUID cat_id = (*iter);
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
if (!cat)
continue;
std::string name = cat->getName();
// *TODO: create accordion tabs and lists from XML.
LLAccordionCtrlTab::Params params;
params.name(name);
params.title(name);
params.rect(LLRect(0, 0, 315, 20));
params.display_children(false);
LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(params);
mAccordion->addCollapsibleCtrl(tab);
LLFlatListView::Params list_params;
LLWearableItemsList* list = LLUICtrlFactory::create<LLWearableItemsList>(list_params);
tab->addChild(list, 0);
tab->setDisplayChildren(false);
// Map the new tab with outfit category UUID.
mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));
// Start observing the new outfit category.
mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id));
// Fetch the new outfit contents.
cat->fetch();
// Refresh the list of outfit items after fetch().
// Further list updates will be triggered by the category observer.
list->updateList(cat_id);
}
// Handle removed tabs.
for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); iter++)
{
outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter));
if (outfits_iter != mOutfitsMap.end())
{
// An outfit is removed from the list. Do the following:
// 1. Remove outfit accordion tab from accordion.
mAccordion->removeCollapsibleCtrl(outfits_iter->second);
// 2. Remove outfit category from observer to stop monitoring its changes.
mCategoriesObserver->removeCategory(outfits_iter->first);
// 3. Remove category UUID to accordion tab mapping.
mOutfitsMap.erase(outfits_iter);
}
}
// Get changed items from inventory model and update outfit tabs
// which might have been renamed.
const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
items_iter != changed_items.end();
++items_iter)
{
updateOutfitTab(*items_iter);
}
mAccordion->arrange();
}
void LLOutfitsList::updateOutfitTab(const LLUUID& category_id)
{
outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id);
if (outfits_iter != mOutfitsMap.end())
{
LLViewerInventoryCategory *cat = gInventory.getCategory(category_id);
if (!cat)
return;
std::string name = cat->getName();
// Update tab name with the new category name.
LLAccordionCtrlTab* tab = outfits_iter->second;
if (tab)
{
tab->setName(name);
}
// Update tab title with the new category name using textbox
// in accordion tab header.
LLTextBox* tab_title = tab->findChild<LLTextBox>("dd_textbox");
if (tab_title)
{
tab_title->setText(name);
}
}
}
void LLOutfitsList::setFilterSubString(const std::string& string)
{
mFilterSubString = string;
}
// EOF

View File

@ -0,0 +1,74 @@
/**
* @file lloutfitslist.h
* @brief List of agent's outfits for My Appearance side panel.
*
* $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_LLOUTFITSLIST_H
#define LL_LLOUTFITSLIST_H
#include "llpanel.h"
// newview
#include "llinventoryobserver.h"
class LLAccordionCtrl;
class LLAccordionCtrlTab;
class LLWearableItemsList;
class LLOutfitsList : public LLPanel, public LLInventoryObserver
{
public:
LLOutfitsList();
virtual ~LLOutfitsList();
/*virtual*/ BOOL postBuild();
/*virtual*/ void changed(U32 mask);
void refreshList(const LLUUID& category_id);
// Update tab displaying outfit identified by category_id.
void updateOutfitTab(const LLUUID& category_id);
void setFilterSubString(const std::string& string);
private:
LLInventoryCategoriesObserver* mCategoriesObserver;
LLAccordionCtrl* mAccordion;
LLPanel* mListCommands;
std::string mFilterSubString;
typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t;
typedef outfits_map_t::value_type outfits_map_value_t;
outfits_map_t mOutfitsMap;
};
#endif //LL_LLOUTFITSLIST_H

View File

@ -49,6 +49,7 @@
#include "lllineeditor.h"
#include "llmodaldialog.h"
#include "llnotificationsutil.h"
#include "lloutfitslist.h"
#include "llsidepanelappearance.h"
#include "llsidetray.h"
#include "lltabcontainer.h"
@ -71,7 +72,8 @@ bool LLPanelOutfitsInventory::sShowDebugEditor = false;
LLPanelOutfitsInventory::LLPanelOutfitsInventory() :
mActivePanel(NULL),
mMyOutfitsPanel(NULL),
mCurrentOutfitPanel(NULL),
mParent(NULL)
{
mSavedFolderState = new LLSaveFolderState();
@ -145,9 +147,17 @@ void LLPanelOutfitsInventory::setParent(LLSidepanelAppearance* parent)
void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
{
mFilterSubString = string;
// TODO: add handling "My Outfits" tab.
if (!isCOFPanelActive())
{
mMyOutfitsPanel->setFilterSubString(string);
return;
}
if (string == "")
{
mActivePanel->setFilterSubString(LLStringUtil::null);
getActivePanel()->setFilterSubString(LLStringUtil::null);
// re-open folders that were initially open
mSavedFolderState->setApply(TRUE);
@ -159,7 +169,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
LLInventoryModelBackgroundFetch::instance().start();
if (mActivePanel->getFilterSubString().empty() && string.empty())
if (getActivePanel()->getFilterSubString().empty() && string.empty())
{
// current filter and new filter empty, do nothing
return;
@ -173,7 +183,7 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string)
}
// set new filter string
mActivePanel->setFilterSubString(string);
getActivePanel()->setFilterSubString(string);
}
void LLPanelOutfitsInventory::onWearButtonClick()
@ -267,6 +277,11 @@ void LLPanelOutfitsInventory::onSave()
void LLPanelOutfitsInventory::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
updateVerbs();
// TODO: add handling "My Outfits" tab.
if (!isCOFPanelActive())
return;
if (getRootFolder()->needsAutoRename() && items.size())
{
getRootFolder()->startRenamingSelectedItem();
@ -284,6 +299,10 @@ void LLPanelOutfitsInventory::showEditOutfitPanel()
LLFolderViewEventListener *LLPanelOutfitsInventory::getCorrectListenerForAction()
{
// TODO: add handling "My Outfits" tab.
if (!isCOFPanelActive())
return NULL;
LLFolderViewItem* current_item = getRootFolder()->getCurSelectedItem();
if (!current_item)
return NULL;
@ -311,7 +330,7 @@ bool LLPanelOutfitsInventory::getIsCorrectType(const LLFolderViewEventListener *
LLFolderView *LLPanelOutfitsInventory::getRootFolder()
{
return mActivePanel->getRootFolder();
return getActivePanel()->getRootFolder();
}
//static
@ -393,7 +412,11 @@ void LLPanelOutfitsInventory::onTrashButtonClick()
void LLPanelOutfitsInventory::onClipboardAction(const LLSD& userdata)
{
std::string command_name = userdata.asString();
getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name);
// TODO: add handling "My Outfits" tab.
if (isCOFPanelActive())
{
getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name);
}
updateListCommands();
updateVerbs();
}
@ -447,21 +470,26 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
if (command_name == "delete" || command_name == "remove")
{
BOOL can_delete = FALSE;
LLFolderView* root = getActivePanel()->getRootFolder();
if (root)
// TODO: add handling "My Outfits" tab.
if (isCOFPanelActive())
{
std::set<LLUUID> selection_set;
root->getSelectionList(selection_set);
can_delete = (selection_set.size() > 0);
for (std::set<LLUUID>::iterator iter = selection_set.begin();
iter != selection_set.end();
++iter)
LLFolderView* root = getActivePanel()->getRootFolder();
if (root)
{
const LLUUID &item_id = (*iter);
LLFolderViewItem *item = root->getItemByID(item_id);
can_delete &= item->getListener()->isItemRemovable();
std::set<LLUUID> selection_set;
root->getSelectionList(selection_set);
can_delete = (selection_set.size() > 0);
for (std::set<LLUUID>::iterator iter = selection_set.begin();
iter != selection_set.end();
++iter)
{
const LLUUID &item_id = (*iter);
LLFolderViewItem *item = root->getItemByID(item_id);
can_delete &= item->getListener()->isItemRemovable();
}
return can_delete;
}
return can_delete;
}
return FALSE;
}
@ -517,12 +545,17 @@ BOOL LLPanelOutfitsInventory::isActionEnabled(const LLSD& userdata)
bool LLPanelOutfitsInventory::hasItemsSelected()
{
bool has_items_selected = false;
LLFolderView* root = getActivePanel()->getRootFolder();
if (root)
// TODO: add handling "My Outfits" tab.
if (isCOFPanelActive())
{
std::set<LLUUID> selection_set;
root->getSelectionList(selection_set);
has_items_selected = (selection_set.size() > 0);
LLFolderView* root = getActivePanel()->getRootFolder();
if (root)
{
std::set<LLUUID> selection_set;
root->getSelectionList(selection_set);
has_items_selected = (selection_set.size() > 0);
}
}
return has_items_selected;
}
@ -549,74 +582,58 @@ bool LLPanelOutfitsInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropTy
void LLPanelOutfitsInventory::initTabPanels()
{
LLInventoryPanel *cof_panel = getChild<LLInventoryPanel>(COF_TAB_NAME);
cof_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
mTabPanels.push_back(cof_panel);
mCurrentOutfitPanel = getChild<LLInventoryPanel>(COF_TAB_NAME);
mCurrentOutfitPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
mCurrentOutfitPanel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, mCurrentOutfitPanel, _1, _2));
LLInventoryPanel *myoutfits_panel = getChild<LLInventoryPanel>(OUTFITS_TAB_NAME);
myoutfits_panel->setFilterTypes(1LL << LLFolderType::FT_OUTFIT, LLInventoryFilter::FILTERTYPE_CATEGORY);
myoutfits_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
mTabPanels.push_back(myoutfits_panel);
for (tabpanels_vec_t::iterator iter = mTabPanels.begin();
iter != mTabPanels.end();
++iter)
{
LLInventoryPanel *panel = (*iter);
panel->setSelectCallback(boost::bind(&LLPanelOutfitsInventory::onTabSelectionChange, this, panel, _1, _2));
}
mMyOutfitsPanel = getChild<LLOutfitsList>(OUTFITS_TAB_NAME);
mAppearanceTabs = getChild<LLTabContainer>("appearance_tabs");
mAppearanceTabs->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::onTabChange, this));
mActivePanel = (LLInventoryPanel*)mAppearanceTabs->getCurrentPanel();
}
void LLPanelOutfitsInventory::onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action)
{
if (user_action && items.size() > 0)
{
for (tabpanels_vec_t::iterator iter = mTabPanels.begin();
iter != mTabPanels.end();
++iter)
// TODO: add handling "My Outfits" tab.
if (isCOFPanelActive())
{
LLInventoryPanel *panel = (*iter);
if (panel == tab_panel)
{
mActivePanel = panel;
}
else
{
panel->getRootFolder()->clearSelection();
}
onSelectionChange(items, user_action);
}
else
{
mCurrentOutfitPanel->getRootFolder()->clearSelection();
}
}
onSelectionChange(items, user_action);
}
void LLPanelOutfitsInventory::onTabChange()
{
mActivePanel = (LLInventoryPanel*)childGetVisibleTab("appearance_tabs");
if (!mActivePanel)
// TODO: add handling "My Outfits" tab.
if (isCOFPanelActive())
{
return;
mCurrentOutfitPanel->setFilterSubString(mFilterSubString);
}
mActivePanel->setFilterSubString(mFilterSubString);
else
{
mMyOutfitsPanel->setFilterSubString(mFilterSubString);
}
updateVerbs();
}
BOOL LLPanelOutfitsInventory::isTabPanel(LLInventoryPanel *panel) const
{
for(tabpanels_vec_t::const_iterator it = mTabPanels.begin();
it != mTabPanels.end();
++it)
// TODO: add handling "My Outfits" tab.
if (mCurrentOutfitPanel == panel)
{
if (*it == panel)
return TRUE;
return TRUE;
}
return FALSE;
}
BOOL LLPanelOutfitsInventory::isCOFPanelActive() const
{
return (getActivePanel()->getName() == COF_TAB_NAME);
return (childGetVisibleTab("appearance_tabs")->getName() == COF_TAB_NAME);
}

View File

@ -40,6 +40,7 @@ class LLFolderView;
class LLFolderViewItem;
class LLFolderViewEventListener;
class LLInventoryPanel;
class LLOutfitsList;
class LLSaveFolderState;
class LLButton;
class LLMenuGL;
@ -88,20 +89,21 @@ private:
public:
//////////////////////////////////////////////////////////////////////////////////
// tab panels
LLInventoryPanel* getActivePanel() { return mActivePanel; }
const LLInventoryPanel* getActivePanel() const { return mActivePanel; }
// TODO: change getActivePanel() to return the active tab instead of returning
// a pointer to "Wearing" inventory panel.
LLInventoryPanel* getActivePanel() { return mCurrentOutfitPanel; }
BOOL isTabPanel(LLInventoryPanel *panel) const;
BOOL isCOFPanelActive() const;
protected:
void initTabPanels();
void onTabSelectionChange(LLInventoryPanel* tab_panel, const std::deque<LLFolderViewItem*> &items, BOOL user_action);
void onTabChange();
BOOL isCOFPanelActive() const;
private:
LLInventoryPanel* mActivePanel;
typedef std::vector<LLInventoryPanel *> tabpanels_vec_t;
tabpanels_vec_t mTabPanels;
LLOutfitsList* mMyOutfitsPanel;
LLInventoryPanel* mCurrentOutfitPanel;
// tab panels //
////////////////////////////////////////////////////////////////////////////////

View File

@ -329,8 +329,8 @@ void LLSidepanelAppearance::updateVerbs()
if (mPanelOutfitsInventory && !is_look_info_visible)
{
const bool is_correct_type = (mPanelOutfitsInventory->getCorrectListenerForAction() != NULL);
mEditBtn->setEnabled(is_correct_type);
// const bool is_correct_type = (mPanelOutfitsInventory->getCorrectListenerForAction() != NULL);
// mEditBtn->setEnabled(is_correct_type);
}
else
{

View File

@ -0,0 +1,88 @@
/**
* @file llwearableitemslist.cpp
* @brief A flat list of wearable items.
*
* $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 "llwearableitemslist.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
class LLFindOutfitItems : public LLInventoryCollectFunctor
{
public:
LLFindOutfitItems() {}
virtual ~LLFindOutfitItems() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
};
bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
if(item)
{
if((item->getType() == LLAssetType::AT_CLOTHING)
|| (item->getType() == LLAssetType::AT_BODYPART)
|| (item->getType() == LLAssetType::AT_OBJECT))
{
return TRUE;
}
}
return FALSE;
}
static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_items_list");
LLWearableItemsList::LLWearableItemsList(const LLFlatListView::Params& p)
: LLInventoryItemsList(p)
{}
// virtual
LLWearableItemsList::~LLWearableItemsList()
{}
void LLWearableItemsList::updateList(const LLUUID& category_id)
{
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
LLFindOutfitItems collector = LLFindOutfitItems();
// collectDescendentsIf takes non-const reference:
gInventory.collectDescendentsIf(
category_id,
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH,
collector);
refreshList(item_array);
}

View File

@ -0,0 +1,56 @@
/**
* @file llwearableitemslist.h
* @brief A flat list of wearable items.
*
* $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_LLWEARABLEITEMSLIST_H
#define LL_LLWEARABLEITEMSLIST_H
#include "llpanel.h"
#include "llassettype.h"
#include "llinventorytype.h"
// newview
#include "llinventoryitemslist.h"
class LLWearableItemsList : public LLInventoryItemsList
{
public:
virtual ~LLWearableItemsList();
void updateList(const LLUUID& category_id);
protected:
friend class LLUICtrlFactory;
LLWearableItemsList(const LLFlatListView::Params& p);
};
#endif //LL_LLWEARABLEITEMSLIST_H

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
follows="top|right|left"
height="20"
layout="topleft"
left="0"
name="inventory_item"
top="0"
width="380">
<icon
follows="top|right|left"
height="20"
image_name="ListItem_Over"
layout="topleft"
left="0"
name="hovered_icon"
top="0"
visible="false"
width="380" />
<icon
height="20"
follows="top|right|left"
image_name="ListItem_Select"
layout="topleft"
left="0"
name="selected_icon"
top="0"
visible="false"
width="380" />
<icon
height="16"
follows="top|left"
image_name="Inv_Object"
layout="topleft"
left="0"
name="item_icon"
top="0"
width="16" />
<text
follows="left|right"
height="20"
layout="topleft"
left_pad="5"
allow_html="false"
use_ellipses="true"
name="item_name"
text_color="white"
top="4"
value="..."
width="359" />
</panel>

View File

@ -23,20 +23,16 @@
tab_position="top"
halign="center"
width="312">
<inventory_panel
background_visible="true"
background_opaque="true"
label="MY OUTFITS"
help_topic="my_outfits_tab"
allow_multi_select="true"
follows="all"
border="false"
left="0"
top="0"
width="315"
mouse_opaque="true"
<panel
class="outfits_list"
filename="panel_outfits_list.xml"
height="490"
name="outfitslist_tab"
start_folder="My Outfits" />
background_visible="true"
follows="all"
label="MY OUTFITS"
layout="topleft"
width="315" />
<inventory_panel
follows="all"
background_visible="true"

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
background_visible="true"
bg_alpha_color="DkGray"
border="false"
follows="all"
height="400"
name="Outfits"
layout="topleft"
left="0"
top="0"
width="313">
<accordion
background_visible="true"
bg_alpha_color="DkGray2"
bg_opaque_color="DkGray2"
follows="all"
height="400"
layout="topleft"
left="3"
name="outfits_accordion"
top="0"
width="307">
</accordion>
</panel>