diff options
Diffstat (limited to 'indra/newview/lloutfitslist.cpp')
-rw-r--r-- | indra/newview/lloutfitslist.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp new file mode 100644 index 0000000000..ad42d80467 --- /dev/null +++ b/indra/newview/lloutfitslist.cpp @@ -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 |