PageRenderTime 82ms CodeModel.GetById 18ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llfloaterproperties.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 905 lines | 691 code | 87 blank | 127 comment | 108 complexity | c176a35ffc8803f3224eec0556ca6d54 MD5 | raw file
  1/** 
  2 * @file llfloaterproperties.cpp
  3 * @brief A floater which shows an inventory item's properties.
  4 *
  5 * $LicenseInfo:firstyear=2002&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#include "llfloaterproperties.h"
 29
 30#include <algorithm>
 31#include <functional>
 32#include "llcachename.h"
 33#include "lldbstrings.h"
 34#include "llfloaterreg.h"
 35
 36#include "llagent.h"
 37#include "llbutton.h"
 38#include "llcheckboxctrl.h"
 39#include "llavataractions.h"
 40#include "llinventorydefines.h"
 41#include "llinventoryobserver.h"
 42#include "llinventorymodel.h"
 43#include "lllineeditor.h"
 44//#include "llspinctrl.h"
 45#include "llradiogroup.h"
 46#include "llresmgr.h"
 47#include "roles_constants.h"
 48#include "llselectmgr.h"
 49#include "lltextbox.h"
 50#include "lltrans.h"
 51#include "lluiconstants.h"
 52#include "llviewerinventory.h"
 53#include "llviewerobjectlist.h"
 54#include "llviewerregion.h"
 55#include "llviewercontrol.h"
 56#include "llviewerwindow.h"
 57#include "llgroupactions.h"
 58
 59#include "lluictrlfactory.h"
 60
 61
 62//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 63// Class LLPropertiesObserver
 64//
 65// helper class to watch the inventory. 
 66//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 67
 68// Ugh. This can't be a singleton because it needs to remove itself
 69//  from the inventory observer list when destroyed, which could
 70//  happen after gInventory has already been destroyed if a singleton.
 71// Instead, do our own ref counting and create / destroy it as needed
 72class LLPropertiesObserver : public LLInventoryObserver
 73{
 74public:
 75	LLPropertiesObserver(LLFloaterProperties* floater)
 76		: mFloater(floater)
 77	{
 78		gInventory.addObserver(this);
 79	}
 80	virtual ~LLPropertiesObserver()
 81	{
 82		gInventory.removeObserver(this);
 83	}
 84	virtual void changed(U32 mask);
 85private:
 86	LLFloaterProperties* mFloater;
 87};
 88
 89void LLPropertiesObserver::changed(U32 mask)
 90{
 91	// if there's a change we're interested in.
 92	if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
 93	{
 94		mFloater->dirty();
 95	}
 96}
 97
 98
 99
100///----------------------------------------------------------------------------
101/// Class LLFloaterProperties
102///----------------------------------------------------------------------------
103
104// Default constructor
105LLFloaterProperties::LLFloaterProperties(const LLUUID& item_id)
106  : LLFloater(mItemID),
107	mItemID(item_id),
108	mDirty(TRUE)
109{
110	mPropertiesObserver = new LLPropertiesObserver(this);
111}
112
113// Destroys the object
114LLFloaterProperties::~LLFloaterProperties()
115{
116	delete mPropertiesObserver;
117	mPropertiesObserver = NULL;
118}
119
120// virtual
121BOOL LLFloaterProperties::postBuild()
122{
123	// build the UI
124	// item name & description
125	getChild<LLLineEditor>("LabelItemName")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
126	getChild<LLUICtrl>("LabelItemName")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitName,this));
127	getChild<LLLineEditor>("LabelItemDesc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
128	getChild<LLUICtrl>("LabelItemDesc")->setCommitCallback(boost::bind(&LLFloaterProperties:: onCommitDescription, this));
129	// Creator information
130	getChild<LLUICtrl>("BtnCreator")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickCreator,this));
131	// owner information
132	getChild<LLUICtrl>("BtnOwner")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickOwner,this));
133	// acquired date
134	// owner permissions
135	// Permissions debug text
136	// group permissions
137	getChild<LLUICtrl>("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
138	// everyone permissions
139	getChild<LLUICtrl>("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
140	// next owner permissions
141	getChild<LLUICtrl>("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
142	getChild<LLUICtrl>("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
143	getChild<LLUICtrl>("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this));
144	// Mark for sale or not, and sale info
145	getChild<LLUICtrl>("CheckPurchase")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
146	getChild<LLUICtrl>("RadioSaleType")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleType, this));
147	// "Price" label for edit
148	getChild<LLUICtrl>("Edit Cost")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this));
149	// The UI has been built, now fill in all the values
150	refresh();
151
152	return TRUE;
153}
154
155// virtual
156void LLFloaterProperties::onOpen(const LLSD& key)
157{
158	refresh();
159}
160
161void LLFloaterProperties::refresh()
162{
163	LLInventoryItem* item = findItem();
164	if(item)
165	{
166		refreshFromItem(item);
167	}
168	else
169	{
170		//RN: it is possible that the container object is in the middle of an inventory refresh
171		// causing findItem() to fail, so just temporarily disable everything
172		
173		mDirty = TRUE;
174
175		const char* enableNames[]={
176			"LabelItemName",
177			"LabelItemDesc",
178			"LabelCreatorName",
179			"BtnCreator",
180			"LabelOwnerName",
181			"BtnOwner",
182			"CheckOwnerModify",
183			"CheckOwnerCopy",
184			"CheckOwnerTransfer",
185			"CheckShareWithGroup",
186			"CheckEveryoneCopy",
187			"CheckNextOwnerModify",
188			"CheckNextOwnerCopy",
189			"CheckNextOwnerTransfer",
190			"CheckPurchase",
191			"RadioSaleType",
192			"Edit Cost"
193		};
194		for(size_t t=0; t<LL_ARRAY_SIZE(enableNames); ++t)
195		{
196			getChildView(enableNames[t])->setEnabled(false);
197		}
198		const char* hideNames[]={
199			"BaseMaskDebug",
200			"OwnerMaskDebug",
201			"GroupMaskDebug",
202			"EveryoneMaskDebug",
203			"NextMaskDebug"
204		};
205		for(size_t t=0; t<LL_ARRAY_SIZE(hideNames); ++t)
206		{
207			getChildView(hideNames[t])->setVisible(false);
208		}
209	}
210}
211
212void LLFloaterProperties::draw()
213{
214	if (mDirty)
215	{
216		// RN: clear dirty first because refresh can set dirty to TRUE
217		mDirty = FALSE;
218		refresh();
219	}
220
221	LLFloater::draw();
222}
223
224void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
225{
226	////////////////////////
227	// PERMISSIONS LOOKUP //
228	////////////////////////
229
230	// do not enable the UI for incomplete items.
231	LLViewerInventoryItem* i = (LLViewerInventoryItem*)item;
232	BOOL is_complete = i->isFinished();
233	const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(i->getInventoryType());
234	const BOOL is_calling_card = (i->getInventoryType() == LLInventoryType::IT_CALLINGCARD);
235	const LLPermissions& perm = item->getPermissions();
236	const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm, 
237															GP_OBJECT_MANIPULATE);
238	const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm, 
239													  GP_OBJECT_SET_SALE) &&
240		!cannot_restrict_permissions;
241	const BOOL is_link = i->getIsLinkType();
242
243	// You need permission to modify the object to modify an inventory
244	// item in it.
245	LLViewerObject* object = NULL;
246	if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID);
247	BOOL is_obj_modify = TRUE;
248	if(object)
249	{
250		is_obj_modify = object->permOwnerModify();
251	}
252
253	//////////////////////
254	// ITEM NAME & DESC //
255	//////////////////////
256	BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm,
257											   GP_OBJECT_MANIPULATE)
258		&& is_obj_modify && is_complete;
259
260	getChildView("LabelItemNameTitle")->setEnabled(TRUE);
261	getChildView("LabelItemName")->setEnabled(is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards
262	getChild<LLUICtrl>("LabelItemName")->setValue(item->getName());
263	getChildView("LabelItemDescTitle")->setEnabled(TRUE);
264	getChildView("LabelItemDesc")->setEnabled(is_modifiable);
265	getChildView("IconLocked")->setVisible(!is_modifiable);
266	getChild<LLUICtrl>("LabelItemDesc")->setValue(item->getDescription());
267
268	//////////////////
269	// CREATOR NAME //
270	//////////////////
271	if(!gCacheName) return;
272	if(!gAgent.getRegion()) return;
273
274	if (item->getCreatorUUID().notNull())
275	{
276		std::string name;
277		gCacheName->getFullName(item->getCreatorUUID(), name);
278		getChildView("BtnCreator")->setEnabled(TRUE);
279		getChildView("LabelCreatorTitle")->setEnabled(TRUE);
280		getChildView("LabelCreatorName")->setEnabled(TRUE);
281		getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
282	}
283	else
284	{
285		getChildView("BtnCreator")->setEnabled(FALSE);
286		getChildView("LabelCreatorTitle")->setEnabled(FALSE);
287		getChildView("LabelCreatorName")->setEnabled(FALSE);
288		getChild<LLUICtrl>("LabelCreatorName")->setValue(getString("unknown"));
289	}
290
291	////////////////
292	// OWNER NAME //
293	////////////////
294	if(perm.isOwned())
295	{
296		std::string name;
297		if (perm.isGroupOwned())
298		{
299			gCacheName->getGroupName(perm.getGroup(), name);
300		}
301		else
302		{
303			gCacheName->getFullName(perm.getOwner(), name);
304		}
305		getChildView("BtnOwner")->setEnabled(TRUE);
306		getChildView("LabelOwnerTitle")->setEnabled(TRUE);
307		getChildView("LabelOwnerName")->setEnabled(TRUE);
308		getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
309	}
310	else
311	{
312		getChildView("BtnOwner")->setEnabled(FALSE);
313		getChildView("LabelOwnerTitle")->setEnabled(FALSE);
314		getChildView("LabelOwnerName")->setEnabled(FALSE);
315		getChild<LLUICtrl>("LabelOwnerName")->setValue(getString("public"));
316	}
317	
318	//////////////////
319	// ACQUIRE DATE //
320	//////////////////
321	
322	time_t time_utc = item->getCreationDate();
323	if (0 == time_utc)
324	{
325		getChild<LLUICtrl>("LabelAcquiredDate")->setValue(getString("unknown"));
326	}
327	else
328	{
329		std::string timeStr = getString("acquiredDate");
330		LLSD substitution;
331		substitution["datetime"] = (S32) time_utc;
332		LLStringUtil::format (timeStr, substitution);
333		getChild<LLUICtrl>("LabelAcquiredDate")->setValue(timeStr);
334	}
335
336	///////////////////////
337	// OWNER PERMISSIONS //
338	///////////////////////
339	if(can_agent_manipulate)
340	{
341		getChild<LLUICtrl>("OwnerLabel")->setValue(getString("you_can"));
342	}
343	else
344	{
345		getChild<LLUICtrl>("OwnerLabel")->setValue(getString("owner_can"));
346	}
347
348	U32 base_mask		= perm.getMaskBase();
349	U32 owner_mask		= perm.getMaskOwner();
350	U32 group_mask		= perm.getMaskGroup();
351	U32 everyone_mask	= perm.getMaskEveryone();
352	U32 next_owner_mask	= perm.getMaskNextOwner();
353
354	getChildView("OwnerLabel")->setEnabled(TRUE);
355	getChildView("CheckOwnerModify")->setEnabled(FALSE);
356	getChild<LLUICtrl>("CheckOwnerModify")->setValue(LLSD((BOOL)(owner_mask & PERM_MODIFY)));
357	getChildView("CheckOwnerCopy")->setEnabled(FALSE);
358	getChild<LLUICtrl>("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY)));
359	getChildView("CheckOwnerTransfer")->setEnabled(FALSE);
360	getChild<LLUICtrl>("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER)));
361
362	///////////////////////
363	// DEBUG PERMISSIONS //
364	///////////////////////
365
366	if( gSavedSettings.getBOOL("DebugPermissions") )
367	{
368		BOOL slam_perm 			= FALSE;
369		BOOL overwrite_group	= FALSE;
370		BOOL overwrite_everyone	= FALSE;
371
372		if (item->getType() == LLAssetType::AT_OBJECT)
373		{
374			U32 flags = item->getFlags();
375			slam_perm 			= flags & LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
376			overwrite_everyone	= flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
377			overwrite_group		= flags & LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
378		}
379		
380		std::string perm_string;
381
382		perm_string = "B: ";
383		perm_string += mask_to_string(base_mask);
384		getChild<LLUICtrl>("BaseMaskDebug")->setValue(perm_string);
385		getChildView("BaseMaskDebug")->setVisible(TRUE);
386		
387		perm_string = "O: ";
388		perm_string += mask_to_string(owner_mask);
389		getChild<LLUICtrl>("OwnerMaskDebug")->setValue(perm_string);
390		getChildView("OwnerMaskDebug")->setVisible(TRUE);
391		
392		perm_string = "G";
393		perm_string += overwrite_group ? "*: " : ": ";
394		perm_string += mask_to_string(group_mask);
395		getChild<LLUICtrl>("GroupMaskDebug")->setValue(perm_string);
396		getChildView("GroupMaskDebug")->setVisible(TRUE);
397		
398		perm_string = "E";
399		perm_string += overwrite_everyone ? "*: " : ": ";
400		perm_string += mask_to_string(everyone_mask);
401		getChild<LLUICtrl>("EveryoneMaskDebug")->setValue(perm_string);
402		getChildView("EveryoneMaskDebug")->setVisible(TRUE);
403		
404		perm_string = "N";
405		perm_string += slam_perm ? "*: " : ": ";
406		perm_string += mask_to_string(next_owner_mask);
407		getChild<LLUICtrl>("NextMaskDebug")->setValue(perm_string);
408		getChildView("NextMaskDebug")->setVisible(TRUE);
409	}
410	else
411	{
412		getChildView("BaseMaskDebug")->setVisible(FALSE);
413		getChildView("OwnerMaskDebug")->setVisible(FALSE);
414		getChildView("GroupMaskDebug")->setVisible(FALSE);
415		getChildView("EveryoneMaskDebug")->setVisible(FALSE);
416		getChildView("NextMaskDebug")->setVisible(FALSE);
417	}
418
419	/////////////
420	// SHARING //
421	/////////////
422
423	// Check for ability to change values.
424	if (is_link || cannot_restrict_permissions)
425	{
426		getChildView("CheckShareWithGroup")->setEnabled(FALSE);
427		getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
428	}
429	else if (is_obj_modify && can_agent_manipulate)
430	{
431		getChildView("CheckShareWithGroup")->setEnabled(TRUE);
432		getChildView("CheckEveryoneCopy")->setEnabled((owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER));
433	}
434	else
435	{
436		getChildView("CheckShareWithGroup")->setEnabled(FALSE);
437		getChildView("CheckEveryoneCopy")->setEnabled(FALSE);
438	}
439
440	// Set values.
441	BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE;
442	BOOL is_group_modify = (group_mask & PERM_MODIFY) ? TRUE : FALSE;
443	BOOL is_group_move = (group_mask & PERM_MOVE) ? TRUE : FALSE;
444
445	if (is_group_copy && is_group_modify && is_group_move)
446	{
447		getChild<LLUICtrl>("CheckShareWithGroup")->setValue(LLSD((BOOL)TRUE));
448
449		LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
450		if(ctl)
451		{
452			ctl->setTentative(FALSE);
453		}
454	}
455	else if (!is_group_copy && !is_group_modify && !is_group_move)
456	{
457		getChild<LLUICtrl>("CheckShareWithGroup")->setValue(LLSD((BOOL)FALSE));
458		LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
459		if(ctl)
460		{
461			ctl->setTentative(FALSE);
462		}
463	}
464	else
465	{
466		LLCheckBoxCtrl* ctl = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
467		if(ctl)
468		{
469			ctl->setTentative(TRUE);
470			ctl->set(TRUE);
471		}
472	}
473	
474	getChild<LLUICtrl>("CheckEveryoneCopy")->setValue(LLSD((BOOL)(everyone_mask & PERM_COPY)));
475
476	///////////////
477	// SALE INFO //
478	///////////////
479
480	const LLSaleInfo& sale_info = item->getSaleInfo();
481	BOOL is_for_sale = sale_info.isForSale();
482	// Check for ability to change values.
483	if (is_obj_modify && can_agent_sell 
484		&& gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE))
485	{
486		getChildView("SaleLabel")->setEnabled(is_complete);
487		getChildView("CheckPurchase")->setEnabled(is_complete);
488
489		getChildView("NextOwnerLabel")->setEnabled(TRUE);
490		getChildView("CheckNextOwnerModify")->setEnabled((base_mask & PERM_MODIFY) && !cannot_restrict_permissions);
491		getChildView("CheckNextOwnerCopy")->setEnabled((base_mask & PERM_COPY) && !cannot_restrict_permissions);
492		getChildView("CheckNextOwnerTransfer")->setEnabled((next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
493
494		getChildView("RadioSaleType")->setEnabled(is_complete && is_for_sale);
495		getChildView("TextPrice")->setEnabled(is_complete && is_for_sale);
496		getChildView("Edit Cost")->setEnabled(is_complete && is_for_sale);
497	}
498	else
499	{
500		getChildView("SaleLabel")->setEnabled(FALSE);
501		getChildView("CheckPurchase")->setEnabled(FALSE);
502
503		getChildView("NextOwnerLabel")->setEnabled(FALSE);
504		getChildView("CheckNextOwnerModify")->setEnabled(FALSE);
505		getChildView("CheckNextOwnerCopy")->setEnabled(FALSE);
506		getChildView("CheckNextOwnerTransfer")->setEnabled(FALSE);
507
508		getChildView("RadioSaleType")->setEnabled(FALSE);
509		getChildView("TextPrice")->setEnabled(FALSE);
510		getChildView("Edit Cost")->setEnabled(FALSE);
511	}
512
513	// Set values.
514	getChild<LLUICtrl>("CheckPurchase")->setValue(is_for_sale);
515	getChildView("combobox sale copy")->setEnabled(is_for_sale);
516	getChildView("Edit Cost")->setEnabled(is_for_sale);
517	getChild<LLUICtrl>("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY)));
518	getChild<LLUICtrl>("CheckNextOwnerCopy")->setValue(LLSD(BOOL(next_owner_mask & PERM_COPY)));
519	getChild<LLUICtrl>("CheckNextOwnerTransfer")->setValue(LLSD(BOOL(next_owner_mask & PERM_TRANSFER)));
520
521	LLRadioGroup* radioSaleType = getChild<LLRadioGroup>("RadioSaleType");
522	if (is_for_sale)
523	{
524		radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1);
525		S32 numerical_price;
526		numerical_price = sale_info.getSalePrice();
527		getChild<LLUICtrl>("Edit Cost")->setValue(llformat("%d",numerical_price));
528	}
529	else
530	{
531		radioSaleType->setSelectedIndex(-1);
532		getChild<LLUICtrl>("Edit Cost")->setValue(llformat("%d",0));
533	}
534}
535
536void LLFloaterProperties::onClickCreator()
537{
538	LLInventoryItem* item = findItem();
539	if(!item) return;
540	if(!item->getCreatorUUID().isNull())
541	{
542		LLAvatarActions::showProfile(item->getCreatorUUID());
543	}
544}
545
546// static
547void LLFloaterProperties::onClickOwner()
548{
549	LLInventoryItem* item = findItem();
550	if(!item) return;
551	if(item->getPermissions().isGroupOwned())
552	{
553		LLGroupActions::show(item->getPermissions().getGroup());
554	}
555	else
556	{
557		LLAvatarActions::showProfile(item->getPermissions().getOwner());
558	}
559}
560
561// static
562void LLFloaterProperties::onCommitName()
563{
564	//llinfos << "LLFloaterProperties::onCommitName()" << llendl;
565	LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
566	if(!item)
567	{
568		return;
569	}
570	LLLineEditor* labelItemName = getChild<LLLineEditor>("LabelItemName");
571
572	if(labelItemName&&
573	   (item->getName() != labelItemName->getText()) && 
574	   (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) )
575	{
576		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
577		new_item->rename(labelItemName->getText());
578		if(mObjectID.isNull())
579		{
580			new_item->updateServer(FALSE);
581			gInventory.updateItem(new_item);
582			gInventory.notifyObservers();
583		}
584		else
585		{
586			LLViewerObject* object = gObjectList.findObject(mObjectID);
587			if(object)
588			{
589				object->updateInventory(
590					new_item,
591					TASK_INVENTORY_ITEM_KEY,
592					false);
593			}
594		}
595	}
596}
597
598void LLFloaterProperties::onCommitDescription()
599{
600	//llinfos << "LLFloaterProperties::onCommitDescription()" << llendl;
601	LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
602	if(!item) return;
603
604	LLLineEditor* labelItemDesc = getChild<LLLineEditor>("LabelItemDesc");
605	if(!labelItemDesc)
606	{
607		return;
608	}
609	if((item->getDescription() != labelItemDesc->getText()) && 
610	   (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)))
611	{
612		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
613
614		new_item->setDescription(labelItemDesc->getText());
615		if(mObjectID.isNull())
616		{
617			new_item->updateServer(FALSE);
618			gInventory.updateItem(new_item);
619			gInventory.notifyObservers();
620		}
621		else
622		{
623			LLViewerObject* object = gObjectList.findObject(mObjectID);
624			if(object)
625			{
626				object->updateInventory(
627					new_item,
628					TASK_INVENTORY_ITEM_KEY,
629					false);
630			}
631		}
632	}
633}
634
635// static
636void LLFloaterProperties::onCommitPermissions()
637{
638	//llinfos << "LLFloaterProperties::onCommitPermissions()" << llendl;
639	LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
640	if(!item) return;
641	LLPermissions perm(item->getPermissions());
642
643
644	LLCheckBoxCtrl* CheckShareWithGroup = getChild<LLCheckBoxCtrl>("CheckShareWithGroup");
645
646	if(CheckShareWithGroup)
647	{
648		perm.setGroupBits(gAgent.getID(), gAgent.getGroupID(),
649						CheckShareWithGroup->get(),
650						PERM_MODIFY | PERM_MOVE | PERM_COPY);
651	}
652	LLCheckBoxCtrl* CheckEveryoneCopy = getChild<LLCheckBoxCtrl>("CheckEveryoneCopy");
653	if(CheckEveryoneCopy)
654	{
655		perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(),
656						 CheckEveryoneCopy->get(), PERM_COPY);
657	}
658
659	LLCheckBoxCtrl* CheckNextOwnerModify = getChild<LLCheckBoxCtrl>("CheckNextOwnerModify");
660	if(CheckNextOwnerModify)
661	{
662		perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
663							CheckNextOwnerModify->get(), PERM_MODIFY);
664	}
665	LLCheckBoxCtrl* CheckNextOwnerCopy = getChild<LLCheckBoxCtrl>("CheckNextOwnerCopy");
666	if(CheckNextOwnerCopy)
667	{
668		perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
669							CheckNextOwnerCopy->get(), PERM_COPY);
670	}
671	LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild<LLCheckBoxCtrl>("CheckNextOwnerTransfer");
672	if(CheckNextOwnerTransfer)
673	{
674		perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
675							CheckNextOwnerTransfer->get(), PERM_TRANSFER);
676	}
677	if(perm != item->getPermissions()
678		&& item->isFinished())
679	{
680		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
681		new_item->setPermissions(perm);
682		U32 flags = new_item->getFlags();
683		// If next owner permissions have changed (and this is an object)
684		// then set the slam permissions flag so that they are applied on rez.
685		if((perm.getMaskNextOwner()!=item->getPermissions().getMaskNextOwner())
686		   && (item->getType() == LLAssetType::AT_OBJECT))
687		{
688			flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_PERM;
689		}
690		// If everyone permissions have changed (and this is an object)
691		// then set the overwrite everyone permissions flag so they
692		// are applied on rez.
693		if ((perm.getMaskEveryone()!=item->getPermissions().getMaskEveryone())
694			&& (item->getType() == LLAssetType::AT_OBJECT))
695		{
696			flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
697		}
698		// If group permissions have changed (and this is an object)
699		// then set the overwrite group permissions flag so they
700		// are applied on rez.
701		if ((perm.getMaskGroup()!=item->getPermissions().getMaskGroup())
702			&& (item->getType() == LLAssetType::AT_OBJECT))
703		{
704			flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
705		}
706		new_item->setFlags(flags);
707		if(mObjectID.isNull())
708		{
709			new_item->updateServer(FALSE);
710			gInventory.updateItem(new_item);
711			gInventory.notifyObservers();
712		}
713		else
714		{
715			LLViewerObject* object = gObjectList.findObject(mObjectID);
716			if(object)
717			{
718				object->updateInventory(
719					new_item,
720					TASK_INVENTORY_ITEM_KEY,
721					false);
722			}
723		}
724	}
725	else
726	{
727		// need to make sure we don't just follow the click
728		refresh();
729	}
730}
731
732// static
733void LLFloaterProperties::onCommitSaleInfo()
734{
735	//llinfos << "LLFloaterProperties::onCommitSaleInfo()" << llendl;
736	updateSaleInfo();
737}
738
739// static
740void LLFloaterProperties::onCommitSaleType()
741{
742	//llinfos << "LLFloaterProperties::onCommitSaleType()" << llendl;
743	updateSaleInfo();
744}
745
746void LLFloaterProperties::updateSaleInfo()
747{
748	LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem();
749	if(!item) return;
750	LLSaleInfo sale_info(item->getSaleInfo());
751	if(!gAgent.allowOperation(PERM_TRANSFER, item->getPermissions(), GP_OBJECT_SET_SALE))
752	{
753		getChild<LLUICtrl>("CheckPurchase")->setValue(LLSD((BOOL)FALSE));
754	}
755
756	if((BOOL)getChild<LLUICtrl>("CheckPurchase")->getValue())
757	{
758		// turn on sale info
759		LLSaleInfo::EForSale sale_type = LLSaleInfo::FS_COPY;
760	
761		LLRadioGroup* RadioSaleType = getChild<LLRadioGroup>("RadioSaleType");
762		if(RadioSaleType)
763		{
764			switch (RadioSaleType->getSelectedIndex())
765			{
766			case 0:
767				sale_type = LLSaleInfo::FS_ORIGINAL;
768				break;
769			case 1:
770				sale_type = LLSaleInfo::FS_COPY;
771				break;
772			case 2:
773				sale_type = LLSaleInfo::FS_CONTENTS;
774				break;
775			default:
776				sale_type = LLSaleInfo::FS_COPY;
777				break;
778			}
779		}
780
781		if (sale_type == LLSaleInfo::FS_COPY 
782			&& !gAgent.allowOperation(PERM_COPY, item->getPermissions(), 
783									  GP_OBJECT_SET_SALE))
784		{
785			sale_type = LLSaleInfo::FS_ORIGINAL;
786		}
787
788	     
789		
790		S32 price = -1;
791		price =  getChild<LLUICtrl>("Edit Cost")->getValue().asInteger();;
792
793		// Invalid data - turn off the sale
794		if (price < 0)
795		{
796			sale_type = LLSaleInfo::FS_NOT;
797			price = 0;
798		}
799
800		sale_info.setSaleType(sale_type);
801		sale_info.setSalePrice(price);
802	}
803	else
804	{
805		sale_info.setSaleType(LLSaleInfo::FS_NOT);
806	}
807	if(sale_info != item->getSaleInfo()
808		&& item->isFinished())
809	{
810		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
811
812		// Force an update on the sale price at rez
813		if (item->getType() == LLAssetType::AT_OBJECT)
814		{
815			U32 flags = new_item->getFlags();
816			flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_SLAM_SALE;
817			new_item->setFlags(flags);
818		}
819
820		new_item->setSaleInfo(sale_info);
821		if(mObjectID.isNull())
822		{
823			// This is in the agent's inventory.
824			new_item->updateServer(FALSE);
825			gInventory.updateItem(new_item);
826			gInventory.notifyObservers();
827		}
828		else
829		{
830			// This is in an object's contents.
831			LLViewerObject* object = gObjectList.findObject(mObjectID);
832			if(object)
833			{
834				object->updateInventory(
835					new_item,
836					TASK_INVENTORY_ITEM_KEY,
837					false);
838			}
839		}
840	}
841	else
842	{
843		// need to make sure we don't just follow the click
844		refresh();
845	}
846}
847
848LLInventoryItem* LLFloaterProperties::findItem() const
849{
850	LLInventoryItem* item = NULL;
851	if(mObjectID.isNull())
852	{
853		// it is in agent inventory
854		item = gInventory.getItem(mItemID);
855	}
856	else
857	{
858		LLViewerObject* object = gObjectList.findObject(mObjectID);
859		if(object)
860		{
861			item = (LLInventoryItem*)object->getInventoryObject(mItemID);
862		}
863	}
864	return item;
865}
866
867//static
868void LLFloaterProperties::dirtyAll()
869{
870	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("properties");
871	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
872		 iter != inst_list.end(); ++iter)
873	{
874		LLFloaterProperties* floater = dynamic_cast<LLFloaterProperties*>(*iter);
875		llassert(floater); // else cast failed - wrong type D:
876		if (floater)
877		{
878			floater->dirty();
879		}
880	}
881}
882
883///----------------------------------------------------------------------------
884/// LLMultiProperties
885///----------------------------------------------------------------------------
886
887LLMultiProperties::LLMultiProperties()
888	: LLMultiFloater(LLSD())
889{
890	// start with a small rect in the top-left corner ; will get resized
891	LLRect rect;
892	rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 20, 20);
893	setRect(rect);
894	LLFloater* last_floater = LLFloaterReg::getLastFloaterInGroup("properties");
895	if (last_floater)
896	{
897		stackWith(*last_floater);
898	}
899	setTitle(LLTrans::getString("MultiPropertiesTitle"));
900	buildTabContainer();
901}
902
903///----------------------------------------------------------------------------
904/// Local function definitions
905///----------------------------------------------------------------------------