summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorSergei Litovchuk <slitovchuk@productengine.com>2010-04-29 20:11:58 +0300
committerSergei Litovchuk <slitovchuk@productengine.com>2010-04-29 20:11:58 +0300
commit20d95dd5235117593766a9e5b9ab84ee7b2c0abc (patch)
treeb6f7b9a56248e7b327c3716adb5de527c483b6f4 /indra
parent02d6922727bd674025759a95df15a1f764b784fd (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')
-rw-r--r--indra/llui/llaccordionctrltab.cpp28
-rw-r--r--indra/llui/llaccordionctrltab.h6
-rw-r--r--indra/newview/llinventoryitemslist.cpp7
-rw-r--r--indra/newview/llinventoryobserver.cpp69
-rw-r--r--indra/newview/llinventoryobserver.h13
-rw-r--r--indra/newview/lloutfitslist.cpp119
-rw-r--r--indra/newview/lloutfitslist.h17
-rw-r--r--indra/newview/llpaneloutfitsinventory.cpp30
8 files changed, 226 insertions, 63 deletions
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index 3c706ce90e..596da782ce 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -436,6 +436,34 @@ void LLAccordionCtrlTab::setAccordionView(LLView* panel)
addChild(panel,0);
}
+void LLAccordionCtrlTab::setTitle(const std::string& title)
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ header->setTitle(title);
+ }
+}
+
+boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ return header->setFocusReceivedCallback(cb);
+ }
+ return boost::signals2::connection();
+}
+
+boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)
+{
+ LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+ if (header)
+ {
+ return header->setFocusLostCallback(cb);
+ }
+ return boost::signals2::connection();
+}
LLView* LLAccordionCtrlTab::findContainerView()
{
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index fb19d17e99..de254ed3eb 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -113,6 +113,12 @@ public:
void setAccordionView(LLView* panel);
LLView* getAccordionView() { return mContainerPanel; };
+ // Set text in LLAccordionCtrlTabHeader
+ void setTitle(const std::string& title);
+
+ boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb);
+ boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb);
+
bool getCollapsible() {return mCollapsible;};
void setCollapsible(bool collapsible) {mCollapsible = collapsible;};
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");
+ }
}
}