PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llpaneloutfitedit.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1415 lines | 1028 code | 246 blank | 141 comment | 176 complexity | 65ed7320619a0e6d353df119b1b8b468 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llpaneloutfitedit.cpp
  3. * @brief Displays outfit edit information in Side Tray.
  4. *
  5. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llpaneloutfitedit.h"
  28. // *TODO: reorder includes to match the coding standard
  29. #include "llagent.h"
  30. #include "llagentcamera.h"
  31. #include "llagentwearables.h"
  32. #include "llappearancemgr.h"
  33. #include "lloutfitobserver.h"
  34. #include "llcofwearables.h"
  35. #include "llfilteredwearablelist.h"
  36. #include "llfolderview.h"
  37. #include "llinventory.h"
  38. #include "llinventoryitemslist.h"
  39. #include "llviewercontrol.h"
  40. #include "llui.h"
  41. #include "llfloater.h"
  42. #include "llfloaterreg.h"
  43. #include "llinventoryfunctions.h"
  44. #include "llinventorypanel.h"
  45. #include "llviewermenu.h"
  46. #include "llviewerwindow.h"
  47. #include "llviewerinventory.h"
  48. #include "llbutton.h"
  49. #include "llcombobox.h"
  50. #include "llfiltereditor.h"
  51. #include "llfloaterinventory.h"
  52. #include "llinventorybridge.h"
  53. #include "llinventorymodel.h"
  54. #include "llinventorymodelbackgroundfetch.h"
  55. #include "llloadingindicator.h"
  56. #include "llmenubutton.h"
  57. #include "llpaneloutfitsinventory.h"
  58. #include "lluiconstants.h"
  59. #include "llsaveoutfitcombobtn.h"
  60. #include "llscrolllistctrl.h"
  61. #include "lltextbox.h"
  62. #include "lltoggleablemenu.h"
  63. #include "lltrans.h"
  64. #include "lluictrlfactory.h"
  65. #include "llsdutil.h"
  66. #include "llsidepanelappearance.h"
  67. #include "lltoggleablemenu.h"
  68. #include "llvoavatarself.h"
  69. #include "llwearablelist.h"
  70. #include "llwearableitemslist.h"
  71. #include "llwearabletype.h"
  72. #include "llweb.h"
  73. static LLRegisterPanelClassWrapper<LLPanelOutfitEdit> t_outfit_edit("panel_outfit_edit");
  74. const U64 WEARABLE_MASK = (1LL << LLInventoryType::IT_WEARABLE);
  75. const U64 ATTACHMENT_MASK = (1LL << LLInventoryType::IT_ATTACHMENT) | (1LL << LLInventoryType::IT_OBJECT);
  76. const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
  77. static const std::string REVERT_BTN("revert_btn");
  78. ///////////////////////////////////////////////////////////////////////////////
  79. // LLShopURLDispatcher
  80. ///////////////////////////////////////////////////////////////////////////////
  81. class LLShopURLDispatcher
  82. {
  83. public:
  84. std::string resolveURL(LLWearableType::EType wearable_type, ESex sex);
  85. std::string resolveURL(LLAssetType::EType asset_type, ESex sex);
  86. };
  87. std::string LLShopURLDispatcher::resolveURL(LLWearableType::EType wearable_type, ESex sex)
  88. {
  89. const std::string prefix = "MarketplaceURL";
  90. const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female";
  91. const std::string type_str = LLWearableType::getTypeName(wearable_type);
  92. std::string setting_name = prefix;
  93. switch (wearable_type)
  94. {
  95. case LLWearableType::WT_ALPHA:
  96. case LLWearableType::WT_NONE:
  97. case LLWearableType::WT_INVALID: // just in case, this shouldn't happen
  98. case LLWearableType::WT_COUNT: // just in case, this shouldn't happen
  99. break;
  100. default:
  101. setting_name += '_';
  102. setting_name += type_str;
  103. setting_name += sex_str;
  104. break;
  105. }
  106. return gSavedSettings.getString(setting_name);
  107. }
  108. std::string LLShopURLDispatcher::resolveURL(LLAssetType::EType asset_type, ESex sex)
  109. {
  110. const std::string prefix = "MarketplaceURL";
  111. const std::string sex_str = (sex == SEX_MALE) ? "Male" : "Female";
  112. const std::string type_str = LLAssetType::lookup(asset_type);
  113. std::string setting_name = prefix;
  114. switch (asset_type)
  115. {
  116. case LLAssetType::AT_CLOTHING:
  117. case LLAssetType::AT_OBJECT:
  118. case LLAssetType::AT_BODYPART:
  119. setting_name += '_';
  120. setting_name += type_str;
  121. setting_name += sex_str;
  122. break;
  123. // to suppress warnings
  124. default:
  125. break;
  126. }
  127. return gSavedSettings.getString(setting_name);
  128. }
  129. ///////////////////////////////////////////////////////////////////////////////
  130. // LLPanelOutfitEditGearMenu
  131. ///////////////////////////////////////////////////////////////////////////////
  132. class LLPanelOutfitEditGearMenu
  133. {
  134. public:
  135. static LLToggleableMenu* create()
  136. {
  137. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  138. registrar.add("Wearable.Create", boost::bind(onCreate, _2));
  139. LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
  140. "menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
  141. llassert(menu);
  142. if (menu)
  143. {
  144. populateCreateWearableSubmenus(menu);
  145. }
  146. return menu;
  147. }
  148. private:
  149. static void onCreate(const LLSD& param)
  150. {
  151. LLWearableType::EType type = LLWearableType::typeNameToType(param.asString());
  152. if (type == LLWearableType::WT_NONE)
  153. {
  154. llwarns << "Invalid wearable type" << llendl;
  155. return;
  156. }
  157. LLAgentWearables::createWearable(type, true);
  158. }
  159. // Populate the menu with items like "New Skin", "New Pants", etc.
  160. static void populateCreateWearableSubmenus(LLMenuGL* menu)
  161. {
  162. LLView* menu_clothes = gMenuHolder->getChildView("COF.Gear.New_Clothes", FALSE);
  163. LLView* menu_bp = gMenuHolder->getChildView("COF.Geear.New_Body_Parts", FALSE);
  164. for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i)
  165. {
  166. LLWearableType::EType type = (LLWearableType::EType) i;
  167. const std::string& type_name = LLWearableType::getTypeName(type);
  168. LLMenuItemCallGL::Params p;
  169. p.name = type_name;
  170. p.label = LLTrans::getString(LLWearableType::getTypeDefaultNewName(type));
  171. p.on_click.function_name = "Wearable.Create";
  172. p.on_click.parameter = LLSD(type_name);
  173. LLView* parent = LLWearableType::getAssetType(type) == LLAssetType::AT_CLOTHING ?
  174. menu_clothes : menu_bp;
  175. LLUICtrlFactory::create<LLMenuItemCallGL>(p, parent);
  176. }
  177. }
  178. };
  179. ///////////////////////////////////////////////////////////////////////////////
  180. // LLAddWearablesGearMenu
  181. ///////////////////////////////////////////////////////////////////////////////
  182. class LLAddWearablesGearMenu : public LLInitClass<LLAddWearablesGearMenu>
  183. {
  184. public:
  185. static LLToggleableMenu* create(LLWearableItemsList* flat_list, LLInventoryPanel* inventory_panel)
  186. {
  187. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  188. LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
  189. llassert(flat_list);
  190. llassert(inventory_panel);
  191. LLHandle<LLView> flat_list_handle = flat_list->getHandle();
  192. LLHandle<LLPanel> inventory_panel_handle = inventory_panel->getHandle();
  193. registrar.add("AddWearable.Gear.Sort", boost::bind(onSort, flat_list_handle, inventory_panel_handle, _2));
  194. enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2));
  195. enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2));
  196. LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
  197. "menu_add_wearable_gear.xml",
  198. LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
  199. return menu;
  200. }
  201. private:
  202. static void onSort(LLHandle<LLView> flat_list_handle,
  203. LLHandle<LLPanel> inventory_panel_handle,
  204. LLSD::String sort_order_str)
  205. {
  206. if (flat_list_handle.isDead() || inventory_panel_handle.isDead()) return;
  207. LLWearableItemsList* flat_list = dynamic_cast<LLWearableItemsList*>(flat_list_handle.get());
  208. LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
  209. if (!flat_list || !inventory_panel) return;
  210. LLWearableItemsList::ESortOrder sort_order;
  211. if ("by_most_recent" == sort_order_str)
  212. {
  213. sort_order = LLWearableItemsList::E_SORT_BY_MOST_RECENT;
  214. }
  215. else if ("by_name" == sort_order_str)
  216. {
  217. sort_order = LLWearableItemsList::E_SORT_BY_NAME;
  218. }
  219. else if ("by_type" == sort_order_str)
  220. {
  221. sort_order = LLWearableItemsList::E_SORT_BY_TYPE_NAME;
  222. }
  223. else
  224. {
  225. llwarns << "Unrecognized sort order action" << llendl;
  226. return;
  227. }
  228. if (inventory_panel->getVisible())
  229. {
  230. inventory_panel->setSortOrder(sort_order);
  231. }
  232. else
  233. {
  234. flat_list->setSortOrder(sort_order);
  235. }
  236. }
  237. static bool onCheck(LLHandle<LLView> flat_list_handle,
  238. LLHandle<LLPanel> inventory_panel_handle,
  239. LLSD::String sort_order_str)
  240. {
  241. if (flat_list_handle.isDead() || inventory_panel_handle.isDead()) return false;
  242. LLWearableItemsList* flat_list = dynamic_cast<LLWearableItemsList*>(flat_list_handle.get());
  243. LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
  244. if (!inventory_panel || !flat_list) return false;
  245. // Inventory panel uses its own sort order independent from
  246. // flat list view so this flag is used to distinguish between
  247. // currently visible "tree" or "flat" representation of inventory.
  248. bool inventory_tree_visible = inventory_panel->getVisible();
  249. if (inventory_tree_visible)
  250. {
  251. U32 sort_order = inventory_panel->getSortOrder();
  252. if ("by_most_recent" == sort_order_str)
  253. {
  254. return LLWearableItemsList::E_SORT_BY_MOST_RECENT & sort_order;
  255. }
  256. else if ("by_name" == sort_order_str)
  257. {
  258. // If inventory panel is not sorted by date then it is sorted by name.
  259. return LLWearableItemsList::E_SORT_BY_MOST_RECENT & ~sort_order;
  260. }
  261. llwarns << "Unrecognized inventory panel sort order" << llendl;
  262. }
  263. else
  264. {
  265. LLWearableItemsList::ESortOrder sort_order = flat_list->getSortOrder();
  266. if ("by_most_recent" == sort_order_str)
  267. {
  268. return LLWearableItemsList::E_SORT_BY_MOST_RECENT == sort_order;
  269. }
  270. else if ("by_name" == sort_order_str)
  271. {
  272. return LLWearableItemsList::E_SORT_BY_NAME == sort_order;
  273. }
  274. else if ("by_type" == sort_order_str)
  275. {
  276. return LLWearableItemsList::E_SORT_BY_TYPE_NAME == sort_order;
  277. }
  278. llwarns << "Unrecognized wearable list sort order" << llendl;
  279. }
  280. return false;
  281. }
  282. static bool onVisible(LLHandle<LLPanel> inventory_panel_handle,
  283. LLSD::String sort_order_str)
  284. {
  285. if (inventory_panel_handle.isDead()) return false;
  286. LLInventoryPanel* inventory_panel = dynamic_cast<LLInventoryPanel*>(inventory_panel_handle.get());
  287. // Enable sorting by type only for the flat list of items
  288. // because inventory panel doesn't support this kind of sorting.
  289. return ( "by_type" == sort_order_str )
  290. && ( !inventory_panel || !inventory_panel->getVisible() );
  291. }
  292. };
  293. ///////////////////////////////////////////////////////////////////////////////
  294. // LLCOFDragAndDropObserver
  295. ///////////////////////////////////////////////////////////////////////////////
  296. class LLCOFDragAndDropObserver : public LLInventoryAddItemByAssetObserver
  297. {
  298. public:
  299. LLCOFDragAndDropObserver(LLInventoryModel* model);
  300. virtual ~LLCOFDragAndDropObserver();
  301. virtual void done();
  302. private:
  303. LLInventoryModel* mModel;
  304. };
  305. inline LLCOFDragAndDropObserver::LLCOFDragAndDropObserver(LLInventoryModel* model):
  306. mModel(model)
  307. {
  308. if (model != NULL)
  309. {
  310. model->addObserver(this);
  311. }
  312. }
  313. inline LLCOFDragAndDropObserver::~LLCOFDragAndDropObserver()
  314. {
  315. if (mModel != NULL && mModel->containsObserver(this))
  316. {
  317. mModel->removeObserver(this);
  318. }
  319. }
  320. void LLCOFDragAndDropObserver::done()
  321. {
  322. LLAppearanceMgr::instance().updateAppearanceFromCOF();
  323. }
  324. ///////////////////////////////////////////////////////////////////////////////
  325. // LLPanelOutfitEdit
  326. ///////////////////////////////////////////////////////////////////////////////
  327. LLPanelOutfitEdit::LLPanelOutfitEdit()
  328. : LLPanel(),
  329. mSearchFilter(NULL),
  330. mCOFWearables(NULL),
  331. mInventoryItemsPanel(NULL),
  332. mGearMenu(NULL),
  333. mAddWearablesGearMenu(NULL),
  334. mCOFDragAndDropObserver(NULL),
  335. mInitialized(false),
  336. mAddWearablesPanel(NULL),
  337. mFolderViewFilterCmbBox(NULL),
  338. mListViewFilterCmbBox(NULL),
  339. mWearableListManager(NULL),
  340. mPlusBtn(NULL),
  341. mWearablesGearMenuBtn(NULL),
  342. mGearMenuBtn(NULL)
  343. {
  344. mSavedFolderState = new LLSaveFolderState();
  345. mSavedFolderState->setApply(FALSE);
  346. LLOutfitObserver& observer = LLOutfitObserver::instance();
  347. observer.addBOFReplacedCallback(boost::bind(&LLPanelOutfitEdit::updateCurrentOutfitName, this));
  348. observer.addBOFChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
  349. observer.addOutfitLockChangedCallback(boost::bind(&LLPanelOutfitEdit::updateVerbs, this));
  350. observer.addCOFChangedCallback(boost::bind(&LLPanelOutfitEdit::onCOFChanged, this));
  351. gAgentWearables.addLoadingStartedCallback(boost::bind(&LLPanelOutfitEdit::onOutfitChanging, this, true));
  352. gAgentWearables.addLoadedCallback(boost::bind(&LLPanelOutfitEdit::onOutfitChanging, this, false));
  353. mFolderViewItemTypes.reserve(NUM_FOLDER_VIEW_ITEM_TYPES);
  354. for (U32 i = 0; i < NUM_FOLDER_VIEW_ITEM_TYPES; i++)
  355. {
  356. mFolderViewItemTypes.push_back(LLLookItemType());
  357. }
  358. }
  359. LLPanelOutfitEdit::~LLPanelOutfitEdit()
  360. {
  361. delete mWearableListManager;
  362. delete mSavedFolderState;
  363. delete mCOFDragAndDropObserver;
  364. while (!mListViewItemTypes.empty()) {
  365. delete mListViewItemTypes.back();
  366. mListViewItemTypes.pop_back();
  367. }
  368. }
  369. BOOL LLPanelOutfitEdit::postBuild()
  370. {
  371. // gInventory.isInventoryUsable() no longer needs to be tested per Richard's fix for race conditions between inventory and panels
  372. mFolderViewItemTypes[FVIT_ALL] = LLLookItemType(getString("Filter.All"), ALL_ITEMS_MASK);
  373. mFolderViewItemTypes[FVIT_WEARABLE] = LLLookItemType(getString("Filter.Clothes/Body"), WEARABLE_MASK);
  374. mFolderViewItemTypes[FVIT_ATTACHMENT] = LLLookItemType(getString("Filter.Objects"), ATTACHMENT_MASK);
  375. //order is important, see EListViewItemType for order information
  376. mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.All"), new LLFindNonLinksByMask(ALL_ITEMS_MASK)));
  377. mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Clothing"), new LLIsTypeActual(LLAssetType::AT_CLOTHING)));
  378. mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Bodyparts"), new LLIsTypeActual(LLAssetType::AT_BODYPART)));
  379. mListViewItemTypes.push_back(new LLFilterItem(getString("Filter.Objects"), new LLFindNonLinksByMask(ATTACHMENT_MASK)));;
  380. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shape"), new LLFindActualWearablesOfType(LLWearableType::WT_SHAPE)));
  381. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skin"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIN)));
  382. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("hair"), new LLFindActualWearablesOfType(LLWearableType::WT_HAIR)));
  383. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("eyes"), new LLFindActualWearablesOfType(LLWearableType::WT_EYES)));
  384. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SHIRT)));
  385. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("pants"), new LLFindActualWearablesOfType(LLWearableType::WT_PANTS)));
  386. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("shoes"), new LLFindActualWearablesOfType(LLWearableType::WT_SHOES)));
  387. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("socks"), new LLFindActualWearablesOfType(LLWearableType::WT_SOCKS)));
  388. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("jacket"), new LLFindActualWearablesOfType(LLWearableType::WT_JACKET)));
  389. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("gloves"), new LLFindActualWearablesOfType(LLWearableType::WT_GLOVES)));
  390. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("undershirt"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERSHIRT)));
  391. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("underpants"), new LLFindActualWearablesOfType(LLWearableType::WT_UNDERPANTS)));
  392. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIRT)));
  393. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("alpha"), new LLFindActualWearablesOfType(LLWearableType::WT_ALPHA)));
  394. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("tattoo"), new LLFindActualWearablesOfType(LLWearableType::WT_TATTOO)));
  395. mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("physics"), new LLFindActualWearablesOfType(LLWearableType::WT_PHYSICS)));
  396. mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name");
  397. mStatus = getChild<LLTextBox>("status");
  398. mFolderViewBtn = getChild<LLButton>("folder_view_btn");
  399. mListViewBtn = getChild<LLButton>("list_view_btn");
  400. childSetCommitCallback("filter_button", boost::bind(&LLPanelOutfitEdit::showWearablesFilter, this), NULL);
  401. childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesFolderView, this), NULL);
  402. childSetCommitCallback("folder_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
  403. childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::showWearablesListView, this), NULL);
  404. childSetCommitCallback("list_view_btn", boost::bind(&LLPanelOutfitEdit::saveListSelection, this), NULL);
  405. childSetCommitCallback("shop_btn_1", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
  406. childSetCommitCallback("shop_btn_2", boost::bind(&LLPanelOutfitEdit::onShopButtonClicked, this), NULL);
  407. setVisibleCallback(boost::bind(&LLPanelOutfitEdit::onVisibilityChange, this, _2));
  408. mWearablesGearMenuBtn = getChild<LLMenuButton>("wearables_gear_menu_btn");
  409. mGearMenuBtn = getChild<LLMenuButton>("gear_menu_btn");
  410. mCOFWearables = findChild<LLCOFWearables>("cof_wearables_list");
  411. mCOFWearables->setCommitCallback(boost::bind(&LLPanelOutfitEdit::filterWearablesBySelectedItem, this));
  412. mCOFWearables->getCOFCallbacks().mAddWearable = boost::bind(&LLPanelOutfitEdit::onAddWearableClicked, this);
  413. mCOFWearables->getCOFCallbacks().mEditWearable = boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this);
  414. mCOFWearables->getCOFCallbacks().mDeleteWearable = boost::bind(&LLPanelOutfitEdit::onRemoveFromOutfitClicked, this);
  415. mCOFWearables->getCOFCallbacks().mMoveWearableCloser = boost::bind(&LLPanelOutfitEdit::moveWearable, this, true);
  416. mCOFWearables->getCOFCallbacks().mMoveWearableFurther = boost::bind(&LLPanelOutfitEdit::moveWearable, this, false);
  417. mAddWearablesPanel = getChild<LLPanel>("add_wearables_panel");
  418. mInventoryItemsPanel = getChild<LLInventoryPanel>("folder_view");
  419. mInventoryItemsPanel->setFilterTypes(ALL_ITEMS_MASK);
  420. mInventoryItemsPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
  421. mInventoryItemsPanel->setSelectCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
  422. mInventoryItemsPanel->getRootFolder()->setReshapeCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
  423. mCOFDragAndDropObserver = new LLCOFDragAndDropObserver(mInventoryItemsPanel->getModel());
  424. mFolderViewFilterCmbBox = getChild<LLComboBox>("folder_view_filter_combobox");
  425. mFolderViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onFolderViewFilterCommitted, this, _1));
  426. mFolderViewFilterCmbBox->removeall();
  427. for (U32 i = 0; i < mFolderViewItemTypes.size(); ++i)
  428. {
  429. mFolderViewFilterCmbBox->add(mFolderViewItemTypes[i].displayName);
  430. }
  431. mFolderViewFilterCmbBox->setCurrentByIndex(FVIT_ALL);
  432. mListViewFilterCmbBox = getChild<LLComboBox>("list_view_filter_combobox");
  433. mListViewFilterCmbBox->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onListViewFilterCommitted, this, _1));
  434. mListViewFilterCmbBox->removeall();
  435. for (U32 i = 0; i < mListViewItemTypes.size(); ++i)
  436. {
  437. mListViewFilterCmbBox->add(mListViewItemTypes[i]->displayName);
  438. }
  439. mListViewFilterCmbBox->setCurrentByIndex(LVIT_ALL);
  440. mSearchFilter = getChild<LLFilterEditor>("look_item_filter");
  441. mSearchFilter->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onSearchEdit, this, _2));
  442. childSetAction("show_add_wearables_btn", boost::bind(&LLPanelOutfitEdit::onAddMoreButtonClicked, this));
  443. mPlusBtn = getChild<LLButton>("plus_btn");
  444. mPlusBtn->setClickedCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
  445. mEditWearableBtn = getChild<LLButton>("edit_wearable_btn");
  446. mEditWearableBtn->setEnabled(FALSE);
  447. mEditWearableBtn->setVisible(FALSE);
  448. mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this));
  449. childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
  450. /*
  451. * By default AT_CLOTHING are sorted by (in in MY OUTFITS):
  452. * - by type (types order determined in LLWearableType::EType)
  453. * - each LLWearableType::EType by outer layer on top
  454. *
  455. * In Add More panel AT_CLOTHING should be sorted in a such way:
  456. * - by type (types order determined in LLWearableType::EType)
  457. * - each LLWearableType::EType by name (EXT-8205)
  458. */
  459. mWearableListViewItemsComparator = new LLWearableItemTypeNameComparator();
  460. mWearableListViewItemsComparator->setOrder(LLAssetType::AT_CLOTHING, LLWearableItemTypeNameComparator::ORDER_RANK_1, false, true);
  461. mWearablesListViewPanel = getChild<LLPanel>("filtered_wearables_panel");
  462. mWearableItemsList = getChild<LLWearableItemsList>("list_view");
  463. mWearableItemsList->setCommitOnSelectionChange(true);
  464. mWearableItemsList->setCommitCallback(boost::bind(&LLPanelOutfitEdit::updatePlusButton, this));
  465. mWearableItemsList->setDoubleClickCallback(boost::bind(&LLPanelOutfitEdit::onPlusBtnClicked, this));
  466. mWearableItemsList->setComparator(mWearableListViewItemsComparator);
  467. // Creating "Add Wearables" panel gear menu after initialization of mWearableItemsList and mInventoryItemsPanel.
  468. mAddWearablesGearMenu = LLAddWearablesGearMenu::create(mWearableItemsList, mInventoryItemsPanel);
  469. mWearablesGearMenuBtn->setMenu(mAddWearablesGearMenu);
  470. mGearMenu = LLPanelOutfitEditGearMenu::create();
  471. mGearMenuBtn->setMenu(mGearMenu);
  472. mSaveComboBtn.reset(new LLSaveOutfitComboBtn(this));
  473. return TRUE;
  474. }
  475. // virtual
  476. void LLPanelOutfitEdit::onOpen(const LLSD& key)
  477. {
  478. if (!mInitialized)
  479. {
  480. // *TODO: this method is called even panel is not visible to user because its parent layout panel is hidden.
  481. // So, we can defer initializing a bit.
  482. mWearableListManager = new LLFilteredWearableListManager(mWearableItemsList, mListViewItemTypes[LVIT_ALL]->collector);
  483. mWearableListManager->populateList();
  484. displayCurrentOutfit();
  485. mInitialized = true;
  486. }
  487. }
  488. void LLPanelOutfitEdit::moveWearable(bool closer_to_body)
  489. {
  490. LLUUID item_id = mCOFWearables->getSelectedUUID();
  491. if (item_id.isNull()) return;
  492. LLViewerInventoryItem* wearable_to_move = gInventory.getItem(item_id);
  493. LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body);
  494. }
  495. void LLPanelOutfitEdit::toggleAddWearablesPanel()
  496. {
  497. BOOL current_visibility = mAddWearablesPanel->getVisible();
  498. showAddWearablesPanel(!current_visibility);
  499. }
  500. void LLPanelOutfitEdit::showAddWearablesPanel(bool show_add_wearables)
  501. {
  502. mAddWearablesPanel->setVisible(show_add_wearables);
  503. getChild<LLUICtrl>("show_add_wearables_btn")->setValue(show_add_wearables);
  504. updateFiltersVisibility();
  505. getChildView("filter_button")->setVisible( show_add_wearables);
  506. //search filter should be disabled
  507. if (!show_add_wearables)
  508. {
  509. getChild<LLUICtrl>("filter_button")->setValue(false);
  510. mFolderViewFilterCmbBox->setVisible(false);
  511. mListViewFilterCmbBox->setVisible(false);
  512. showWearablesFilter();
  513. /*
  514. * By default AT_CLOTHING are sorted by (in in MY OUTFITS):
  515. * - by type (types order determined in LLWearableType::EType)
  516. * - each LLWearableType::EType by outer layer on top
  517. *
  518. * In Add More panel AT_CLOTHING should be sorted in a such way:
  519. * - by type (types order determined in LLWearableType::EType)
  520. * - each LLWearableType::EType by name (EXT-8205)
  521. */
  522. mWearableItemsList->setSortOrder(LLWearableItemsList::E_SORT_BY_TYPE_NAME);
  523. // Reset mWearableItemsList position to top. See EXT-8180.
  524. mWearableItemsList->goToTop();
  525. }
  526. //switching button bars
  527. getChildView("no_add_wearables_button_bar")->setVisible( !show_add_wearables);
  528. getChildView("add_wearables_button_bar")->setVisible( show_add_wearables);
  529. }
  530. void LLPanelOutfitEdit::showWearablesFilter()
  531. {
  532. bool filter_visible = getChild<LLUICtrl>("filter_button")->getValue();
  533. getChildView("filter_panel")->setVisible( filter_visible);
  534. if(!filter_visible)
  535. {
  536. mSearchFilter->clear();
  537. onSearchEdit(LLStringUtil::null);
  538. }
  539. else
  540. {
  541. mSearchFilter->setFocus(TRUE);
  542. }
  543. }
  544. void LLPanelOutfitEdit::showWearablesListView()
  545. {
  546. if(switchPanels(mInventoryItemsPanel, mWearablesListViewPanel))
  547. {
  548. updateWearablesPanelVerbButtons();
  549. updateFiltersVisibility();
  550. }
  551. mListViewBtn->setToggleState(TRUE);
  552. }
  553. void LLPanelOutfitEdit::showWearablesFolderView()
  554. {
  555. if(switchPanels(mWearablesListViewPanel, mInventoryItemsPanel))
  556. {
  557. updateWearablesPanelVerbButtons();
  558. updateFiltersVisibility();
  559. }
  560. mFolderViewBtn->setToggleState(TRUE);
  561. }
  562. void LLPanelOutfitEdit::updateFiltersVisibility()
  563. {
  564. mListViewFilterCmbBox->setVisible(mWearablesListViewPanel->getVisible());
  565. mFolderViewFilterCmbBox->setVisible(mInventoryItemsPanel->getVisible());
  566. }
  567. void LLPanelOutfitEdit::onFolderViewFilterCommitted(LLUICtrl* ctrl)
  568. {
  569. S32 curr_filter_type = mFolderViewFilterCmbBox->getCurrentIndex();
  570. if (curr_filter_type < 0) return;
  571. mInventoryItemsPanel->setFilterTypes(mFolderViewItemTypes[curr_filter_type].inventoryMask);
  572. mSavedFolderState->setApply(TRUE);
  573. mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
  574. LLOpenFoldersWithSelection opener;
  575. mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);
  576. mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
  577. LLInventoryModelBackgroundFetch::instance().start();
  578. }
  579. void LLPanelOutfitEdit::onListViewFilterCommitted(LLUICtrl* ctrl)
  580. {
  581. S32 curr_filter_type = mListViewFilterCmbBox->getCurrentIndex();
  582. if (curr_filter_type < 0) return;
  583. mWearableListManager->setFilterCollector(mListViewItemTypes[curr_filter_type]->collector);
  584. }
  585. void LLPanelOutfitEdit::onSearchEdit(const std::string& string)
  586. {
  587. if (mSearchString != string)
  588. {
  589. mSearchString = string;
  590. // Searches are case-insensitive
  591. LLStringUtil::toUpper(mSearchString);
  592. LLStringUtil::trimHead(mSearchString);
  593. }
  594. if (mSearchString == "")
  595. {
  596. mInventoryItemsPanel->setFilterSubString(LLStringUtil::null);
  597. mWearableItemsList->setFilterSubString(LLStringUtil::null);
  598. // re-open folders that were initially open
  599. mSavedFolderState->setApply(TRUE);
  600. mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
  601. LLOpenFoldersWithSelection opener;
  602. mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(opener);
  603. mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
  604. }
  605. LLInventoryModelBackgroundFetch::instance().start();
  606. if (mInventoryItemsPanel->getFilterSubString().empty() && mSearchString.empty())
  607. {
  608. // current filter and new filter empty, do nothing
  609. return;
  610. }
  611. // save current folder open state if no filter currently applied
  612. if (mInventoryItemsPanel->getRootFolder()->getFilterSubString().empty())
  613. {
  614. mSavedFolderState->setApply(FALSE);
  615. mInventoryItemsPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
  616. }
  617. // set new filter string
  618. mInventoryItemsPanel->setFilterSubString(mSearchString);
  619. mWearableItemsList->setFilterSubString(mSearchString);
  620. }
  621. void LLPanelOutfitEdit::onPlusBtnClicked(void)
  622. {
  623. uuid_vec_t selected_items;
  624. getSelectedItemsUUID(selected_items);
  625. LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
  626. for(uuid_vec_t::iterator iter = selected_items.begin(); iter != selected_items.end(); iter++)
  627. {
  628. LLUUID selected_id = *iter;
  629. if (!selected_id.isNull())
  630. {
  631. //replacing instead of adding the item
  632. LLAppearanceMgr::getInstance()->wearItemOnAvatar(selected_id, false, true, link_waiter);
  633. }
  634. }
  635. }
  636. void LLPanelOutfitEdit::onVisibilityChange(const LLSD &in_visible_chain)
  637. {
  638. showAddWearablesPanel(false);
  639. mWearableItemsList->resetSelection();
  640. mInventoryItemsPanel->clearSelection();
  641. if (in_visible_chain.asBoolean())
  642. {
  643. update();
  644. }
  645. }
  646. void LLPanelOutfitEdit::onAddWearableClicked(void)
  647. {
  648. LLPanelDummyClothingListItem* item = dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem());
  649. if(item)
  650. {
  651. showFilteredWearablesListView(item->getWearableType());
  652. }
  653. }
  654. void LLPanelOutfitEdit::onReplaceMenuItemClicked(LLUUID selected_item_id)
  655. {
  656. LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
  657. if (item)
  658. {
  659. showFilteredWearablesListView(item->getWearableType());
  660. }
  661. }
  662. void LLPanelOutfitEdit::onShopButtonClicked()
  663. {
  664. static LLShopURLDispatcher url_resolver;
  665. // will contain the resultant URL
  666. std::string url;
  667. if (isAgentAvatarValid())
  668. {
  669. // try to get wearable type from 'Add More' panel first (EXT-7639)
  670. selection_info_t selection_info = getAddMorePanelSelectionType();
  671. LLWearableType::EType type = selection_info.first;
  672. if (selection_info.second > 1)
  673. {
  674. // the second argument is not important in this case: generic market place will be opened
  675. url = url_resolver.resolveURL(LLWearableType::WT_NONE, SEX_FEMALE);
  676. }
  677. else
  678. {
  679. if (type == LLWearableType::WT_NONE)
  680. {
  681. type = getCOFWearablesSelectionType();
  682. }
  683. ESex sex = gAgentAvatarp->getSex();
  684. // WT_INVALID comes for attachments
  685. if (type != LLWearableType::WT_INVALID && type != LLWearableType::WT_NONE)
  686. {
  687. url = url_resolver.resolveURL(type, sex);
  688. }
  689. if (url.empty())
  690. {
  691. url = url_resolver.resolveURL(
  692. mCOFWearables->getExpandedAccordionAssetType(), sex);
  693. }
  694. }
  695. }
  696. else
  697. {
  698. llwarns << "Agent avatar is invalid" << llendl;
  699. // the second argument is not important in this case: generic market place will be opened
  700. url = url_resolver.resolveURL(LLWearableType::WT_NONE, SEX_FEMALE);
  701. }
  702. LLWeb::loadURLExternal(url);
  703. }
  704. LLWearableType::EType LLPanelOutfitEdit::getCOFWearablesSelectionType() const
  705. {
  706. std::vector<LLPanel*> selected_items;
  707. LLWearableType::EType type = LLWearableType::WT_NONE;
  708. mCOFWearables->getSelectedItems(selected_items);
  709. if (selected_items.size() == 1)
  710. {
  711. LLPanel* item = selected_items.front();
  712. // LLPanelDummyClothingListItem is lower then LLPanelInventoryListItemBase in hierarchy tree
  713. if (LLPanelDummyClothingListItem* dummy_item = dynamic_cast<LLPanelDummyClothingListItem*>(item))
  714. {
  715. type = dummy_item->getWearableType();
  716. }
  717. else if (LLPanelInventoryListItemBase* real_item = dynamic_cast<LLPanelInventoryListItemBase*>(item))
  718. {
  719. type = real_item->getWearableType();
  720. }
  721. }
  722. return type;
  723. }
  724. LLPanelOutfitEdit::selection_info_t LLPanelOutfitEdit::getAddMorePanelSelectionType() const
  725. {
  726. selection_info_t result = std::make_pair(LLWearableType::WT_NONE, 0);
  727. if (mAddWearablesPanel != NULL && mAddWearablesPanel->getVisible())
  728. {
  729. if (mInventoryItemsPanel != NULL && mInventoryItemsPanel->getVisible())
  730. {
  731. std::set<LLUUID> selected_uuids = mInventoryItemsPanel->getRootFolder()->getSelectionList();
  732. result.second = selected_uuids.size();
  733. if (result.second == 1)
  734. {
  735. result.first = getWearableTypeByItemUUID(*(selected_uuids.begin()));
  736. }
  737. }
  738. else if (mWearableItemsList != NULL && mWearableItemsList->getVisible())
  739. {
  740. std::vector<LLUUID> selected_uuids;
  741. mWearableItemsList->getSelectedUUIDs(selected_uuids);
  742. result.second = selected_uuids.size();
  743. if (result.second == 1)
  744. {
  745. result.first = getWearableTypeByItemUUID(selected_uuids.front());
  746. }
  747. }
  748. }
  749. return result;
  750. }
  751. LLWearableType::EType LLPanelOutfitEdit::getWearableTypeByItemUUID(const LLUUID& item_uuid) const
  752. {
  753. LLViewerInventoryItem* item = gInventory.getLinkedItem(item_uuid);
  754. return (item != NULL) ? item->getWearableType() : LLWearableType::WT_NONE;
  755. }
  756. void LLPanelOutfitEdit::onRemoveFromOutfitClicked(void)
  757. {
  758. LLUUID id_to_remove = mCOFWearables->getSelectedUUID();
  759. LLWearableType::EType type = getWearableTypeByItemUUID(id_to_remove);
  760. LLAppearanceMgr::getInstance()->removeItemFromAvatar(id_to_remove);
  761. if (!mCOFWearables->getSelectedItem())
  762. {
  763. mCOFWearables->selectClothing(type);
  764. }
  765. }
  766. void LLPanelOutfitEdit::onEditWearableClicked(void)
  767. {
  768. LLUUID selected_item_id = mCOFWearables->getSelectedUUID();
  769. if (selected_item_id.notNull())
  770. {
  771. gAgentWearables.editWearable(selected_item_id);
  772. }
  773. }
  774. void LLPanelOutfitEdit::updatePlusButton()
  775. {
  776. uuid_vec_t selected_items;
  777. getSelectedItemsUUID(selected_items);
  778. if (selected_items.empty())
  779. {
  780. mPlusBtn->setEnabled(false);
  781. return;
  782. }
  783. // If any of the selected items are not wearable (due to already being worn OR being of the wrong type), disable the add button.
  784. uuid_vec_t::iterator unwearable_item = std::find_if(selected_items.begin(), selected_items.end(), !boost::bind(&get_can_item_be_worn, _1));
  785. bool can_add = ( unwearable_item == selected_items.end() );
  786. mPlusBtn->setEnabled(can_add);
  787. LLViewerInventoryItem* first_item(gInventory.getItem(selected_items.front()));
  788. if (can_add &&
  789. first_item &&
  790. selected_items.size() == 1 &&
  791. first_item->getType() == LLAssetType::AT_BODYPART)
  792. {
  793. mPlusBtn->setToolTip(getString("replace_body_part"));
  794. }
  795. else
  796. {
  797. mPlusBtn->setToolTip(LLStringUtil::null);
  798. }
  799. /* Removing add to look inline button (not part of mvp for viewer 2)
  800. LLRect btn_rect(current_item->getLocalRect().mRight - 50,
  801. current_item->getLocalRect().mTop,
  802. current_item->getLocalRect().mRight - 30,
  803. current_item->getLocalRect().mBottom);
  804. mAddToLookBtn->setRect(btn_rect);
  805. mAddToLookBtn->setEnabled(TRUE);
  806. if (!mAddToLookBtn->getVisible())
  807. {
  808. mAddToLookBtn->setVisible(TRUE);
  809. }
  810. current_item->addChild(mAddToLookBtn); */
  811. }
  812. void LLPanelOutfitEdit::applyFolderViewFilter(EFolderViewItemType type)
  813. {
  814. mFolderViewFilterCmbBox->setCurrentByIndex(type);
  815. mFolderViewFilterCmbBox->onCommit();
  816. }
  817. void LLPanelOutfitEdit::applyListViewFilter(EListViewItemType type)
  818. {
  819. mListViewFilterCmbBox->setCurrentByIndex(type);
  820. mListViewFilterCmbBox->onCommit();
  821. }
  822. void LLPanelOutfitEdit::filterWearablesBySelectedItem(void)
  823. {
  824. if (!mAddWearablesPanel->getVisible()) return;
  825. uuid_vec_t ids;
  826. mCOFWearables->getSelectedUUIDs(ids);
  827. bool nothing_selected = ids.empty();
  828. bool one_selected = ids.size() == 1;
  829. bool more_than_one_selected = ids.size() > 1;
  830. bool is_dummy_item = (ids.size() && dynamic_cast<LLPanelDummyClothingListItem*>(mCOFWearables->getSelectedItem()));
  831. // selected, expanded accordion tabs and selection in flat list view determine filtering when no item is selected in COF
  832. // selection in flat list view participates in determining filtering because of EXT-7963
  833. // So the priority of criterions in is:
  834. // 1. Selected accordion tab | IF (any accordion selected)
  835. // | filter_type = selected_accordion_type
  836. // 2. Selected item in flat list view | ELSEIF (any item in flat list view selected)
  837. // | filter_type = selected_item_type
  838. // 3. Expanded accordion tab | ELSEIF (any accordion expanded)
  839. // | filter_type = expanded accordion_type
  840. if (nothing_selected)
  841. {
  842. if (mInventoryItemsPanel->getVisible())
  843. {
  844. return;
  845. }
  846. showWearablesListView();
  847. //selected accordion tab is more priority than expanded tab
  848. //and selected item in flat list view of 'Add more' panel when
  849. //determining filtering
  850. LLAssetType::EType type = mCOFWearables->getSelectedAccordionAssetType();
  851. if (type == LLAssetType::AT_NONE)
  852. { //no accordion selected
  853. // when no accordion selected then selected item from flat list view
  854. // has more priority than expanded when determining filtering
  855. LLUUID selected_item_id = mWearableItemsList->getSelectedUUID();
  856. LLViewerInventoryItem* item = gInventory.getLinkedItem(selected_item_id);
  857. if(item)
  858. {
  859. showFilteredWearablesListView(item->getWearableType());
  860. return;
  861. }
  862. // when no accordion selected and no selected items in flat list view
  863. // determine filtering according to expanded accordion
  864. type = mCOFWearables->getExpandedAccordionAssetType();
  865. }
  866. switch (type)
  867. {
  868. case LLAssetType::AT_OBJECT:
  869. applyListViewFilter(LVIT_ATTACHMENT);
  870. break;
  871. case LLAssetType::AT_BODYPART:
  872. applyListViewFilter(LVIT_BODYPART);
  873. break;
  874. case LLAssetType::AT_CLOTHING:
  875. default:
  876. applyListViewFilter(LVIT_CLOTHING);
  877. break;
  878. }
  879. return;
  880. }
  881. //resetting selection if more than one item is selected
  882. if (more_than_one_selected)
  883. {
  884. if (mInventoryItemsPanel->getVisible())
  885. {
  886. applyFolderViewFilter(FVIT_ALL);
  887. return;
  888. }
  889. showWearablesListView();
  890. applyListViewFilter(LVIT_ALL);
  891. return;
  892. }
  893. //filter wearables by a type represented by a dummy item
  894. if (one_selected && is_dummy_item)
  895. {
  896. if (mInventoryItemsPanel->getVisible())
  897. {
  898. applyFolderViewFilter(FVIT_WEARABLE);
  899. return;
  900. }
  901. onAddWearableClicked();
  902. return;
  903. }
  904. LLViewerInventoryItem* item = gInventory.getItem(ids[0]);
  905. if (!item && ids[0].notNull())
  906. {
  907. if (mInventoryItemsPanel->getVisible())
  908. {
  909. applyFolderViewFilter(FVIT_ALL);
  910. return;
  911. }
  912. //Inventory misses an item with non-zero id
  913. showWearablesListView();
  914. applyListViewFilter(LVIT_ALL);
  915. return;
  916. }
  917. if (item && one_selected && !is_dummy_item)
  918. {
  919. if (item->isWearableType())
  920. {
  921. if (mInventoryItemsPanel->getVisible())
  922. {
  923. applyFolderViewFilter(FVIT_WEARABLE);
  924. return;
  925. }
  926. //single clothing or bodypart item is selected
  927. showFilteredWearablesListView(item->getWearableType());
  928. return;
  929. }
  930. else
  931. {
  932. if (mInventoryItemsPanel->getVisible())
  933. {
  934. applyFolderViewFilter(FVIT_ATTACHMENT);
  935. return;
  936. }
  937. //attachment is selected
  938. showWearablesListView();
  939. applyListViewFilter(LVIT_ATTACHMENT);
  940. return;
  941. }
  942. }
  943. }
  944. void LLPanelOutfitEdit::update()
  945. {
  946. mCOFWearables->refresh();
  947. updateVerbs();
  948. }
  949. BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  950. EDragAndDropType cargo_type,
  951. void* cargo_data,
  952. EAcceptance* accept,
  953. std::string& tooltip_msg)
  954. {
  955. if (cargo_data == NULL)
  956. {
  957. llwarns << "cargo_data is NULL" << llendl;
  958. return TRUE;
  959. }
  960. switch (cargo_type)
  961. {
  962. case DAD_BODYPART:
  963. case DAD_CLOTHING:
  964. case DAD_OBJECT:
  965. case DAD_LINK:
  966. *accept = ACCEPT_YES_MULTI;
  967. break;
  968. default:
  969. *accept = ACCEPT_NO;
  970. }
  971. if (drop)
  972. {
  973. LLInventoryItem* item = static_cast<LLInventoryItem*>(cargo_data);
  974. if (LLAssetType::lookupIsAssetIDKnowable(item->getType()))
  975. {
  976. mCOFDragAndDropObserver->watchAsset(item->getAssetUUID());
  977. /*
  978. * Adding request to wear item. If the item is a link, then getLinkedUUID() will
  979. * return the ID of the linked item. Otherwise it will return the item's ID. The
  980. * second argument is used to delay the appearance update until all dragged items
  981. * are added to optimize user experience.
  982. */
  983. LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false);
  984. }
  985. else
  986. {
  987. // if asset id is not available for the item we must wear it immediately (attachments only)
  988. LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true);
  989. }
  990. }
  991. return TRUE;
  992. }
  993. void LLPanelOutfitEdit::displayCurrentOutfit()
  994. {
  995. if (!getVisible())
  996. {
  997. setVisible(TRUE);
  998. }
  999. updateCurrentOutfitName();
  1000. update();
  1001. }
  1002. void LLPanelOutfitEdit::updateCurrentOutfitName()
  1003. {
  1004. std::string current_outfit_name;
  1005. if (LLAppearanceMgr::getInstance()->getBaseOutfitName(current_outfit_name))
  1006. {
  1007. mCurrentOutfitName->setText(current_outfit_name);
  1008. }
  1009. else
  1010. {
  1011. mCurrentOutfitName->setText(getString("No Outfit"));
  1012. }
  1013. }
  1014. //private
  1015. void LLPanelOutfitEdit::updateVerbs()
  1016. {
  1017. bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
  1018. bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked();
  1019. bool has_baseoutfit = LLAppearanceMgr::getInstance()->getBaseOutfitUUID().notNull();
  1020. mSaveComboBtn->setSaveBtnEnabled(!outfit_locked && outfit_is_dirty);
  1021. getChildView(REVERT_BTN)->setEnabled(outfit_is_dirty && has_baseoutfit);
  1022. mSaveComboBtn->setMenuItemEnabled("save_outfit", !outfit_locked && outfit_is_dirty);
  1023. mStatus->setText(outfit_is_dirty ? getString("unsaved_changes") : getString("now_editing"));
  1024. updateCurrentOutfitName();
  1025. //updating state of "Wear Item" button previously known as "Plus" button
  1026. updatePlusButton();
  1027. }
  1028. bool LLPanelOutfitEdit::switchPanels(LLPanel* switch_from_panel, LLPanel* switch_to_panel)
  1029. {
  1030. if(switch_from_panel && switch_to_panel && !switch_to_panel->getVisible())
  1031. {
  1032. switch_from_panel->setVisible(FALSE);
  1033. switch_to_panel->setVisible(TRUE);
  1034. return true;
  1035. }
  1036. return false;
  1037. }
  1038. void LLPanelOutfitEdit::resetAccordionState()
  1039. {
  1040. if (mCOFWearables != NULL)
  1041. {
  1042. mCOFWearables->expandDefaultAccordionTab();
  1043. }
  1044. else
  1045. {
  1046. llwarns << "mCOFWearables is NULL" << llendl;
  1047. }
  1048. }
  1049. void LLPanelOutfitEdit::onAddMoreButtonClicked()
  1050. {
  1051. toggleAddWearablesPanel();
  1052. filterWearablesBySelectedItem();
  1053. }
  1054. void LLPanelOutfitEdit::showFilteredWearablesListView(LLWearableType::EType type)
  1055. {
  1056. showAddWearablesPanel(true);
  1057. showWearablesListView();
  1058. //e_list_view_item_type implicitly contains LLWearableType::EType starting from LVIT_SHAPE
  1059. applyListViewFilter((EListViewItemType) (LVIT_SHAPE + type));
  1060. }
  1061. static void update_status_widget_rect(LLView * widget, S32 right_border)
  1062. {
  1063. LLRect rect = widget->getRect();
  1064. rect.mRight = right_border;
  1065. widget->setShape(rect);
  1066. }
  1067. void LLPanelOutfitEdit::onOutfitChanging(bool started)
  1068. {
  1069. static LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("edit_outfit_loading_indicator");
  1070. static LLView* status_panel = getChild<LLView>("outfit_name_and_status");
  1071. static S32 indicator_delta = status_panel->getRect().getWidth() - indicator->getRect().mLeft;
  1072. S32 delta = started ? indicator_delta : 0;
  1073. S32 right_border = status_panel->getRect().getWidth() - delta;
  1074. update_status_widget_rect(mCurrentOutfitName, right_border);
  1075. update_status_widget_rect(mStatus, right_border);
  1076. indicator->setVisible(started);
  1077. }
  1078. void LLPanelOutfitEdit::getCurrentItemUUID(LLUUID& selected_id)
  1079. {
  1080. if (mInventoryItemsPanel->getVisible())
  1081. {
  1082. LLFolderViewItem* curr_item = mInventoryItemsPanel->getRootFolder()->getCurSelectedItem();
  1083. if (!curr_item) return;
  1084. LLFolderViewEventListener* listenerp = curr_item->getListener();
  1085. if (!listenerp) return;
  1086. selected_id = listenerp->getUUID();
  1087. }
  1088. else if (mWearablesListViewPanel->getVisible())
  1089. {
  1090. selected_id = mWearableItemsList->getSelectedUUID();
  1091. }
  1092. }
  1093. void LLPanelOutfitEdit::getSelectedItemsUUID(uuid_vec_t& uuid_list)
  1094. {
  1095. void (uuid_vec_t::* tmp)(LLUUID const &) = &uuid_vec_t::push_back;
  1096. if (mInventoryItemsPanel->getVisible())
  1097. {
  1098. std::set<LLUUID> item_set = mInventoryItemsPanel->getRootFolder()->getSelectionList();
  1099. std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, _1));
  1100. }
  1101. else if (mWearablesListViewPanel->getVisible())
  1102. {
  1103. std::vector<LLSD> item_set;
  1104. mWearableItemsList->getSelectedValues(item_set);
  1105. std::for_each(item_set.begin(), item_set.end(), boost::bind( tmp, &uuid_list, boost::bind(&LLSD::asUUID, _1 )));
  1106. }
  1107. // return selected_id;
  1108. }
  1109. void LLPanelOutfitEdit::onCOFChanged()
  1110. {
  1111. //the panel is only updated when is visible to a user
  1112. // BAP - this check has to be removed because otherwise item name
  1113. // changes made when the panel is not visible will not be
  1114. // propagated to the panel.
  1115. // if (!isInVisibleChain()) return;
  1116. update();
  1117. }
  1118. void LLPanelOutfitEdit::updateWearablesPanelVerbButtons()
  1119. {
  1120. if(mWearablesListViewPanel->getVisible())
  1121. {
  1122. mFolderViewBtn->setToggleState(FALSE);
  1123. mFolderViewBtn->setImageOverlay(getString("folder_view_off"), mFolderViewBtn->getImageOverlayHAlign());
  1124. mListViewBtn->setImageOverlay(getString("list_view_on"), mListViewBtn->getImageOverlayHAlign());
  1125. }
  1126. else if(mInventoryItemsPanel->getVisible())
  1127. {
  1128. mListViewBtn->setToggleState(FALSE);
  1129. mListViewBtn->setImageOverlay(getString("list_view_off"), mListViewBtn->getImageOverlayHAlign());
  1130. mFolderViewBtn->setImageOverlay(getString("folder_view_on"), mFolderViewBtn->getImageOverlayHAlign());
  1131. }
  1132. }
  1133. void LLPanelOutfitEdit::saveListSelection()
  1134. {
  1135. if(mWearablesListViewPanel->getVisible())
  1136. {
  1137. std::set<LLUUID> selected_ids = mInventoryItemsPanel->getRootFolder()->getSelectionList();
  1138. if(!selected_ids.size()) return;
  1139. for (std::set<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id)
  1140. {
  1141. mWearableItemsList->selectItemByUUID(*item_id, true);
  1142. }
  1143. mWearableItemsList->scrollToShowFirstSelectedItem();
  1144. }
  1145. else if(mInventoryItemsPanel->getVisible())
  1146. {
  1147. std::vector<LLUUID> selected_ids;
  1148. mWearableItemsList->getSelectedUUIDs(selected_ids);
  1149. if(!selected_ids.size()) return;
  1150. mInventoryItemsPanel->clearSelection();
  1151. LLFolderView* root = mInventoryItemsPanel->getRootFolder();
  1152. if(!root) return;
  1153. for(std::vector<LLUUID>::const_iterator item_id = selected_ids.begin(); item_id != selected_ids.end(); ++item_id)
  1154. {
  1155. LLFolderViewItem* item = root->getItemByID(*item_id);
  1156. if (!item) continue;
  1157. LLFolderViewFolder* parent = item->getParentFolder();
  1158. if(parent)
  1159. {
  1160. parent->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
  1161. }
  1162. mInventoryItemsPanel->getRootFolder()->changeSelection(item, TRUE);
  1163. }
  1164. mInventoryItemsPanel->getRootFolder()->scrollToShowSelection();
  1165. }
  1166. }
  1167. // EOF