PageRenderTime 427ms CodeModel.GetById 161ms app.highlight 108ms RepoModel.GetById 154ms app.codeStats 0ms

/indra/newview/llpanelwearing.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 307 lines | 199 code | 64 blank | 44 comment | 36 complexity | 4c897c6444492562fedd9f8141bcd25a MD5 | raw file
  1/**
  2 * @file llpanelwearing.cpp
  3 * @brief List of agent's worn items.
  4 *
  5 * $LicenseInfo:firstyear=2010&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
 27#include "llviewerprecompiledheaders.h"
 28
 29#include "llpanelwearing.h"
 30
 31#include "lltoggleablemenu.h"
 32
 33#include "llappearancemgr.h"
 34#include "llfloatersidepanelcontainer.h"
 35#include "llinventoryfunctions.h"
 36#include "llinventorymodel.h"
 37#include "llinventoryobserver.h"
 38#include "llmenubutton.h"
 39#include "llviewermenu.h"
 40#include "llwearableitemslist.h"
 41#include "llsdserialize.h"
 42#include "llclipboard.h"
 43
 44// Context menu and Gear menu helper.
 45static void edit_outfit()
 46{
 47	LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "edit_outfit"));
 48}
 49
 50//////////////////////////////////////////////////////////////////////////
 51
 52class LLWearingGearMenu
 53{
 54public:
 55	LLWearingGearMenu(LLPanelWearing* panel_wearing)
 56	:	mMenu(NULL), mPanelWearing(panel_wearing)
 57	{
 58		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 59		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
 60
 61		registrar.add("Gear.Edit", boost::bind(&edit_outfit));
 62		registrar.add("Gear.TakeOff", boost::bind(&LLWearingGearMenu::onTakeOff, this));
 63		registrar.add("Gear.Copy", boost::bind(&LLPanelWearing::copyToClipboard, mPanelWearing));
 64
 65		enable_registrar.add("Gear.OnEnable", boost::bind(&LLPanelWearing::isActionEnabled, mPanelWearing, _2));
 66
 67		mMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
 68			"menu_wearing_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 69		llassert(mMenu);
 70	}
 71
 72	LLToggleableMenu* getMenu() { return mMenu; }
 73
 74private:
 75
 76	void onTakeOff()
 77	{
 78		uuid_vec_t selected_uuids;
 79		mPanelWearing->getSelectedItemsUUIDs(selected_uuids);
 80
 81		for (uuid_vec_t::const_iterator it=selected_uuids.begin(); it != selected_uuids.end(); ++it)
 82		{
 83				LLAppearanceMgr::instance().removeItemFromAvatar(*it);
 84		}
 85	}
 86
 87	LLToggleableMenu*		mMenu;
 88	LLPanelWearing* 		mPanelWearing;
 89};
 90
 91//////////////////////////////////////////////////////////////////////////
 92
 93class LLWearingContextMenu : public LLListContextMenu
 94{
 95protected:
 96	/* virtual */ LLContextMenu* createMenu()
 97	{
 98		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 99
100		functor_t take_off = boost::bind(&LLAppearanceMgr::removeItemFromAvatar, LLAppearanceMgr::getInstance(), _1);
101
102		registrar.add("Wearing.Edit", boost::bind(&edit_outfit));
103		registrar.add("Wearing.TakeOff", boost::bind(handleMultiple, take_off, mUUIDs));
104		registrar.add("Wearing.Detach", boost::bind(handleMultiple, take_off, mUUIDs));
105
106		LLContextMenu* menu = createFromFile("menu_wearing_tab.xml");
107
108		updateMenuItemsVisibility(menu);
109
110		return menu;
111	}
112
113	void updateMenuItemsVisibility(LLContextMenu* menu)
114	{
115		bool bp_selected			= false;	// true if body parts selected
116		bool clothes_selected		= false;
117		bool attachments_selected	= false;
118
119		// See what types of wearables are selected.
120		for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it)
121		{
122			LLViewerInventoryItem* item = gInventory.getItem(*it);
123
124			if (!item)
125			{
126				llwarns << "Invalid item" << llendl;
127				continue;
128			}
129
130			LLAssetType::EType type = item->getType();
131			if (type == LLAssetType::AT_CLOTHING)
132			{
133				clothes_selected = true;
134			}
135			else if (type == LLAssetType::AT_BODYPART)
136			{
137				bp_selected = true;
138			}
139			else if (type == LLAssetType::AT_OBJECT)
140			{
141				attachments_selected = true;
142			}
143		}
144
145		// Enable/disable some menu items depending on the selection.
146		bool allow_detach = !bp_selected && !clothes_selected && attachments_selected;
147		bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected;
148
149		menu->setItemVisible("take_off",	allow_take_off);
150		menu->setItemVisible("detach",		allow_detach);
151		menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach);
152	}
153};
154
155//////////////////////////////////////////////////////////////////////////
156
157std::string LLPanelAppearanceTab::sFilterSubString = LLStringUtil::null;
158
159static LLRegisterPanelClassWrapper<LLPanelWearing> t_panel_wearing("panel_wearing");
160
161LLPanelWearing::LLPanelWearing()
162	:	LLPanelAppearanceTab()
163	,	mCOFItemsList(NULL)
164	,	mIsInitialized(false)
165{
166	mCategoriesObserver = new LLInventoryCategoriesObserver();
167
168	mGearMenu = new LLWearingGearMenu(this);
169	mContextMenu = new LLWearingContextMenu();
170}
171
172LLPanelWearing::~LLPanelWearing()
173{
174	delete mGearMenu;
175	delete mContextMenu;
176
177	if (gInventory.containsObserver(mCategoriesObserver))
178	{
179		gInventory.removeObserver(mCategoriesObserver);
180	}
181	delete mCategoriesObserver;
182}
183
184BOOL LLPanelWearing::postBuild()
185{
186	mCOFItemsList = getChild<LLWearableItemsList>("cof_items_list");
187	mCOFItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onWearableItemsListRightClick, this, _1, _2, _3));
188
189	LLMenuButton* menu_gear_btn = getChild<LLMenuButton>("options_gear_btn");
190
191	menu_gear_btn->setMenu(mGearMenu->getMenu());
192
193	return TRUE;
194}
195
196//virtual
197void LLPanelWearing::onOpen(const LLSD& /*info*/)
198{
199	if (!mIsInitialized)
200	{
201		// *TODO: I'm not sure is this check necessary but it never match while developing.
202		if (!gInventory.isInventoryUsable())
203			return;
204
205		const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
206
207		// *TODO: I'm not sure is this check necessary but it never match while developing.
208		LLViewerInventoryCategory* category = gInventory.getCategory(cof);
209		if (!category)
210			return;
211
212		gInventory.addObserver(mCategoriesObserver);
213
214		// Start observing changes in Current Outfit category.
215		mCategoriesObserver->addCategory(cof, boost::bind(&LLWearableItemsList::updateList, mCOFItemsList, cof));
216
217		// Fetch Current Outfit contents and refresh the list to display
218		// initially fetched items. If not all items are fetched now
219		// the observer will refresh the list as soon as the new items
220		// arrive.
221		category->fetch();
222
223		mCOFItemsList->updateList(cof);
224
225		mIsInitialized = true;
226	}
227}
228
229// virtual
230void LLPanelWearing::setFilterSubString(const std::string& string)
231{
232	sFilterSubString = string;
233	mCOFItemsList->setFilterSubString(sFilterSubString);
234}
235
236// virtual
237bool LLPanelWearing::isActionEnabled(const LLSD& userdata)
238{
239	const std::string command_name = userdata.asString();
240
241	if (command_name == "save_outfit")
242	{
243		bool outfit_locked = LLAppearanceMgr::getInstance()->isOutfitLocked();
244		bool outfit_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
245		// allow save only if outfit isn't locked and is dirty
246		return !outfit_locked && outfit_dirty;
247	}
248
249	if (command_name == "take_off")
250	{
251		return hasItemSelected() && canTakeOffSelected();
252	}
253
254	return false;
255}
256
257boost::signals2::connection LLPanelWearing::setSelectionChangeCallback(commit_callback_t cb)
258{
259	if (!mCOFItemsList) return boost::signals2::connection();
260
261	return mCOFItemsList->setCommitCallback(cb);
262}
263
264void LLPanelWearing::onWearableItemsListRightClick(LLUICtrl* ctrl, S32 x, S32 y)
265{
266	LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl);
267	if (!list) return;
268
269	uuid_vec_t selected_uuids;
270
271	list->getSelectedUUIDs(selected_uuids);
272
273	mContextMenu->show(ctrl, selected_uuids, x, y);
274}
275
276bool LLPanelWearing::hasItemSelected()
277{
278	return mCOFItemsList->getSelectedItem() != NULL;
279}
280
281void LLPanelWearing::getSelectedItemsUUIDs(uuid_vec_t& selected_uuids) const
282{
283	mCOFItemsList->getSelectedUUIDs(selected_uuids);
284}
285
286void LLPanelWearing::copyToClipboard()
287{
288	std::string text;
289	std::vector<LLSD> data;
290	mCOFItemsList->getValues(data);
291
292	for(std::vector<LLSD>::const_iterator iter = data.begin(); iter != data.end();)
293	{
294		LLSD uuid = (*iter);
295		LLViewerInventoryItem* item = gInventory.getItem(uuid);
296
297		iter++;
298		if (item != NULL)
299		{
300			// Append a newline to all but the last line
301			text += iter != data.end() ? item->getName() + "\n" : item->getName();
302		}
303	}
304
305	gClipboard.copyFromString(utf8str_to_wstring(text));
306}
307// EOF