diff options
author | Sergei Litovchuk <slitovchuk@productengine.com> | 2010-04-29 20:11:58 +0300 |
---|---|---|
committer | Sergei Litovchuk <slitovchuk@productengine.com> | 2010-04-29 20:11:58 +0300 |
commit | 20d95dd5235117593766a9e5b9ab84ee7b2c0abc (patch) | |
tree | b6f7b9a56248e7b327c3716adb5de527c483b6f4 /indra/newview | |
parent | 02d6922727bd674025759a95df15a1f764b784fd (diff) |
(EXT-6722) Create modified inventory view for "my outfits" tab in top-level appearance sidebar (tier 2)
llui:
- Added accordion tab title setter.
- Added setters for accordion tab focus changes callbacks.
newview:
- Fixed observer used for outfit items collecting. Added checking number of fetched items.
- Added outfit selection and enabled "replace outfit" and "add to outfit" commands for selected outfit.
Reviewed by Mike Antipov https://codereview.productengine.com/secondlife/r/332/
--HG--
branch : product-engine
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/llinventoryitemslist.cpp | 7 | ||||
-rw-r--r-- | indra/newview/llinventoryobserver.cpp | 69 | ||||
-rw-r--r-- | indra/newview/llinventoryobserver.h | 13 | ||||
-rw-r--r-- | indra/newview/lloutfitslist.cpp | 119 | ||||
-rw-r--r-- | indra/newview/lloutfitslist.h | 17 | ||||
-rw-r--r-- | indra/newview/llpaneloutfitsinventory.cpp | 30 |
6 files changed, 192 insertions, 63 deletions
diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp index e78ffcba62..8dfdb0788a 100644 --- a/indra/newview/llinventoryitemslist.cpp +++ b/indra/newview/llinventoryitemslist.cpp @@ -368,17 +368,18 @@ void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item) if (!item) { llwarns << "No inventory item. Couldn't create flat list item." << llendl; - llassert(!"No inventory item. Couldn't create flat list item."); + llassert(item != NULL); } LLPanelInventoryListItemBase *list_item = LLPanelInventoryListItemBase::create(item); if (!list_item) return; - if (!addItem(list_item, item->getUUID())) + bool is_item_added = addItem(list_item, item->getUUID()); + if (!is_item_added) { llwarns << "Couldn't add flat list item." << llendl; - llassert(!"Couldn't add flat list item."); + llassert(is_item_added); } } diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index e4a7b17966..86147d65e6 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -669,36 +669,87 @@ void LLInventoryCategoriesObserver::changed(U32 mask) if (!category) continue; - S32 version = category->getVersion(); - if (version != (*iter).second.mVersion) + const S32 version = category->getVersion(); + const S32 expected_num_descendents = category->getDescendentCount(); + if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) || + (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)) { - // Update category version in map. - (*iter).second.mVersion = version; - (*iter).second.mCallback(); + continue; + } + + // Check number of known descendents to find out whether it has changed. + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf((*iter).first, cats, items); + if (!cats || !items) + { + llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just skip this category. + + llassert(cats != NULL && items != NULL); + } + const S32 current_num_known_descendents = cats->count() + items->count(); + + LLCategoryData cat_data = (*iter).second; + + // If category version or descendents count has changed + // update category data in mCategoryMap and fire a callback. + if (version != cat_data.mVersion || current_num_known_descendents != cat_data.mDescendentsCount) + { + cat_data.mVersion = version; + cat_data.mDescendentsCount = current_num_known_descendents; + + cat_data.mCallback(); } } } -void LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) +bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) { S32 version; + S32 current_num_known_descendents; + bool can_be_added = true; + LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); if (category) { // Inventory category version is used to find out if some changes // to a category have been made. version = category->getVersion(); + + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat_id, cats, items); + if (!cats || !items) + { + llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean + // that the cat just doesn't have any items or subfolders). + // Unrecoverable, so just return "false" meaning that the category can't be observed. + can_be_added = false; + + llassert(cats != NULL && items != NULL); + } + current_num_known_descendents = cats->count() + items->count(); } else { // If category could not be retrieved it might mean that // inventory is unusable at the moment so the category is - // stored with VERSION_UNKNOWN and it may be updated later. + // stored with VERSION_UNKNOWN and DESCENDENT_COUNT_UNKNOWN, + // it may be updated later. version = LLViewerInventoryCategory::VERSION_UNKNOWN; + current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN; + } + + if (can_be_added) + { + mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version, current_num_known_descendents))); } - version = category->getVersion(); - mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version))); + return can_be_added; } void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id) diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index e63b67d2ad..036e6ca40d 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -276,19 +276,28 @@ public: LLInventoryCategoriesObserver() {}; virtual void changed(U32 mask); - void addCategory(const LLUUID& cat_id, callback_t cb); + /** + * Add cat_id to the list of observed categories with a + * callback fired on category being changed. + * + * @return "true" if category was added, "false" if it could + * not be found. + */ + bool addCategory(const LLUUID& cat_id, callback_t cb); void removeCategory(const LLUUID& cat_id); protected: struct LLCategoryData { - LLCategoryData(callback_t cb, S32 version) + LLCategoryData(callback_t cb, S32 version, S32 num_descendents) : mCallback(cb) , mVersion(version) + , mDescendentsCount(num_descendents) {} callback_t mCallback; S32 mVersion; + S32 mDescendentsCount; }; typedef std::map<LLUUID, LLCategoryData> category_map_t; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 1215272685..b103ec45d0 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -41,6 +41,7 @@ #include "llaccordionctrl.h" #include "llaccordionctrltab.h" +#include "llappearancemgr.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llwearableitemslist.h" @@ -51,6 +52,7 @@ LLOutfitsList::LLOutfitsList() : LLPanel() , mAccordion(NULL) , mListCommands(NULL) + , mSelectedList(NULL) { mCategoriesObserver = new LLInventoryCategoriesObserver(); gInventory.addObserver(mCategoriesObserver); @@ -135,30 +137,37 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) { const LLUUID cat_id = (*iter); LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); - if (!cat) - continue; + if (!cat) continue; std::string name = cat->getName(); static LLXMLNodePtr accordionXmlNode = getAccordionTabXMLNode(); - - accordionXmlNode->setAttributeString("name", name); - accordionXmlNode->setAttributeString("title", name); LLAccordionCtrlTab* tab = LLUICtrlFactory::defaultBuilder<LLAccordionCtrlTab>(accordionXmlNode, NULL, NULL); + tab->setName(name); + tab->setTitle(name); + // *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated. tab->setDisplayChildren(false); mAccordion->addCollapsibleCtrl(tab); + // Start observing the new outfit category. + LLWearableItemsList* list = tab->getChild<LLWearableItemsList>("wearable_items_list"); + if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id))) + { + // Remove accordion tab if category could not be added to observer. + mAccordion->removeCollapsibleCtrl(tab); + continue; + } + // Map the new tab with outfit category UUID. mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab)); - // Start observing the new outfit category. - LLWearableItemsList* list = tab->getChild<LLWearableItemsList>("wearable_items_list"); - mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)); + // Setting tab focus callback to monitor currently selected outfit. + tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id)); - // Setting drop down callback to monitor currently selected outfit. - tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::onTabExpandedCollapsed, this, list)); + // Setting list commit callback to monitor currently selected wearable item. + list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1)); // Fetch the new outfit contents. cat->fetch(); @@ -178,10 +187,18 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) // 1. Remove outfit accordion tab from accordion. mAccordion->removeCollapsibleCtrl(outfits_iter->second); + const LLUUID& outfit_id = outfits_iter->first; + // 2. Remove outfit category from observer to stop monitoring its changes. - mCategoriesObserver->removeCategory(outfits_iter->first); + mCategoriesObserver->removeCategory(outfit_id); - // 3. Remove category UUID to accordion tab mapping. + // 3. Reset selection if selected outfit is being removed. + if (mSelectedOutfitUUID == outfit_id) + { + changeOutfitSelection(NULL, LLUUID()); + } + + // 4. Remove category UUID to accordion tab mapping. mOutfitsMap.erase(outfits_iter); } } @@ -199,40 +216,30 @@ void LLOutfitsList::refreshList(const LLUUID& category_id) mAccordion->arrange(); } -void LLOutfitsList::updateOutfitTab(const LLUUID& category_id) +void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl) { - outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id); - if (outfits_iter != mOutfitsMap.end()) - { - LLViewerInventoryCategory *cat = gInventory.getCategory(category_id); - if (!cat) - return; + LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl); + if (!list) return; - std::string name = cat->getName(); + LLViewerInventoryItem *item = gInventory.getItem(list->getSelectedUUID()); + if (!item) return; - // 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); - } - } + changeOutfitSelection(list, item->getParentUUID()); } -void LLOutfitsList::onTabExpandedCollapsed(LLWearableItemsList* list) +void LLOutfitsList::performAction(std::string action) { - if (!list) - return; + LLViewerInventoryCategory* cat = gInventory.getCategory(mSelectedOutfitUUID); + if (!cat) return; - // TODO: Add outfit selection handling. + if ("replaceoutfit" == action) + { + LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, FALSE ); + } + else if ("addtooutfit" == action) + { + LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, TRUE ); + } } void LLOutfitsList::setFilterSubString(const std::string& string) @@ -240,7 +247,6 @@ void LLOutfitsList::setFilterSubString(const std::string& string) mFilterSubString = string; } - ////////////////////////////////////////////////////////////////////////// // Private methods ////////////////////////////////////////////////////////////////////////// @@ -283,4 +289,37 @@ void LLOutfitsList::computeDifference( LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved); } +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); + tab->setTitle(name); + } + } +} + +void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id) +{ + // Reset selection in previously selected tab + // if a new one is selected. + if (list && mSelectedList && mSelectedList != list) + { + mSelectedList->resetSelection(); + } + + mSelectedList = list; + mSelectedOutfitUUID = category_id; +} + // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 2d103ea356..d86cf5a703 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -65,10 +65,9 @@ public: void refreshList(const LLUUID& category_id); - // Update tab displaying outfit identified by category_id. - void updateOutfitTab(const LLUUID& category_id); + void onSelectionChange(LLUICtrl* ctrl); - void onTabExpandedCollapsed(LLWearableItemsList* list); + void performAction(std::string action); void setFilterSubString(const std::string& string); @@ -85,12 +84,24 @@ private: */ void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved); + /** + * Updates tab displaying outfit identified by category_id. + */ + void updateOutfitTab(const LLUUID& category_id); + + /** + * Resets previous selection and stores newly selected list and outfit id. + */ + void changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id); LLInventoryCategoriesObserver* mCategoriesObserver; LLAccordionCtrl* mAccordion; LLPanel* mListCommands; + LLWearableItemsList* mSelectedList; + LLUUID mSelectedOutfitUUID; + std::string mFilterSubString; typedef std::map<LLUUID, LLAccordionCtrlTab*> outfits_map_t; diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 789e85b46f..80964938f5 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -188,19 +188,37 @@ void LLPanelOutfitsInventory::onSearchEdit(const std::string& string) void LLPanelOutfitsInventory::onWearButtonClick() { - LLFolderViewEventListener* listenerp = getCorrectListenerForAction(); - if (listenerp) + // TODO: Remove if/else, add common interface + // for "My Outfits" and "Wearing" tabs. + if (!isCOFPanelActive()) + { + mMyOutfitsPanel->performAction("replaceoutfit"); + } + else { - listenerp->performAction(NULL, "replaceoutfit"); + LLFolderViewEventListener* listenerp = getCorrectListenerForAction(); + if (listenerp) + { + listenerp->performAction(NULL, "replaceoutfit"); + } } } void LLPanelOutfitsInventory::onAdd() { - LLFolderViewEventListener* listenerp = getCorrectListenerForAction(); - if (listenerp) + // TODO: Remove if/else, add common interface + // for "My Outfits" and "Wearing" tabs. + if (!isCOFPanelActive()) + { + mMyOutfitsPanel->performAction("addtooutfit"); + } + else { - listenerp->performAction(NULL, "addtooutfit"); + LLFolderViewEventListener* listenerp = getCorrectListenerForAction(); + if (listenerp) + { + listenerp->performAction(NULL, "addtooutfit"); + } } } |