summaryrefslogtreecommitdiff
path: root/indra/newview/lloutfitslist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/lloutfitslist.cpp')
-rw-r--r--indra/newview/lloutfitslist.cpp265
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