summaryrefslogtreecommitdiff
path: root/indra/newview/llpaneloutfitedit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llpaneloutfitedit.cpp')
-rw-r--r--indra/newview/llpaneloutfitedit.cpp816
1 files changed, 571 insertions, 245 deletions
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index 4982e98f8e..d67b95a70e 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -2,31 +2,25 @@
* @file llpaneloutfitedit.cpp
* @brief Displays outfit edit information in Side Tray.
*
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
* 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
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * 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
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -39,6 +33,7 @@
#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
+#include "lloutfitobserver.h"
#include "llcofwearables.h"
#include "llfilteredwearablelist.h"
#include "llinventory.h"
@@ -59,17 +54,22 @@
#include "llinventorybridge.h"
#include "llinventorymodel.h"
#include "llinventorymodelbackgroundfetch.h"
+#include "llloadingindicator.h"
#include "llpaneloutfitsinventory.h"
#include "lluiconstants.h"
#include "llsaveoutfitcombobtn.h"
#include "llscrolllistctrl.h"
#include "lltextbox.h"
+#include "lltrans.h"
#include "lluictrlfactory.h"
#include "llsdutil.h"
#include "llsidepanelappearance.h"
#include "lltoggleablemenu.h"
+#include "llvoavatarself.h"
#include "llwearablelist.h"
#include "llwearableitemslist.h"
+#include "llwearabletype.h"
+#include "llweb.h"
static LLRegisterPanelClassWrapper<LLPanelOutfitEdit> t_outfit_edit("panel_outfit_edit");
@@ -79,6 +79,65 @@ const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
static const std::string REVERT_BTN("revert_btn");
+class LLShopURLDispatcher
+{
+public:
+ std::string resolveURL(LLWearableType::EType wearable_type, ESex sex);
+ std::string resolveURL(LLAssetType::EType asset_type, ESex sex);
+};
+
+std::string LLShopURLDispatcher::resolveURL(LLWearableType::EType wearable_type, ESex sex)
+{
+ const std::string prefix = "MarketplaceURL";
+ const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female";
+ const std::string type_str = LLWearableType::getTypeName(wearable_type);
+
+ std::string setting_name = prefix;
+
+ switch (wearable_type)
+ {
+ case LLWearableType::WT_ALPHA:
+ case LLWearableType::WT_NONE:
+ case LLWearableType::WT_INVALID: // just in case, this shouldn't happen
+ case LLWearableType::WT_COUNT: // just in case, this shouldn't happen
+ break;
+
+ default:
+ setting_name += '_';
+ setting_name += type_str;
+ setting_name += sex_str;
+ break;
+ }
+
+ return gSavedSettings.getString(setting_name);
+}
+
+std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex sex)
+{
+ const std::string prefix = "MarketplaceURL";
+ const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female";
+ const std::string type_str = LLAssetType::lookup(asset_type);
+
+ std::string setting_name = prefix;
+
+ switch (asset_type)
+ {
+ case LLAssetType::AT_CLOTHING:
+ case LLAssetType::AT_OBJECT:
+ case LLAssetType::AT_BODYPART:
+ setting_name += '_';
+ setting_name += type_str;
+ setting_name += sex_str;
+ break;
+
+ // to suppress warnings
+ default:
+ break;
+ }
+
+ return gSavedSettings.getString(setting_name);
+}
+
class LLPanelOutfitEditGearMenu
{
public:
@@ -132,7 +191,7 @@ private:
LLMenuItemCallGL::Params p;
p.name = type_name;
- p.label = LLWearableType::getTypeDefaultNewName(type);
+ p.label = LLTrans::getString(LLWearableType::getTypeDefaultNewName(type));
p.on_click.function_name = "Wearable.Create";
p.on_click.parameter = LLSD(type_name);
@@ -143,100 +202,6 @@ private:
}
};
-class LLCOFObserver : public LLInventoryObserver
-{
-public:
- LLCOFObserver(LLPanelOutfitEdit *panel) : mPanel(panel),
- mCOFLastVersion(LLViewerInventoryCategory::VERSION_UNKNOWN)
- {
- gInventory.addObserver(this);
- }
-
- virtual ~LLCOFObserver()
- {
- if (gInventory.containsObserver(this))
- {
- gInventory.removeObserver(this);
- }
- }
-
- virtual void changed(U32 mask)
- {
- if (!gInventory.isInventoryUsable()) return;
-
- bool panel_updated = checkCOF();
-
- if (!panel_updated)
- {
- checkBaseOutfit();
- }
- }
-
-protected:
-
- /** Get a version of an inventory category specified by its UUID */
- static S32 getCategoryVersion(const LLUUID& cat_id)
- {
- LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
- if (!cat) return LLViewerInventoryCategory::VERSION_UNKNOWN;
-
- return cat->getVersion();
- }
-
- bool checkCOF()
- {
- LLUUID cof = LLAppearanceMgr::getInstance()->getCOF();
- if (cof.isNull()) return false;
-
- S32 cof_version = getCategoryVersion(cof);
-
- if (cof_version == mCOFLastVersion) return false;
-
- mCOFLastVersion = cof_version;
-
- mPanel->update();
-
- return true;
- }
-
- void checkBaseOutfit()
- {
- LLUUID baseoutfit_id = LLAppearanceMgr::getInstance()->getBaseOutfitUUID();
-
- if (baseoutfit_id == mBaseOutfitId)
- {
- if (baseoutfit_id.isNull()) return;
-
- const S32 baseoutfit_ver = getCategoryVersion(baseoutfit_id);
-
- if (baseoutfit_ver == mBaseOutfitLastVersion) return;
- }
- else
- {
- mBaseOutfitId = baseoutfit_id;
- mPanel->updateCurrentOutfitName();
-
- if (baseoutfit_id.isNull()) return;
-
- mBaseOutfitLastVersion = getCategoryVersion(mBaseOutfitId);
- }
-
- mPanel->updateVerbs();
- }
-
-
-
-
- LLPanelOutfitEdit *mPanel;
-
- //last version number of a COF category
- S32 mCOFLastVersion;
-
- LLUUID mBaseOutfitId;
-
- S32 mBaseOutfitLastVersion;
-};
-
class LLCOFDragAndDropObserver : public LLInventoryAddItemByAssetObserver
{
public:
@@ -277,25 +242,32 @@ LLPanelOutfitEdit::LLPanelOutfitEdit()
mSearchFilter(NULL),
mCOFWearables(NULL),
mInventoryItemsPanel(NULL),
- mCOFObserver(NULL),
mGearMenu(NULL),
mCOFDragAndDropObserver(NULL),
mInitialized(false),
mAddWearablesPanel(NULL),
- mWearableListMaskCollector(NULL),
- mWearableListTypeCollector(NULL)
+ mFolderViewFilterCmbBox(NULL),
+ mListViewFilterCmbBox(NULL),
+ mPlusBtn(NULL)
{
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
- mCOFObserver = new LLCOFObserver(this);
+
+ LLOutfitObserver& observer = LLOutfitObserver::instance();
+ observer.addBOFReplacedCallback(boost::bind(&LLPanelOutfitEdit::updateCurrentOutfitName, this));
+ observer.addBOFChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
+ observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
+ observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitEdit::onCOFChanged, this));
+
+ gAgentWearables.addLoadingStartedCallback(boost::bind(&LLPanelOutfitEdit::onOutfitChanging, this, true));
+ gAgentWearables.addLoadedCallback(boost::bind(&LLPanelOutfitEdit::onOutfitChanging, this, false));
- mLookItemTypes.reserve(NUM_LOOK_ITEM_TYPES);
- for (U32 i = 0; i < NUM_LOOK_ITEM_TYPES; i++)
+ mFolderViewItemTypes.reserve(NUM_FOLDER_VIEW_ITEM_TYPES);
+ for (U32 i = 0; i < NUM_FOLDER_VIEW_ITEM_TYPES; i++)
{
- mLookItemTypes.push_back(LLLookItemType());
+ mFolderViewItemTypes.push_back(LLLookItemType());
}
-
}
@@ -303,20 +275,42 @@ LLPanelOutfitEdit::~LLPanelOutfitEdit()
{
delete mSavedFolderState;
- delete mCOFObserver;
delete mCOFDragAndDropObserver;
- delete mWearableListMaskCollector;
- delete mWearableListTypeCollector;
+ while (!mListViewItemTypes.empty()) {
+ delete mListViewItemTypes.back();
+ mListViewItemTypes.pop_back();
+ }
}
BOOL LLPanelOutfitEdit::postBuild()
{
// gInventory.isInventoryUsable() no longer needs to be tested per Richard's fix for race conditions between inventory and panels
-
- mLookItemTypes[LIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK);
- mLookItemTypes[LIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK);
- mLookItemTypes[LIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK);
+
+ mFolderViewItemTypes[FVIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK);
+ mFolderViewItemTypes[FVIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK);
+ mFolderViewItemTypes[FVIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK);
+
+ //order is important, see EListViewItemType for order information
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.All"), new LLFindNonLinksByMask(ALL_ITEMS_MASK)));
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Clothing"), new LLIsTypeActual(LLAssetType::AT_CLOTHING)));
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Bodyparts"), new LLIsTypeActual(LLAssetType::AT_BODYPART)));
+ mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Objects"), new LLFindByMask(ATTACHMENT_MASK)));;
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shape"), new LLFindActualWearablesOfType(LLWearableType::WT_SHAPE)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skin"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIN)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("hair"), new LLFindActualWearablesOfType(LLWearableType::WT_HAIR)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("eyes"), new LLFindActualWearablesOfType(LLWearableType::WT_EYES)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SHIRT)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("pants"), new LLFindActualWearablesOfType(LLWearableType::WT_PANTS)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shoes"), new LLFindActualWearablesOfType(LLWearableType::WT_SHOES)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("socks"), new LLFindActualWearablesOfType(LLWearableType::WT_SOCKS)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("jacket"), new LLFindActualWearablesOfType(LLWearableType::WT_JACKET)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("gloves"), new LLFindActualWearablesOfType(LLWearableType::WT_GLOVES)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("undershirt"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERSHIRT)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("underpants"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERPANTS)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIRT)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("alpha"), new LLFindActualWearablesOfType(LLWearableType::WT_ALPHA)));
+ mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("tattoo"), new LLFindActualWearablesOfType(LLWearableType::WT_TATTOO)));
mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name");
mStatus = getChild<LLTextBox>("status");
@@ -325,12 +319,17 @@ BOOL LLPanelOutfitEdit::postBuild()
mListViewBtn = getChild<LLButton>("list_view_btn");
childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
- childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredFolderWearablesPanel, this), NULL);
- childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showFilteredWearablesPanel, this), NULL);
+ childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesFolderView, this), NULL);
+ childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesListView, this), NULL);
childSetCommitCallback("wearables_gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
+ childSetCommitCallback("gear_menu_btn", boost::bind(&LLPanelOutfitEdit::onGearButtonClick, this, _1), NULL);
+ childSetCommitCallback("shop_btn_1", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
+ childSetCommitCallback("shop_btn_2", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
+
+ setVisibleCallback(boost::bind(&LLPanelOutfitEdit::onVisibilityChange, this, _2));
mCOFWearables = getChild<LLCOFWearables>("cof_wearables_list");
- mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onOutfitItemSelectionChange, this));
+ mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::filterWearablesBySelectedItem, this));
mCOFWearables->getCOFCallbacks().mAddWearable = boost::bind(&LLPanelOutfitEdit::onAddWearableClicked, this);
mCOFWearables->getCOFCallbacks().mEditWearable = boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this);
@@ -340,28 +339,39 @@ BOOL LLPanelOutfitEdit::postBuild()
mAddWearablesPanel = getChild<LLPanel>("add_wearables_panel");
- mInventoryItemsPanel = getChild<LLInventoryPanel>("inventory_items");
+ mInventoryItemsPanel = getChild<LLInventoryPanel>("folder_view");
mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK);
mInventoryItemsPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
- mInventoryItemsPanel->setSelectCallback(boost::bind(&LLPanelOutfitEdit::onInventorySelectionChange, this, _1, _2));
- mInventoryItemsPanel->getRootFolder()->setReshapeCallback(boost::bind(&LLPanelOutfitEdit::onInventorySelectionChange, this, _1, _2));
-
+ mInventoryItemsPanel->setSelectCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
+ mInventoryItemsPanel->getRootFolder()->setReshapeCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
+
mCOFDragAndDropObserver = new LLCOFDragAndDropObserver(mInventoryItemsPanel->getModel());
- LLComboBox* type_filter = getChild<LLComboBox>("filter_wearables_combobox");
- type_filter->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onTypeFilterChanged, this, _1));
- type_filter->removeall();
- for (U32 i = 0; i < mLookItemTypes.size(); ++i)
+ mFolderViewFilterCmbBox = getChild<LLComboBox>("folder_view_filter_combobox");
+ mFolderViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onFolderViewFilterCommitted, this, _1));
+ mFolderViewFilterCmbBox->removeall();
+ for (U32 i = 0; i < mFolderViewItemTypes.size(); ++i)
{
- type_filter->add(mLookItemTypes[i].displayName);
+ mFolderViewFilterCmbBox->add(mFolderViewItemTypes[i].displayName);
}
- type_filter->setCurrentByIndex(LIT_ALL);
+ mFolderViewFilterCmbBox->setCurrentByIndex(FVIT_ALL);
+ mListViewFilterCmbBox = getChild<LLComboBox>("list_view_filter_combobox");
+ mListViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onListViewFilterCommitted, this, _1));
+ mListViewFilterCmbBox->removeall();
+ for (U32 i = 0; i < mListViewItemTypes.size(); ++i)
+ {
+ mListViewFilterCmbBox->add(mListViewItemTypes[i]->displayName);
+ }
+ mListViewFilterCmbBox->setCurrentByIndex(LVIT_ALL);
+
mSearchFilter = getChild<LLFilterEditor>("look_item_filter");
mSearchFilter->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onSearchEdit, this, _2));
- childSetAction("show_add_wearables_btn", boost::bind(&LLPanelOutfitEdit::toggleAddWearablesPanel, this));
- childSetAction("add_to_outfit_btn", boost::bind(&LLPanelOutfitEdit::onAddToOutfitClicked, this));
+ childSetAction("show_add_wearables_btn", boost::bind(&LLPanelOutfitEdit::onAddMoreButtonClicked, this));
+
+ mPlusBtn = getChild<LLButton>("plus_btn");
+ mPlusBtn->setClickedCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
mEditWearableBtn = getChild<LLButton>("edit_wearable_btn");
mEditWearableBtn->setEnabled(FALSE);
@@ -370,11 +380,11 @@ BOOL LLPanelOutfitEdit::postBuild()
childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
- mWearableListMaskCollector = new LLFindNonLinksByMask(ALL_ITEMS_MASK);
- mWearableListTypeCollector = new LLFindWearablesOfType(LLWearableType::WT_NONE);
-
- mWearableItemsPanel = getChild<LLPanel>("filtered_wearables_panel");
- mWearableItemsList = getChild<LLInventoryItemsList>("filtered_wearables_list");
+ mWearablesListViewPanel = getChild<LLPanel>("filtered_wearables_panel");
+ mWearableItemsList = getChild<LLInventoryItemsList>("list_view");
+ mWearableItemsList->setCommitOnSelectionChange(true);
+ mWearableItemsList->setCommitCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
+ mWearableItemsList->setDoubleClickCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this));
return TRUE;
@@ -387,7 +397,7 @@ void LLPanelOutfitEdit::onOpen(const LLSD& key)
{
// *TODO: this method is called even panel is not visible to user because its parent layout panel is hidden.
// So, we can defer initializing a bit.
- mWearableListManager = new LLFilteredWearableListManager(mWearableItemsList, mWearableListMaskCollector);
+ mWearableListManager = new LLFilteredWearableListManager(mWearableItemsList, mListViewItemTypes[LVIT_ALL]->collector);
mWearableListManager->populateList();
displayCurrentOutfit();
mInitialized = true;
@@ -415,14 +425,21 @@ void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables)
childSetValue("show_add_wearables_btn", show_add_wearables);
- childSetVisible("filter_wearables_combobox", show_add_wearables);
+ updateFiltersVisibility();
childSetVisible("filter_button", show_add_wearables);
//search filter should be disabled
if (!show_add_wearables)
{
childSetValue("filter_button", false);
+
+ mFolderViewFilterCmbBox->setVisible(false);
+ mListViewFilterCmbBox->setVisible(false);
+
showWearablesFilter();
+
+ // Reset mWearableItemsList position to top. See EXT-8180.
+ mWearableItemsList->goToTop();
}
//switching button bars
@@ -441,43 +458,49 @@ void LLPanelOutfitEdit::showWearablesFilter()
mSearchFilter->clear();
onSearchEdit(LLStringUtil::null);
}
+ else
+ {
+ mSearchFilter->setFocus(TRUE);
+ }
}
-void LLPanelOutfitEdit::showFilteredWearablesPanel()
+void LLPanelOutfitEdit::showWearablesListView()
{
- if(switchPanels(mInventoryItemsPanel, mWearableItemsPanel))
+ if(switchPanels(mInventoryItemsPanel, mWearablesListViewPanel))
{
mFolderViewBtn->setToggleState(FALSE);
mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign());
mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign());
+ updateFiltersVisibility();
}
mListViewBtn->setToggleState(TRUE);
}
-void LLPanelOutfitEdit::showFilteredFolderWearablesPanel()
+void LLPanelOutfitEdit::showWearablesFolderView()
{
- if(switchPanels(mWearableItemsPanel, mInventoryItemsPanel))
+ if(switchPanels(mWearablesListViewPanel, mInventoryItemsPanel))
{
mListViewBtn->setToggleState(FALSE);
mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign());
mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign());
+ updateFiltersVisibility();
}
mFolderViewBtn->setToggleState(TRUE);
}
-void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl)
+void LLPanelOutfitEdit::updateFiltersVisibility()
{
- LLComboBox* type_filter = dynamic_cast<LLComboBox*>(ctrl);
- llassert(type_filter);
- if (type_filter)
- {
- U32 curr_filter_type = type_filter->getCurrentIndex();
- mInventoryItemsPanel->setFilterTypes(mLookItemTypes[curr_filter_type].inventoryMask);
+ mListViewFilterCmbBox->setVisible(mWearablesListViewPanel->getVisible());
+ mFolderViewFilterCmbBox->setVisible(mInventoryItemsPanel->getVisible());
+}
+
+void LLPanelOutfitEdit::onFolderViewFilterCommitted(LLUICtrl* ctrl)
+{
+ S32 curr_filter_type = mFolderViewFilterCmbBox->getCurrentIndex();
+ if (curr_filter_type < 0) return;
+
+ mInventoryItemsPanel->setFilterTypes(mFolderViewItemTypes[curr_filter_type].inventoryMask);
- mWearableListMaskCollector->setFilterMask(mLookItemTypes[curr_filter_type].inventoryMask);
- mWearableListManager->setFilterCollector(mWearableListMaskCollector);
- }
-
mSavedFolderState->setApply(TRUE);
mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
@@ -488,6 +511,14 @@ void LLPanelOutfitEdit::onTypeFilterChanged(LLUICtrl* ctrl)
LLInventoryModelBackgroundFetch::instance().start();
}
+void LLPanelOutfitEdit::onListViewFilterCommitted(LLUICtrl* ctrl)
+{
+ S32 curr_filter_type = mListViewFilterCmbBox->getCurrentIndex();
+ if (curr_filter_type < 0) return;
+
+ mWearableListManager->setFilterCollector(mListViewItemTypes[curr_filter_type]->collector);
+}
+
void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
{
if (mSearchString != string)
@@ -532,27 +563,34 @@ void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
}
-void LLPanelOutfitEdit::onAddToOutfitClicked(void)
+void LLPanelOutfitEdit::onPlusBtnClicked(void)
{
- LLUUID selected_id;
- if (mInventoryItemsPanel->getVisible())
- {
- LLFolderViewItem* curr_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
- if (!curr_item) return;
-
- LLFolderViewEventListener* listenerp = curr_item->getListener();
- if (!listenerp) return;
+ uuid_vec_t selected_items;
+ getSelectedItemsUUID(selected_items);
- selected_id = listenerp->getUUID();
- }
- else if (mWearableItemsPanel->getVisible())
+ LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
+
+ for(uuid_vec_t::iterator iter = selected_items.begin(); iter != selected_items.end(); iter++)
{
- selected_id = mWearableItemsList->getSelectedUUID();
+ LLUUID selected_id = *iter;
+ if (!selected_id.isNull())
+ {
+ //replacing instead of adding the item
+ LLAppearanceMgr::getInstance()->wearItemOnAvatar(selected_id, false, true, link_waiter);
+ }
}
+}
- if (selected_id.isNull()) return;
+void LLPanelOutfitEdit::onVisibilityChange(const LLSD &in_visible_chain)
+{
+ showAddWearablesPanel(false);
+ mWearableItemsList->resetSelection();
+ mInventoryItemsPanel->clearSelection();
- LLAppearanceMgr::getInstance()->wearItemOnAvatar(selected_id);
+ if (in_visible_chain.asBoolean())
+ {
+ update();
+ }
}
void LLPanelOutfitEdit::onAddWearableClicked(void)
@@ -561,82 +599,169 @@ void LLPanelOutfitEdit::onAddWearableClicked(void)
if(item)
{
- showFilteredWearableItemsList(item->getWearableType());
+ showFilteredWearablesListView(item->getWearableType());
}
}
-void LLPanelOutfitEdit::onReplaceBodyPartMenuItemClicked(LLUUID selected_item_id)
+void LLPanelOutfitEdit::onReplaceMenuItemClicked(LLUUID selected_item_id)
{
LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
- if (item && item->getType() == LLAssetType::AT_BODYPART)
+ if (item)
{
- showFilteredWearableItemsList(item->getWearableType());
+ showFilteredWearablesListView(item->getWearableType());
}
}
-void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
+void LLPanelOutfitEdit::onShopButtonClicked()
{
- LLUUID id_to_remove = mCOFWearables->getSelectedUUID();
-
- LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
+ static LLShopURLDispatcher url_resolver;
+
+ // will contain the resultant URL
+ std::string url;
+
+ if (isAgentAvatarValid())
+ {
+ // try to get wearable type from 'Add More' panel first (EXT-7639)
+ LLWearableType::EType type = getAddMorePanelSelectionType();
+
+ if (type == LLWearableType::WT_NONE)
+ {
+ type = getCOFWearablesSelectionType();
+ }
+
+ ESex sex = gAgentAvatarp->getSex();
+
+ // WT_INVALID comes for attachments
+ if (type != LLWearableType::WT_INVALID && type != LLWearableType::WT_NONE)
+ {
+ url = url_resolver.resolveURL(type, sex);
+ }
+
+ if (url.empty())
+ {
+ url = url_resolver.resolveURL(mCOFWearables->getExpandedAccordionAssetType(), sex);
+ }
+ }
+ else
+ {
+ llwarns << "Agent avatar is invalid" << llendl;
+
+ // the second argument is not important in this case: generic market place will be opened
+ url = url_resolver.resolveURL(LLWearableType::WT_NONE, SEX_FEMALE);
+ }
+
+ LLWeb::loadURLExternal(url);
}
+LLWearableType::EType LLPanelOutfitEdit::getCOFWearablesSelectionType() const
+{
+ std::vector<LLPanel*> selected_items;
+ LLWearableType::EType type = LLWearableType::WT_NONE;
-void LLPanelOutfitEdit::onEditWearableClicked(void)
+ mCOFWearables->getSelectedItems(selected_items);
+
+ if (selected_items.size() == 1)
+ {
+ LLPanel* item = selected_items.front();
+
+ // LLPanelDummyClothingListItem is lower then LLPanelInventoryListItemBase in hierarchy tree
+ if (LLPanelDummyClothingListItem* dummy_item = dynamic_cast<LLPanelDummyClothingListItem*>(item))
+ {
+ type = dummy_item->getWearableType();
+ }
+ else if (LLPanelInventoryListItemBase* real_item = dynamic_cast<LLPanelInventoryListItemBase*>(item))
+ {
+ type = real_item->getWearableType();
+ }
+ }
+
+ return type;
+}
+
+LLWearableType::EType LLPanelOutfitEdit::getAddMorePanelSelectionType() const
{
- LLUUID id_to_edit = mCOFWearables->getSelectedUUID();
- LLViewerInventoryItem * item_to_edit = gInventory.getItem(id_to_edit);
+ LLWearableType::EType type = LLWearableType::WT_NONE;
- if (item_to_edit)
+ if (mAddWearablesPanel != NULL && mAddWearablesPanel->getVisible())
{
- // returns null if not a wearable (attachment, etc).
- LLWearable* wearable_to_edit = gAgentWearables.getWearableFromAssetID(item_to_edit->getAssetUUID());
- if(wearable_to_edit)
+ if (mInventoryItemsPanel != NULL && mInventoryItemsPanel->getVisible())
{
- bool can_modify = false;
- bool is_complete = item_to_edit->isFinished();
- // if item_to_edit is a link, its properties are not appropriate,
- // lets get original item with actual properties
- LLViewerInventoryItem* original_item = gInventory.getItem(wearable_to_edit->getItemID());
- if(original_item)
+ std::set<LLUUID> selected_uuids = mInventoryItemsPanel->getRootFolder()->getSelectionList();
+
+ if (selected_uuids.size() == 1)
{
- can_modify = original_item->getPermissions().allowModifyBy(gAgentID);
- is_complete = original_item->isFinished();
+ type = getWearableTypeByItemUUID(*(selected_uuids.begin()));
}
+ }
+ else if (mWearableItemsList != NULL && mWearableItemsList->getVisible())
+ {
+ std::vector<LLUUID> selected_uuids;
+ mWearableItemsList->getSelectedUUIDs(selected_uuids);
- if (can_modify && is_complete)
- {
- LLSidepanelAppearance::editWearable(wearable_to_edit, getParent());
- if (mEditWearableBtn->getVisible())
- {
- mEditWearableBtn->setVisible(FALSE);
- }
+ if (selected_uuids.size() == 1)
+ {
+ type = getWearableTypeByItemUUID(selected_uuids.front());
}
}
}
+
+ return type;
}
-void LLPanelOutfitEdit::onInventorySelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action)
+LLWearableType::EType LLPanelOutfitEdit::getWearableTypeByItemUUID(const LLUUID& item_uuid) const
{
- LLFolderViewItem* current_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
- if (!current_item)
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(item_uuid);
+ return (item != NULL) ? item->getWearableType() : LLWearableType::WT_NONE;
+}
+
+void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
+{
+ LLUUID id_to_remove = mCOFWearables->getSelectedUUID();
+
+ LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
+}
+
+
+void LLPanelOutfitEdit::onEditWearableClicked(void)
+{
+ LLUUID selected_item_id = mCOFWearables->getSelectedUUID();
+ if (selected_item_id.notNull())
{
+ gAgentWearables.editWearable(selected_item_id);
+ }
+}
+
+void LLPanelOutfitEdit::updatePlusButton()
+{
+ uuid_vec_t selected_items;
+ getSelectedItemsUUID(selected_items);
+ if (selected_items.empty())
+ {
+ mPlusBtn->setEnabled(false);
return;
}
- LLViewerInventoryItem* item = current_item->getInventoryItem();
- if (!item) return;
+ // If any of the selected items are not wearable (due to already being worn OR being of the wrong type), disable the add button.
+ uuid_vec_t::iterator unwearable_item = std::find_if(selected_items.begin(), selected_items.end(), !boost::bind(& get_can_item_be_worn, _1));
+ bool can_add = ( unwearable_item == selected_items.end() );
+
+ mPlusBtn->setEnabled(can_add);
+
+ LLViewerInventoryItem* first_item(gInventory.getItem(selected_items.front()));
- switch (item->getType())
+ if (can_add &&
+ first_item &&
+ selected_items.size() == 1 &&
+ first_item->getType() == LLAssetType::AT_BODYPART)
{
- case LLAssetType::AT_CLOTHING:
- case LLAssetType::AT_BODYPART:
- case LLAssetType::AT_OBJECT:
- default:
- break;
+ mPlusBtn->setToolTip(getString("replace_body_part"));
}
-
+ else
+ {
+ mPlusBtn->setToolTip(LLStringUtil::null);
+ }
+
/* Removing add to look inline button (not part of mvp for viewer 2)
LLRect btn_rect(current_item->getLocalRect().mRight - 50,
current_item->getLocalRect().mTop,
@@ -653,24 +778,129 @@ void LLPanelOutfitEdit::onInventorySelectionChange(const std::deque<LLFolderView
current_item->addChild(mAddToLookBtn); */
}
-void LLPanelOutfitEdit::onOutfitItemSelectionChange(void)
-{
- LLUUID item_id = mCOFWearables->getSelectedUUID();
- //*TODO show Edit Wearable Button
+void LLPanelOutfitEdit::applyFolderViewFilter(EFolderViewItemType type)
+{
+ mFolderViewFilterCmbBox->setCurrentByIndex(type);
+ mFolderViewFilterCmbBox->onCommit();
+}
- LLViewerInventoryItem* item_to_remove = gInventory.getItem(item_id);
- if (!item_to_remove) return;
+void LLPanelOutfitEdit::applyListViewFilter(EListViewItemType type)
+{
+ mListViewFilterCmbBox->setCurrentByIndex(type);
+ mListViewFilterCmbBox->onCommit();
+}
- switch (item_to_remove->getType())
+void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
+{
+ if (!mAddWearablesPanel->getVisible()) return;
+
+ uuid_vec_t ids;
+ mCOFWearables->getSelectedUUIDs(ids);
+
+ bool nothing_selected = ids.empty();
+ bool one_selected = ids.size() == 1;
+ bool more_than_one_selected = ids.size() > 1;
+ bool is_dummy_item = (ids.size() && dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem()));
+
+ // selected, expanded accordion tabs and selection in flat list view determine filtering when no item is selected in COF
+ // selection in flat list view participates in determining filtering because of EXT-7963
+ // So the priority of criterions in is:
+ // 1. Selected accordion tab | IF (any accordion selected)
+ // | filter_type = selected_accordion_type
+ // 2. Selected item in flat list view | ELSEIF (any item in flat list view selected)
+ // | filter_type = selected_item_type
+ // 3. Expanded accordion tab | ELSEIF (any accordion expanded)
+ // | filter_type = expanded accordion_type
+ if (nothing_selected)
{
- case LLAssetType::AT_CLOTHING:
- case LLAssetType::AT_OBJECT:
- default:
- break;
+ showWearablesListView();
+
+ //selected accordion tab is more priority than expanded tab
+ //and selected item in flat list view of 'Add more' panel when
+ //determining filtering
+ LLAssetType::EType type = mCOFWearables->getSelectedAccordionAssetType();
+ if (type == LLAssetType::AT_NONE)
+ { //no accordion selected
+
+ // when no accordion selected then selected item from flat list view
+ // has more priority than expanded when determining filtering
+ LLUUID selected_item_id = mWearableItemsList->getSelectedUUID();
+ LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
+ if(item)
+ {
+ showFilteredWearablesListView(item->getWearableType());
+ return;
+ }
+
+ // when no accordion selected and no selected items in flat list view
+ // determine filtering according to expanded accordion
+ type = mCOFWearables->getExpandedAccordionAssetType();
+ }
+
+ switch (type)
+ {
+ case LLAssetType::AT_OBJECT:
+ applyListViewFilter(LVIT_ATTACHMENT);
+ break;
+ case LLAssetType::AT_BODYPART:
+ applyListViewFilter(LVIT_BODYPART);
+ break;
+ case LLAssetType::AT_CLOTHING:
+ default:
+ applyListViewFilter(LVIT_CLOTHING);
+ break;
+ }
+
+ return;
+ }
+
+ //resetting selection if more than one item is selected
+ if (more_than_one_selected)
+ {
+ showWearablesListView();
+ applyListViewFilter(LVIT_ALL);
+ return;
+ }
+
+
+ //filter wearables by a type represented by a dummy item
+ if (one_selected && is_dummy_item)
+ {
+ onAddWearableClicked();
+ return;
}
+
+ LLViewerInventoryItem* item = gInventory.getItem(ids[0]);
+ if (!item && ids[0].notNull())
+ {
+ //Inventory misses an item with non-zero id
+ showWearablesListView();
+ applyListViewFilter(LVIT_ALL);
+ return;
+ }
+
+ if (item && one_selected && !is_dummy_item)
+ {
+ if (item->isWearableType())
+ {
+ //single clothing or bodypart item is selected
+ showFilteredWearablesListView(item->getWearableType());
+ return;
+ }
+ else
+ {
+ //attachment is selected
+ showWearablesListView();
+ applyListViewFilter(LVIT_ATTACHMENT);
+ return;
+ }
+ }
+
}
+
+
void LLPanelOutfitEdit::update()
{
mCOFWearables->refresh();
@@ -756,19 +986,21 @@ void LLPanelOutfitEdit::updateCurrentOutfitName()
//private
void LLPanelOutfitEdit::updateVerbs()
{
- //*TODO implement better handling of COF dirtiness
- LLAppearanceMgr::getInstance()->updateIsDirty();
-
bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
+ bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked();
bool has_baseoutfit = LLAppearanceMgr::getInstance()->getBaseOutfitUUID().notNull();
- mSaveComboBtn->setSaveBtnEnabled(outfit_is_dirty);
+ mSaveComboBtn->setSaveBtnEnabled(!outfit_locked && outfit_is_dirty);
childSetEnabled(REVERT_BTN, outfit_is_dirty && has_baseoutfit);
- mSaveComboBtn->setMenuItemEnabled("save_outfit", outfit_is_dirty);
+ mSaveComboBtn->setMenuItemEnabled("save_outfit", !outfit_locked && outfit_is_dirty);
mStatus->setText(outfit_is_dirty ? getString("unsaved_changes") : getString("now_editing"));
+ updateCurrentOutfitName();
+
+ //updating state of "Wear Item" button previously known as "Plus" button
+ updatePlusButton();
}
bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch_to_panel)
@@ -782,6 +1014,18 @@ bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch
return false;
}
+void LLPanelOutfitEdit::resetAccordionState()
+{
+ if (mCOFWearables != NULL)
+ {
+ mCOFWearables->expandDefaultAccordionTab();
+ }
+ else
+ {
+ llwarns << "mCOFWearables is NULL" << llendl;
+ }
+}
+
void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
{
if(!mGearMenu)
@@ -793,12 +1037,94 @@ void LLPanelOutfitEdit::onGearButtonClick(LLUICtrl* clicked_button)
LLMenuGL::showPopup(clicked_button, mGearMenu, 0, menu_y);
}
-void LLPanelOutfitEdit::showFilteredWearableItemsList(LLWearableType::EType type)
+void LLPanelOutfitEdit::onAddMoreButtonClicked()
+{
+ toggleAddWearablesPanel();
+ filterWearablesBySelectedItem();
+}
+
+void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type)
{
- mWearableListTypeCollector->setType(type);
- mWearableListManager->setFilterCollector(mWearableListTypeCollector);
showAddWearablesPanel(true);
- showFilteredWearablesPanel();
+ showWearablesListView();
+
+ //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE
+ applyListViewFilter((EListViewItemType) (LVIT_SHAPE + type));
+}
+
+static void update_status_widget_rect(LLView * widget, S32 right_border)
+{
+ LLRect rect = widget->getRect();
+ rect.mRight = right_border;
+
+ widget->setShape(rect);
+}
+
+void LLPanelOutfitEdit::onOutfitChanging(bool started)
+{
+ static LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("edit_outfit_loading_indicator");
+ static LLView* status_panel = getChild<LLView>("outfit_name_and_status");
+ static S32 indicator_delta = status_panel->getRect().getWidth() - indicator->getRect().mLeft;
+
+ S32 delta = started ? indicator_delta : 0;
+ S32 right_border = status_panel->getRect().getWidth() - delta;
+
+ update_status_widget_rect(mCurrentOutfitName, right_border);
+ update_status_widget_rect(mStatus, right_border);
+
+ indicator->setVisible(started);
+}
+
+void LLPanelOutfitEdit::getCurrentItemUUID(LLUUID& selected_id)
+{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ LLFolderViewItem* curr_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
+ if (!curr_item) return;
+
+ LLFolderViewEventListener* listenerp = curr_item->getListener();
+ if (!listenerp) return;
+
+ selected_id = listenerp->getUUID();
+ }
+ else if (mWearablesListViewPanel->getVisible())
+ {
+ selected_id = mWearableItemsList->getSelectedUUID();
+ }
}
+
+void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list)
+{
+ if (mInventoryItemsPanel->getVisible())
+ {
+ std::set<LLUUID> item_set = mInventoryItemsPanel->getRootFolder()->getSelectionList();
+
+ std::for_each(item_set.begin(), item_set.end(), boost::bind( &uuid_vec_t::push_back, &uuid_list, _1));
+ }
+ else if (mWearablesListViewPanel->getVisible())
+ {
+ std::vector<LLSD> item_set;
+ mWearableItemsList->getSelectedValues(item_set);
+
+ std::for_each(item_set.begin(), item_set.end(), boost::bind( &uuid_vec_t::push_back, &uuid_list, boost::bind(&LLSD::asUUID, _1 )));
+
+ }
+
+// return selected_id;
+}
+
+void LLPanelOutfitEdit::onCOFChanged()
+{
+ //the panel is only updated when is visible to a user
+
+ // BAP - this check has to be removed because otherwise item name
+ // changes made when the panel is not visible will not be
+ // propagated to the panel.
+ // if (!isInVisibleChain()) return;
+
+ update();
+}
+
+
// EOF