diff options
Diffstat (limited to 'indra')
22 files changed, 950 insertions, 330 deletions
| diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 6715b6722d..e4102a622d 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -46,7 +46,8 @@ struct AssetEntry : public LLDictionaryEntry  			   const char *type_name, // 8 character limit!  			   const char *human_name,  			   const char *category_name, // used by llinventorymodel when creating new categories -			   EDragAndDropType dad_type); +			   EDragAndDropType dad_type, +			   bool can_link);  	// limited to 8 characters  	const char *mTypeName; @@ -55,6 +56,7 @@ struct AssetEntry : public LLDictionaryEntry  	const char *mHumanName;  	const char *mCategoryName;  	EDragAndDropType mDadType; +	bool mCanLink;  };  class LLAssetDictionary : public LLSingleton<LLAssetDictionary>, @@ -66,44 +68,49 @@ public:  LLAssetDictionary::LLAssetDictionary()  { -	addEntry(LLAssetType::AT_TEXTURE, 			new AssetEntry("TEXTURE",			"texture",	"texture",			"Textures", 		DAD_TEXTURE)); -	addEntry(LLAssetType::AT_SOUND, 			new AssetEntry("SOUND",				"sound",	"sound",			"Sounds", 			DAD_SOUND)); -	addEntry(LLAssetType::AT_CALLINGCARD, 		new AssetEntry("CALLINGCARD",		"callcard",	"calling card",		"Calling Cards", 	DAD_CALLINGCARD)); -	addEntry(LLAssetType::AT_LANDMARK, 			new AssetEntry("LANDMARK",			"landmark",	"landmark",			"Landmarks", 		DAD_LANDMARK)); -	addEntry(LLAssetType::AT_SCRIPT, 			new AssetEntry("SCRIPT",			"script",	"legacy script",	"Scripts", 			DAD_NONE)); -	addEntry(LLAssetType::AT_CLOTHING, 			new AssetEntry("CLOTHING",			"clothing",	"clothing",			"Clothing", 		DAD_CLOTHING)); -	addEntry(LLAssetType::AT_OBJECT, 			new AssetEntry("OBJECT",			"object",	"object",			"Objects", 			DAD_OBJECT)); -	addEntry(LLAssetType::AT_NOTECARD, 			new AssetEntry("NOTECARD",			"notecard",	"note card",		"Notecards", 		DAD_NOTECARD)); -	addEntry(LLAssetType::AT_CATEGORY, 			new AssetEntry("CATEGORY",			"category",	"folder",			"New Folder", 		DAD_CATEGORY)); -	addEntry(LLAssetType::AT_ROOT_CATEGORY, 	new AssetEntry("ROOT_CATEGORY",		"root",		"root",				"Inventory", 		DAD_ROOT_CATEGORY)); -	addEntry(LLAssetType::AT_LSL_TEXT, 			new AssetEntry("LSL_TEXT",			"lsltext",	"lsl2 script",		"Scripts", 			DAD_SCRIPT)); -	addEntry(LLAssetType::AT_LSL_BYTECODE, 		new AssetEntry("LSL_BYTECODE",		"lslbyte",	"lsl bytecode",		"Scripts", 			DAD_NONE)); -	addEntry(LLAssetType::AT_TEXTURE_TGA, 		new AssetEntry("TEXTURE_TGA",		"txtr_tga",	"tga texture",		"Uncompressed Images", DAD_NONE)); -	addEntry(LLAssetType::AT_BODYPART, 			new AssetEntry("BODYPART",			"bodypart",	"body part",		"Body Parts", 		DAD_BODYPART)); -	addEntry(LLAssetType::AT_TRASH, 			new AssetEntry("TRASH",				"trash",	"trash",			"Trash", 			DAD_NONE)); -	addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot",	"snapshot",			"Photo Album", 		DAD_NONE)); -	addEntry(LLAssetType::AT_LOST_AND_FOUND, 	new AssetEntry("LOST_AND_FOUND", 	"lstndfnd",	"lost and found",	"Lost And Found", 	DAD_NONE)); -	addEntry(LLAssetType::AT_SOUND_WAV, 		new AssetEntry("SOUND_WAV",			"snd_wav",	"sound",			"Uncompressed Sounds", DAD_NONE)); -	addEntry(LLAssetType::AT_IMAGE_TGA, 		new AssetEntry("IMAGE_TGA",			"img_tga",	"targa image",		"Uncompressed Images", DAD_NONE)); -	addEntry(LLAssetType::AT_IMAGE_JPEG, 		new AssetEntry("IMAGE_JPEG",		"jpeg",		"jpeg image",		"Uncompressed Images", DAD_NONE)); -	addEntry(LLAssetType::AT_ANIMATION, 		new AssetEntry("ANIMATION",			"animatn",	"animation",		"Animations", 		DAD_ANIMATION)); -	addEntry(LLAssetType::AT_GESTURE, 			new AssetEntry("GESTURE",			"gesture",	"gesture",			"Gestures", 		DAD_GESTURE)); -	addEntry(LLAssetType::AT_SIMSTATE, 			new AssetEntry("SIMSTATE",			"simstate",	"simstate",			"New Folder", 		DAD_NONE)); -	addEntry(LLAssetType::AT_LINK, 				new AssetEntry("LINK",				"link",		"symbolic  link",	"New Folder", 		DAD_NONE)); -	addEntry(LLAssetType::AT_FAVORITE, 			new AssetEntry("FAVORITE",			"favorite",	"favorite",			"favorite", 		DAD_NONE)); -	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		"New Folder", 		DAD_NONE)); +	addEntry(LLAssetType::AT_TEXTURE, 			new AssetEntry("TEXTURE",			"texture",	"texture",			"Textures", 		DAD_TEXTURE,	FALSE)); +	addEntry(LLAssetType::AT_SOUND, 			new AssetEntry("SOUND",				"sound",	"sound",			"Sounds", 			DAD_SOUND,		FALSE)); +	addEntry(LLAssetType::AT_CALLINGCARD, 		new AssetEntry("CALLINGCARD",		"callcard",	"calling card",		"Calling Cards", 	DAD_CALLINGCARD, FALSE)); +	addEntry(LLAssetType::AT_LANDMARK, 			new AssetEntry("LANDMARK",			"landmark",	"landmark",			"Landmarks", 		DAD_LANDMARK,	FALSE)); +	addEntry(LLAssetType::AT_SCRIPT, 			new AssetEntry("SCRIPT",			"script",	"legacy script",	"Scripts", 			DAD_NONE,		FALSE)); +	addEntry(LLAssetType::AT_CLOTHING, 			new AssetEntry("CLOTHING",			"clothing",	"clothing",			"Clothing", 		DAD_CLOTHING,	TRUE)); +	addEntry(LLAssetType::AT_OBJECT, 			new AssetEntry("OBJECT",			"object",	"object",			"Objects", 			DAD_OBJECT,		TRUE)); +	addEntry(LLAssetType::AT_NOTECARD, 			new AssetEntry("NOTECARD",			"notecard",	"note card",		"Notecards", 		DAD_NOTECARD,	FALSE)); +	addEntry(LLAssetType::AT_CATEGORY, 			new AssetEntry("CATEGORY",			"category",	"folder",			"New Folder", 		DAD_CATEGORY,	TRUE)); +	addEntry(LLAssetType::AT_ROOT_CATEGORY, 	new AssetEntry("ROOT_CATEGORY",		"root",		"root",				"Inventory", 		DAD_ROOT_CATEGORY, TRUE)); +	addEntry(LLAssetType::AT_LSL_TEXT, 			new AssetEntry("LSL_TEXT",			"lsltext",	"lsl2 script",		"Scripts", 			DAD_SCRIPT,		FALSE)); +	addEntry(LLAssetType::AT_LSL_BYTECODE, 		new AssetEntry("LSL_BYTECODE",		"lslbyte",	"lsl bytecode",		"Scripts", 			DAD_NONE,		FALSE)); +	addEntry(LLAssetType::AT_TEXTURE_TGA, 		new AssetEntry("TEXTURE_TGA",		"txtr_tga",	"tga texture",		"Uncompressed Images", DAD_NONE,	FALSE)); +	addEntry(LLAssetType::AT_BODYPART, 			new AssetEntry("BODYPART",			"bodypart",	"body part",		"Body Parts", 		DAD_BODYPART,	TRUE)); +	addEntry(LLAssetType::AT_TRASH, 			new AssetEntry("TRASH",				"trash",	"trash",			"Trash", 			DAD_NONE,		FALSE)); +	addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot",	"snapshot",			"Photo Album", 		DAD_NONE,		FALSE)); +	addEntry(LLAssetType::AT_LOST_AND_FOUND, 	new AssetEntry("LOST_AND_FOUND", 	"lstndfnd",	"lost and found",	"Lost And Found", 	DAD_NONE,		FALSE)); +	addEntry(LLAssetType::AT_SOUND_WAV, 		new AssetEntry("SOUND_WAV",			"snd_wav",	"sound",			"Uncompressed SoundS", DAD_NONE,	FALSE)); +	addEntry(LLAssetType::AT_IMAGE_TGA, 		new AssetEntry("IMAGE_TGA",			"img_tga",	"targa image",		"Uncompressed Images", DAD_NONE,	FALSE)); +	addEntry(LLAssetType::AT_IMAGE_JPEG, 		new AssetEntry("IMAGE_JPEG",		"jpeg",		"jpeg image",		"Uncompressed Images", DAD_NONE,	FALSE)); +	addEntry(LLAssetType::AT_ANIMATION, 		new AssetEntry("ANIMATION",			"animatn",	"animation",		"Animations", 		DAD_ANIMATION,	FALSE)); +	addEntry(LLAssetType::AT_GESTURE, 			new AssetEntry("GESTURE",			"gesture",	"gesture",			"Gestures", 		DAD_GESTURE,	FALSE)); +	addEntry(LLAssetType::AT_SIMSTATE, 			new AssetEntry("SIMSTATE",			"simstate",	"simstate",			"New Folder", 		DAD_NONE,		FALSE)); +	addEntry(LLAssetType::AT_FAVORITE, 			new AssetEntry("FAVORITE",			"favorite",	"favorite",			"favorite", 		DAD_NONE,		FALSE)); + +	addEntry(LLAssetType::AT_LINK, 				new AssetEntry("LINK",				"link",		"symbolic link",	"New Folder", 		DAD_NONE,		FALSE)); +	addEntry(LLAssetType::AT_LINK_FOLDER, 		new AssetEntry("FOLDER_LINK",		"link_f", "symbolic folder link", "New Folder", DAD_NONE,		FALSE)); + +	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		"New Folder", 		DAD_NONE,		FALSE));  };  AssetEntry::AssetEntry(const char *desc_name,  					   const char *type_name,  					   const char *human_name,  					   const char *category_name, -					   EDragAndDropType dad_type) : +					   EDragAndDropType dad_type, +					   bool can_link) :  	LLDictionaryEntry(desc_name),  	mTypeName(type_name),  	mHumanName(human_name),  	mCategoryName(category_name), -	mDadType(dad_type) +	mDadType(dad_type), +	mCanLink(can_link)  {  	llassert(strlen(mTypeName) <= 8);  } @@ -231,6 +238,29 @@ EDragAndDropType LLAssetType::lookupDragAndDropType(EType asset_type)  		return DAD_NONE;  } +// static +bool LLAssetType::lookupCanLink(EType asset_type) +{ +	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); +	const AssetEntry *entry = dict->lookup(asset_type); +	if (entry) +	{ +		return entry->mCanLink; +	} +	return false; +} + +// static +// Not adding this to dictionary since we probably will only have these two types +bool LLAssetType::lookupIsLinkType(EType asset_type) +{ +	if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER) +	{ +		return true; +	} +	return false; +} +  // static. Generate a good default description  void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type,  										 std::string& description) diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 2f54031688..353bd57bb9 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -125,23 +125,25 @@ public:  		AT_SIMSTATE = 22,  			// Simstate file. -			 -		AT_LINK = 23, -			// Inventory symbolic link -			 -		AT_FAVORITE = 24, +	 +		AT_FAVORITE = 23,  			// favorite items -		// +*********************************************+ -		// |  TO ADD AN ELEMENT TO THIS ENUM:            | -			// +************************************************+ -		// | 1. INSERT BEFORE AT_COUNT                   | -		// | 2. INCREMENT AT_COUNT BY 1                  | -		// | 3. ADD TO LLAssetType::mAssetTypeNames      | -		// | 4. ADD TO LLAssetType::mAssetTypeHumanNames | -		// +*********************************************+ +		AT_LINK = 24, +			// Inventory symbolic link + +		AT_LINK_FOLDER = 25, +			// Inventory folder link -		AT_COUNT = 25, +		AT_COUNT = 26, + +			// +************************************************+ +			// |  TO ADD AN ELEMENT TO THIS ENUM:               | +			// +************************************************+ +			// | 1. INSERT BEFORE AT_COUNT                      | +			// | 2. INCREMENT AT_COUNT BY 1                     | +			// | 3. ADD TO LLAssetDictionary in llassettype.cpp | +			// +************************************************+  		AT_NONE = -1  	}; @@ -166,6 +168,8 @@ public:  	static EType 				getType(const std::string& desc_name);  	static const std::string&	getDesc(EType asset_type);  	static EDragAndDropType   	lookupDragAndDropType(EType asset_type); +	static bool 				lookupCanLink(EType asset_type); +	static bool 				lookupIsLinkType(EType asset_type);  	/* TODO: Change return types from "const char *" to "const std::string &".  	This is fairly straightforward, but requires changing some calls to use .c_str(). diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index adc80b2ed3..597e19e7ea 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -126,6 +126,20 @@ const std::string& LLInventoryObject::getName() const  	return mName;  } +// To bypass linked items, since llviewerinventory's getType +// will return the linked-to item's type instead of this object's type. +LLAssetType::EType LLInventoryObject::getActualType() const +{ +	return mType; +} + +// See LLInventoryItem override. +// virtual +const LLUUID& LLInventoryObject::getLinkedUUID() const +{ +	return mUUID; +} +  LLAssetType::EType LLInventoryObject::getType() const  {  	return mType; @@ -333,6 +347,19 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)  	mCreationDate = other->mCreationDate;  } +// If this is a linked item, then the UUID of the base object is +// this item's assetID. +// virtual +const LLUUID& LLInventoryItem::getLinkedUUID() const +{ +	if (LLAssetType::lookupIsLinkType(getActualType())) +	{ +		return mAssetUUID; +	} + +	return LLInventoryObject::getLinkedUUID(); +} +  const LLPermissions& LLInventoryItem::getPermissions() const  {  	return mPermissions; diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 3f79cedc23..ce64317f48 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -92,9 +92,12 @@ public:  	// accessors  	virtual const LLUUID& getUUID() const;  	const LLUUID& getParentUUID() const; +	virtual const LLUUID& getLinkedUUID() const; // get the inventoryID that this item points to, else this item's inventoryID +  	virtual const std::string& getName() const;  	virtual LLAssetType::EType getType() const; -	LLAssetType::EType getActualType() const { return mType; } +	LLAssetType::EType getActualType() const; // bypasses indirection for linked items +  	// mutators - will not call updateServer();  	void setUUID(const LLUUID& new_uuid);  	void rename(const std::string& new_name); @@ -240,15 +243,16 @@ public:  	void generateUUID() { mUUID.generate(); }  	// accessors -	const LLPermissions& getPermissions() const; -	const LLUUID& getCreatorUUID() const; +	virtual const LLUUID& getLinkedUUID() const; +	virtual const LLPermissions& getPermissions() const; +	virtual const LLUUID& getCreatorUUID() const;  	virtual const LLUUID& getAssetUUID() const; -	const std::string& getDescription() const; -	const LLSaleInfo& getSaleInfo() const; -	LLInventoryType::EType getInventoryType() const; -	U32 getFlags() const; -	time_t getCreationDate() const; -	U32 getCRC32() const; // really more of a checksum. +	virtual const std::string& getDescription() const; +	virtual const LLSaleInfo& getSaleInfo() const; +	virtual LLInventoryType::EType getInventoryType() const; +	virtual U32 getFlags() const; +	virtual time_t getCreationDate() const; +	virtual U32 getCRC32() const; // really more of a checksum.  	// mutators - will not call updateServer(), and will never fail  	// (though it may correct to sane values) diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index ff9c698943..2dc229226f 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -113,8 +113,10 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =  	LLInventoryType::IT_NONE,			// AT_IMAGE_JPEG  	LLInventoryType::IT_ANIMATION,		// AT_ANIMATION  	LLInventoryType::IT_GESTURE,		// AT_GESTURE -	LLInventoryType::IT_NONE,			// AT_LINK +	LLInventoryType::IT_NONE,			// AT_SIMSTATE  	LLInventoryType::IT_FAVORITE,		// AT_FAVORITE +	LLInventoryType::IT_NONE,			// AT_LINK +	LLInventoryType::IT_NONE,			// AT_LINK_FOLDER  };  InventoryEntry::InventoryEntry(const std::string &name, diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 059c1bdfa1..c715e16e34 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -264,17 +264,17 @@ bool is_asset_fetch_by_id_allowed(LLAssetType::EType type)  	bool rv = false;  	switch(type)  	{ -	case LLAssetType::AT_SOUND: -	case LLAssetType::AT_LANDMARK: -	case LLAssetType::AT_CLOTHING: -	case LLAssetType::AT_BODYPART: -	case LLAssetType::AT_ANIMATION: -	case LLAssetType::AT_GESTURE: -	case LLAssetType::AT_FAVORITE: -		rv = true; -		break; -	default: -		break; +		case LLAssetType::AT_SOUND: +		case LLAssetType::AT_LANDMARK: +		case LLAssetType::AT_CLOTHING: +		case LLAssetType::AT_BODYPART: +		case LLAssetType::AT_ANIMATION: +		case LLAssetType::AT_GESTURE: +		case LLAssetType::AT_FAVORITE: +			rv = true; +			break; +		default: +			break;  	}  	return rv;  } @@ -285,15 +285,17 @@ bool is_asset_id_knowable(LLAssetType::EType type)  	bool rv = false;  	switch(type)  	{ -	case LLAssetType::AT_TEXTURE: -	case LLAssetType::AT_SOUND: -	case LLAssetType::AT_LANDMARK: -	case LLAssetType::AT_CLOTHING: -	case LLAssetType::AT_NOTECARD: -	case LLAssetType::AT_BODYPART: -	case LLAssetType::AT_ANIMATION: -	case LLAssetType::AT_GESTURE: -	case LLAssetType::AT_FAVORITE: +		case LLAssetType::AT_TEXTURE: +		case LLAssetType::AT_SOUND: +		case LLAssetType::AT_LANDMARK: +		case LLAssetType::AT_CLOTHING: +		case LLAssetType::AT_NOTECARD: +		case LLAssetType::AT_BODYPART: +		case LLAssetType::AT_ANIMATION: +		case LLAssetType::AT_GESTURE: +		case LLAssetType::AT_FAVORITE: +		case LLAssetType::AT_LINK: +		case LLAssetType::AT_LINK_FOLDER:  		rv = true;  		break;  	default: diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 4e657067cd..9e3986f257 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -174,6 +174,7 @@ char* _PREHASH_UpdateInventoryItem = LLMessageStringTable::getInstance()->getStr  char* _PREHASH_UpdateCreateInventoryItem = LLMessageStringTable::getInstance()->getString("UpdateCreateInventoryItem");  char* _PREHASH_MoveInventoryItem = LLMessageStringTable::getInstance()->getString("MoveInventoryItem");  char* _PREHASH_CopyInventoryItem = LLMessageStringTable::getInstance()->getString("CopyInventoryItem"); +char* _PREHASH_LinkInventoryItem = LLMessageStringTable::getInstance()->getString("LinkInventoryItem");  char* _PREHASH_RemoveInventoryItem = LLMessageStringTable::getInstance()->getString("RemoveInventoryItem");  char* _PREHASH_CreateInventoryItem = LLMessageStringTable::getInstance()->getString("CreateInventoryItem");  char* _PREHASH_PathTwistBegin = LLMessageStringTable::getInstance()->getString("PathTwistBegin"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index f8ef610408..e73ec3e5e1 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -174,6 +174,7 @@ extern char * _PREHASH_UpdateInventoryItem;  extern char * _PREHASH_UpdateCreateInventoryItem;  extern char * _PREHASH_MoveInventoryItem;  extern char * _PREHASH_CopyInventoryItem; +extern char * _PREHASH_LinkInventoryItem;  extern char * _PREHASH_RemoveInventoryItem;  extern char * _PREHASH_CreateInventoryItem;  extern char * _PREHASH_PathTwistBegin; diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 1c756b1441..1da54ad08c 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -626,9 +626,24 @@ const LLUUID& LLAgentWearables::getWearableItem(EWearableType type, U32 index) c  } -BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const +// Warning: include_linked_items = TRUE makes this operation expensive. +BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_items) const  { -	return (getWearableFromWearableItem(item_id) != NULL); +	if (getWearableFromWearableItem(item_id) != NULL) return TRUE; +	if (include_linked_items) +	{ +		LLInventoryModel::item_array_t item_array; +		gInventory.collectLinkedItems(item_id, item_array); +		for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); +			 iter != item_array.end(); +			 iter++) +		{ +			LLViewerInventoryItem *linked_item = (*iter); +			const LLUUID &item_id = linked_item->getUUID(); +			if (getWearableFromWearableItem(item_id) != NULL) return TRUE; +		} +	} +	return FALSE;  }  // MULTI-WEARABLE: update for multiple diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 98f49203d3..31d6e30069 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -63,7 +63,7 @@ protected:  	// Queries  	//--------------------------------------------------------------------  public: -	BOOL			isWearingItem(const LLUUID& item_id) const; +	BOOL			isWearingItem(const LLUUID& item_id, const BOOL include_linked_items = FALSE) const;  	BOOL			isWearableModifiable(EWearableType type, U32 index /*= 0*/) const;  	BOOL			isWearableCopyable(EWearableType type, U32 index /*= 0*/) const;  	BOOL			areWearablesLoaded() const { return mWearablesLoaded; }  diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 5a8afc2277..dc72b66949 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -305,10 +305,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)  	BOOL is_complete = i->isComplete();  	const LLPermissions& perm = item->getPermissions(); -	BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm,  -												GP_OBJECT_MANIPULATE); -	BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,  -												GP_OBJECT_SET_SALE); +	const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm,  +															GP_OBJECT_MANIPULATE); +	const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,  +													  GP_OBJECT_SET_SALE); +	const BOOL is_link = LLAssetType::lookupIsLinkType(i->getActualType());  	// You need permission to modify the object to modify an inventory  	// item in it. @@ -491,7 +492,12 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)  	/////////////  	// Check for ability to change values. -	if (is_obj_modify && can_agent_manipulate) +	if (is_link) +	{ +		childSetEnabled("CheckShareWithGroup",FALSE); +		childSetEnabled("CheckEveryoneCopy",FALSE); +	} +	else if (is_obj_modify && can_agent_manipulate)  	{  		childSetEnabled("CheckShareWithGroup",TRUE);  		childSetEnabled("CheckEveryoneCopy",(owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER)); diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 9d91f0d64e..3386a7fb0e 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -103,6 +103,7 @@ public:  	virtual void cutToClipboard() = 0;  	virtual BOOL isClipboardPasteable() const = 0;  	virtual void pasteFromClipboard() = 0; +	virtual void pasteLinkFromClipboard() = 0;  	virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0;  	virtual BOOL isUpToDate() const = 0;  	virtual BOOL hasChildren() const = 0; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 540cefbc46..af653238d3 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -202,6 +202,38 @@ BOOL LLInvFVBridge::isItemRemovable()  	return FALSE;  } +// Sends an update to all link items that point to the base item. +void LLInvFVBridge::renameLinkedItems(const LLUUID &item_id, const std::string& new_name) +{ +	LLInventoryModel* model = getInventoryModel(); +	if(!model) return; + +	LLInventoryItem* itemp = model->getItem(mUUID); +	if (!itemp) return; + +	if (LLAssetType::lookupIsLinkType(itemp->getActualType())) +	{ +		return; +	} +	 +	LLInventoryModel::item_array_t item_array; +	model->collectLinkedItems(item_id, item_array); +	for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); +		 iter != item_array.end(); +		 iter++) +	{ +		LLViewerInventoryItem *linked_item = (*iter); +		if (linked_item->getUUID() == item_id) continue; +		 +		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(linked_item); +		new_item->rename(new_name); +		new_item->updateServer(FALSE); +		model->updateItem(new_item); +		// model->addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); +	} +	model->notifyObservers(); +} +  // Can be moved to another folder  BOOL LLInvFVBridge::isItemMovable()  { @@ -370,15 +402,71 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*  BOOL LLInvFVBridge::isClipboardPasteable() const  { +	if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) +	{ +		return FALSE; +	}  	LLInventoryModel* model = getInventoryModel(); -	if(!model) return FALSE; -	BOOL is_agent_inventory = model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()); +	if (!model) +	{ +		return FALSE; +	} + +	const LLUUID &agent_id = gAgent.getID(); -	if(LLInventoryClipboard::instance().hasContents() && is_agent_inventory) +	LLDynamicArray<LLUUID> objects; +	LLInventoryClipboard::instance().retrieve(objects); +	S32 count = objects.count(); +	for(S32 i = 0; i < count; i++)  	{ -		return TRUE; +		const LLUUID &item_id = objects.get(i); + +		// Can't paste folders +		const LLInventoryCategory *cat = model->getCategory(item_id); +		if (cat) +		{ +			return FALSE; +		} + +		const LLInventoryItem *item = model->getItem(item_id); +		if (item) +		{ +			if (!item->getPermissions().allowCopyBy(agent_id)) +			{ +				return FALSE; +			} +		}  	} -	return FALSE; +	return TRUE; +} + +BOOL LLInvFVBridge::isClipboardPasteableAsLink() const +{ +	if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) +	{ +		return FALSE; +	} +	LLInventoryModel* model = getInventoryModel(); +	if (!model) +	{ +		return FALSE; +	} + +	LLDynamicArray<LLUUID> objects; +	LLInventoryClipboard::instance().retrieve(objects); +	S32 count = objects.count(); +	for(S32 i = 0; i < count; i++) +	{ +		LLInventoryItem *item = model->getItem(objects.get(i)); +		if (item) +		{ +			if (!LLAssetType::lookupCanLink(item->getActualType())) +			{ +				return FALSE; +			} +		} +	} +	return TRUE;  }  void hideContextEntries(LLMenuGL& menu,  @@ -461,6 +549,11 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,  		disabled_items.push_back(std::string("Paste"));  	} +	items.push_back(std::string("Paste As Link")); +	if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) +	{ +		disabled_items.push_back(std::string("Paste As Link")); +	}  	items.push_back(std::string("Paste Separator"));  	items.push_back(std::string("Delete")); @@ -544,10 +637,25 @@ BOOL LLInvFVBridge::isInTrash() const  {  	LLInventoryModel* model = getInventoryModel();  	if(!model) return FALSE; -	LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); +	const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);  	return model->isObjectDescendentOf(mUUID, trash_id);  } +BOOL LLInvFVBridge::isLinkedObjectInTrash() const +{ +	if (isInTrash()) return TRUE; + +	LLInventoryModel* model = getInventoryModel(); +	if(!model) return FALSE; +	LLInventoryObject *obj = model->getObject(mUUID); +	if (obj && LLAssetType::lookupIsLinkType(obj->getActualType())) +	{ +		const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); +		return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id); +	} +	return FALSE; +} +  BOOL LLInvFVBridge::isAgentInventory() const  {  	LLInventoryModel* model = getInventoryModel(); @@ -627,108 +735,106 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,  	LLInvFVBridge* new_listener = NULL;  	switch(asset_type)  	{ -	case LLAssetType::AT_TEXTURE: -		if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLTextureBridge(inventory, uuid, inv_type); -		break; +		case LLAssetType::AT_TEXTURE: +			if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLTextureBridge(inventory, uuid, inv_type); +			break; -	case LLAssetType::AT_SOUND: -		if(!(inv_type == LLInventoryType::IT_SOUND)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLSoundBridge(inventory, uuid); -		break; +		case LLAssetType::AT_SOUND: +			if(!(inv_type == LLInventoryType::IT_SOUND)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLSoundBridge(inventory, uuid); +			break; -	case LLAssetType::AT_LANDMARK: -		if(!(inv_type == LLInventoryType::IT_LANDMARK)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLLandmarkBridge(inventory, uuid, flags); -		break; +		case LLAssetType::AT_LANDMARK: +			if(!(inv_type == LLInventoryType::IT_LANDMARK)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLLandmarkBridge(inventory, uuid, flags); +			break; -	case LLAssetType::AT_CALLINGCARD: -		if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLCallingCardBridge(inventory, uuid); -		break; - -	case LLAssetType::AT_SCRIPT: -		if(!(inv_type == LLInventoryType::IT_LSL)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLScriptBridge(inventory, uuid); -		break; - -	case LLAssetType::AT_OBJECT: -		if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags); -		break; +		case LLAssetType::AT_CALLINGCARD: +			if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLCallingCardBridge(inventory, uuid); +			break; -	case LLAssetType::AT_NOTECARD: -		if(!(inv_type == LLInventoryType::IT_NOTECARD)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLNotecardBridge(inventory, uuid); -		break; +		case LLAssetType::AT_SCRIPT: +			if(!(inv_type == LLInventoryType::IT_LSL)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLScriptBridge(inventory, uuid); +			break; -	case LLAssetType::AT_ANIMATION: -		if(!(inv_type == LLInventoryType::IT_ANIMATION)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLAnimationBridge(inventory, uuid); -		break; +		case LLAssetType::AT_OBJECT: +			if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags); +			break; -	case LLAssetType::AT_GESTURE: -		if(!(inv_type == LLInventoryType::IT_GESTURE)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLGestureBridge(inventory, uuid); -		break; +		case LLAssetType::AT_NOTECARD: +			if(!(inv_type == LLInventoryType::IT_NOTECARD)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLNotecardBridge(inventory, uuid); +			break; -	case LLAssetType::AT_LSL_TEXT: -		if(!(inv_type == LLInventoryType::IT_LSL)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLLSLTextBridge(inventory, uuid); -		break; +		case LLAssetType::AT_ANIMATION: +			if(!(inv_type == LLInventoryType::IT_ANIMATION)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLAnimationBridge(inventory, uuid); +			break; -	case LLAssetType::AT_CLOTHING: -	case LLAssetType::AT_BODYPART: -		if(!(inv_type == LLInventoryType::IT_WEARABLE)) -		{ -			llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; -		} -		new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags); -		break; +		case LLAssetType::AT_GESTURE: +			if(!(inv_type == LLInventoryType::IT_GESTURE)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLGestureBridge(inventory, uuid); +			break; -	case LLAssetType::AT_CATEGORY: -	case LLAssetType::AT_ROOT_CATEGORY: -		new_listener = new LLFolderBridge(inventory, uuid); -		break; +		case LLAssetType::AT_LSL_TEXT: +			if(!(inv_type == LLInventoryType::IT_LSL)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLLSLTextBridge(inventory, uuid); +			break; -	case LLAssetType::AT_FAVORITE: -		new_listener = new LLFolderBridge(inventory, uuid); -		break; -		 -	default: -		llinfos << "Unhandled asset type (llassetstorage.h): " -				<< (S32)asset_type << llendl; -		break; +		case LLAssetType::AT_CLOTHING: +		case LLAssetType::AT_BODYPART: +			if(!(inv_type == LLInventoryType::IT_WEARABLE)) +			{ +				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; +			} +			new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags); +			break; +		case LLAssetType::AT_CATEGORY: +		case LLAssetType::AT_ROOT_CATEGORY: +			new_listener = new LLFolderBridge(inventory, uuid); +			break; +		case LLAssetType::AT_LINK: +			// Only should happen for broken links. +			new_listener = new LLLinkItemBridge(inventory, uuid); +			break; +		default: +			llinfos << "Unhandled asset type (llassetstorage.h): " +					<< (S32)asset_type << llendl; +			break;  	}  	if (new_listener) @@ -739,6 +845,22 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,  	return new_listener;  } +void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) +{ +	LLInventoryCategory* cat = model->getCategory(uuid); +	if (cat) +	{ +		model->purgeDescendentsOf(uuid); +		model->notifyObservers(); +	} +	LLInventoryObject* obj = model->getObject(uuid); +	if (obj) +	{ +		model->purgeObject(uuid); +		model->notifyObservers(); +	} +} +  // +=================================================+  // |        LLItemBridge                             |  // +=================================================+ @@ -748,32 +870,27 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model,  	if ("open" == action)  	{  		openItem(); +		return;  	}  	else if ("properties" == action)  	{  		showProperties(); +		return;  	}  	else if ("purge" == action)  	{ -		LLInventoryCategory* cat = model->getCategory(mUUID); -		if(cat) -		{ -			model->purgeDescendentsOf(mUUID); -		} -		LLInventoryObject* obj = model->getObject(mUUID); -		if(!obj) return; -		obj->removeFromServer(); -		LLPreview::hide(mUUID); -		model->deleteObject(mUUID); -		model->notifyObservers(); +		purgeItem(model, mUUID); +		return;  	}  	else if ("restoreToWorld" == action)  	{  		restoreToWorld(); +		return;  	}  	else if ("restore" == action)  	{  		restoreItem(); +		return;  	}  	else if ("copy_uuid" == action)  	{ @@ -804,6 +921,18 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model,  		folder_view_itemp->getListener()->pasteFromClipboard();  		return;  	} +	else if ("paste_link" == action) +	{ +		// Single item only +		LLInventoryItem* itemp = model->getItem(mUUID); +		if (!itemp) return; + +		LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); +		if (!folder_view_itemp) return; + +		folder_view_itemp->getListener()->pasteLinkFromClipboard(); +		return; +	}  }  void LLItemBridge::selectItem() @@ -913,6 +1042,24 @@ void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name)  	}  } +LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const +{  +	U8 font = LLFontGL::NORMAL; +	 +	if( gAgentWearables.isWearingItem( mUUID ) ) +	{ +		// llinfos << "BOLD" << llendl; +		font |= LLFontGL::BOLD; +	} + +	const LLViewerInventoryItem* item = getItem(); +	if (LLAssetType::lookupIsLinkType(item->getActualType())) +	{ +		font |= LLFontGL::ITALIC; +	} +	return (LLFontGL::StyleFlags)font; +} +  std::string LLItemBridge::getLabelSuffix() const  {  	// assume that this won't be called before string table is loaded @@ -932,8 +1079,12 @@ std::string LLItemBridge::getLabelSuffix() const  			BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());  			BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,  																gAgent.getID()); +			BOOL link = (item->getActualType() == LLAssetType::AT_LINK);  			const char* EMPTY = ""; +			const char* LINK = " (link)"; // *TODO: Seraph translate +			if (link) return LINK; +  			const char* scopy;  			if(copy) scopy = EMPTY;  			else scopy = NO_COPY; @@ -986,6 +1137,8 @@ BOOL LLItemBridge::renameItem(const std::string& new_name)  		buildDisplayName(new_item, mDisplayName);  		new_item->updateServer(FALSE);  		model->updateItem(new_item); +		renameLinkedItems(item->getUUID(),new_name); +  		model->notifyObservers();  	}  	// return FALSE because we either notified observers (& therefore @@ -1034,13 +1187,19 @@ BOOL LLItemBridge::isItemCopyable() const  			return FALSE;  		} -		if( avatarp->isWearingAttachment( mUUID ) ) +		if( avatarp->isWearingAttachment( mUUID, TRUE ) )  		{  			return FALSE;  		} -			 - -		return (item->getPermissions().allowCopyBy(gAgent.getID())); +		 +		// All items can be copied, not all can be pasted. +		// The only time an item can't be copied is if it's a link  +		// return (item->getPermissions().allowCopyBy(gAgent.getID())); +		if (item->getActualType() == LLAssetType::AT_LINK) +		{ +			return FALSE; +		} +		return TRUE;  	}  	return FALSE;  } @@ -1152,7 +1311,7 @@ BOOL LLFolderBridge::isItemRemovable()  		if( (item->getType() == LLAssetType::AT_CLOTHING) ||  			(item->getType() == LLAssetType::AT_BODYPART) )  		{ -			if( gAgentWearables.isWearingItem( item->getUUID() ) ) +			if( gAgentWearables.isWearingItem( item->getUUID(), TRUE ) )  			{  				return FALSE;  			} @@ -1160,7 +1319,7 @@ BOOL LLFolderBridge::isItemRemovable()  		else  		if( item->getType() == LLAssetType::AT_OBJECT )  		{ -			if( avatar->isWearingAttachment( item->getUUID() ) ) +			if( avatar->isWearingAttachment( item->getUUID(), TRUE ) )  			{  				return FALSE;  			} @@ -1183,6 +1342,21 @@ BOOL LLFolderBridge::isUpToDate() const  	return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;  } +BOOL LLFolderBridge::isItemCopyable() const +{ +	return TRUE; +} + +BOOL LLFolderBridge::copyToClipboard() const +{ +	if(isItemCopyable()) +	{ +		LLInventoryClipboard::instance().add(mUUID); +		return TRUE; +	} +	return FALSE; +} +  BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  											BOOL drop)  { @@ -1620,22 +1794,37 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model  	if ("open" == action)  	{  		openItem(); +		return;  	}  	else if ("paste" == action)  	{  		pasteFromClipboard(); +		return; +	} +	else if ("paste_link" == action) +	{ +		pasteLinkFromClipboard(); +		return;  	}  	else if ("properties" == action)  	{  		showProperties(); +		return;  	}  	else if ("replaceoutfit" == action)  	{  		modifyOutfit(FALSE); +		return;  	}  	else if ("addtooutfit" == action)  	{  		modifyOutfit(TRUE); +		return; +	} +	else if ("copy" == action) +	{ +		copyToClipboard(); +		return;  	}  	else if ("removefromoutfit" == action)  	{ @@ -1645,25 +1834,17 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model  		if(!cat) return;  		remove_inventory_category_from_avatar ( cat ); +		return;  	}	  	else if ("purge" == action)  	{		 -		LLViewerInventoryCategory* cat; -		cat = (LLViewerInventoryCategory*)getCategory(); - -		if(cat) -		{ -			model->purgeDescendentsOf(mUUID); -		} -		LLInventoryObject* obj = model->getObject(mUUID); -		if(!obj) return; -		obj->removeFromServer(); -		model->deleteObject(mUUID); -		model->notifyObservers(); +		purgeItem(model, mUUID); +		return;  	}  	else if ("restore" == action)  	{  		restoreItem(); +		return;  	}  } @@ -1723,59 +1904,59 @@ LLUIImagePtr LLFolderBridge::getIcon() const  	}  	switch(preferred_type)  	{ -	case LLAssetType::AT_TEXTURE: -		control = "inv_folder_texture.tga"; -		break; -	case LLAssetType::AT_SOUND: -		control = "inv_folder_sound.tga"; -		break; -	case LLAssetType::AT_CALLINGCARD: -		control = "inv_folder_callingcard.tga"; -		break; -	case LLAssetType::AT_LANDMARK: -		control = "inv_folder_landmark.tga"; -		break; -	case LLAssetType::AT_SCRIPT: -	case LLAssetType::AT_LSL_TEXT: -		control = "inv_folder_script.tga"; -		break; -	case LLAssetType::AT_OBJECT: -		control = "inv_folder_object.tga"; -		break; -	case LLAssetType::AT_NOTECARD: -		control = "inv_folder_notecard.tga"; -		break; -	case LLAssetType::AT_CATEGORY: -		control = "inv_folder_plain_closed.tga"; -		break; -	case LLAssetType::AT_CLOTHING: -		control = "inv_folder_clothing.tga"; -		break; -	case LLAssetType::AT_BODYPART: -		control = "inv_folder_bodypart.tga"; -		break; -	case LLAssetType::AT_TRASH: -		control = "inv_folder_trash.tga"; -		break; -	case LLAssetType::AT_SNAPSHOT_CATEGORY: -		control = "inv_folder_snapshot.tga"; -		break; -	case LLAssetType::AT_LOST_AND_FOUND: -		control = "inv_folder_lostandfound.tga"; -		break; -	case LLAssetType::AT_ANIMATION: -		control = "inv_folder_animation.tga"; -		break; -	case LLAssetType::AT_GESTURE: -		control = "inv_folder_gesture.tga"; -		break; -	case LLAssetType::AT_FAVORITE: -		//TODO - need icon -		control = "inv_folder_plain_closed.tga"; -		break; -	default: -		control = "inv_folder_plain_closed.tga"; -		break; +		case LLAssetType::AT_TEXTURE: +			control = "inv_folder_texture.tga"; +			break; +		case LLAssetType::AT_SOUND: +			control = "inv_folder_sound.tga"; +			break; +		case LLAssetType::AT_CALLINGCARD: +			control = "inv_folder_callingcard.tga"; +			break; +		case LLAssetType::AT_LANDMARK: +			control = "inv_folder_landmark.tga"; +			break; +		case LLAssetType::AT_SCRIPT: +		case LLAssetType::AT_LSL_TEXT: +			control = "inv_folder_script.tga"; +			break; +		case LLAssetType::AT_OBJECT: +			control = "inv_folder_object.tga"; +			break; +		case LLAssetType::AT_NOTECARD: +			control = "inv_folder_notecard.tga"; +			break; +		case LLAssetType::AT_CATEGORY: +			control = "inv_folder_plain_closed.tga"; +			break; +		case LLAssetType::AT_CLOTHING: +			control = "inv_folder_clothing.tga"; +			break; +		case LLAssetType::AT_BODYPART: +			control = "inv_folder_bodypart.tga"; +			break; +		case LLAssetType::AT_TRASH: +			control = "inv_folder_trash.tga"; +			break; +		case LLAssetType::AT_SNAPSHOT_CATEGORY: +			control = "inv_folder_snapshot.tga"; +			break; +		case LLAssetType::AT_LOST_AND_FOUND: +			control = "inv_folder_lostandfound.tga"; +			break; +		case LLAssetType::AT_ANIMATION: +			control = "inv_folder_animation.tga"; +			break; +		case LLAssetType::AT_GESTURE: +			control = "inv_folder_gesture.tga"; +			break; +		case LLAssetType::AT_FAVORITE: +			//TODO - need icon +			control = "inv_folder_plain_closed.tga"; +			break; +		default: +			control = "inv_folder_plain_closed.tga"; +			break;  	}  	return LLUI::getUIImage(control);  } @@ -1794,6 +1975,8 @@ BOOL LLFolderBridge::renameItem(const std::string& new_name)  		new_cat->rename(new_name);  		new_cat->updateServer(FALSE);  		model->updateCategory(new_cat); +		renameLinkedItems(cat->getUUID(),new_name); +  		model->notifyObservers();  	}  	// return FALSE because we either notified observers (& therefore @@ -1842,15 +2025,6 @@ BOOL LLFolderBridge::removeItem()  	return TRUE;  } -BOOL LLFolderBridge::isClipboardPasteable() const -{ -	if(LLInventoryClipboard::instance().hasContents() && isAgentInventory()) -	{ -		return TRUE; -	} -	return FALSE; -} -  void LLFolderBridge::pasteFromClipboard()  {  	LLInventoryModel* model = getInventoryModel(); @@ -1878,6 +2052,33 @@ void LLFolderBridge::pasteFromClipboard()  	}  } +void LLFolderBridge::pasteLinkFromClipboard() +{ +	LLInventoryModel* model = getInventoryModel(); +	if(model) +	{ +		LLInventoryItem* item = NULL; +		LLDynamicArray<LLUUID> objects; +		LLInventoryClipboard::instance().retrieve(objects); +		S32 count = objects.count(); +		LLUUID parent_id(mUUID); +		for(S32 i = 0; i < count; i++) +		{ +			item = model->getItem(objects.get(i)); +			if (item) +			{ +				link_inventory_item( +					gAgent.getID(), +					item->getUUID(), +					parent_id, +					item->getName(), +					LLAssetType::AT_LINK, +					LLPointer<LLInventoryCallback>(NULL)); +			} +		} +	} +} +  void LLFolderBridge::staticFolderOptionsMenu()  {  	if (!sSelf) return; @@ -1948,6 +2149,9 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv  // Flags unused  void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  { +	mItems.clear(); +	mDisabledItems.clear(); +  	lldebugs << "LLFolderBridge::buildContextMenu()" << llendl;  //	std::vector<std::string> disabled_items;  	LLInventoryModel* model = getInventoryModel(); @@ -3116,7 +3320,7 @@ BOOL LLObjectBridge::isItemRemovable()  {  	LLVOAvatarSelf* avatar = gAgent.getAvatarObject();  	if(!avatar) return FALSE; -	if(avatar->isWearingAttachment(mUUID)) return FALSE; +	if(avatar->isWearingAttachment(mUUID, TRUE)) return FALSE;  	return LLInvFVBridge::isItemRemovable();  } @@ -3125,6 +3329,17 @@ LLUIImagePtr LLObjectBridge::getIcon() const  	return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject );  } +LLInventoryObject* LLObjectBridge::getObject() const +{ +	LLInventoryObject* object = NULL; +	LLInventoryModel* model = getInventoryModel(); +	if(model) +	{ +		object = (LLInventoryObject*)model->getObject(mUUID); +	} +	return object; +} +  // virtual  void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action)  { @@ -3194,15 +3409,21 @@ void LLObjectBridge::openItem()  LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const  {  +	U8 font = LLFontGL::NORMAL; +  	LLVOAvatarSelf* avatar = gAgent.getAvatarObject();  	if( avatar && avatar->isWearingAttachment( mUUID ) )  	{ -		return LLFontGL::BOLD; +		font |= LLFontGL::BOLD;  	} -	else + +	LLInventoryItem* item = getItem(); +	if (item->getActualType() == LLAssetType::AT_LINK)  	{ -		return LLFontGL::NORMAL; +		font |= LLFontGL::ITALIC;  	} +	 +	return (LLFontGL::StyleFlags)font;  }  std::string LLObjectBridge::getLabelSuffix() const @@ -3223,7 +3444,7 @@ std::string LLObjectBridge::getLabelSuffix() const  void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment)  {  	LLSD payload; -	payload["item_id"] = item->getUUID(); +	payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link.  	S32 attach_pt = 0;  	if (gAgent.getAvatarObject() && attachment) @@ -3315,7 +3536,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  				items.push_back(std::string("Detach From Yourself"));  			}  			else -			if( !isInTrash() ) +			if( !isInTrash() && !isLinkedObjectInTrash() )  			{  				items.push_back(std::string("Attach Separator"));  				items.push_back(std::string("Object Wear")); @@ -3381,6 +3602,8 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name)  		buildDisplayName(new_item, mDisplayName);  		new_item->updateServer(FALSE);  		model->updateItem(new_item); +		renameLinkedItems(item->getUUID(),new_name); +  		model->notifyObservers();  		LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); @@ -4141,23 +4364,10 @@ BOOL LLWearableBridge::renameItem(const std::string& new_name)  BOOL LLWearableBridge::isItemRemovable()  { -	if(gAgentWearables.isWearingItem(mUUID)) return FALSE; +	if (gAgentWearables.isWearingItem(mUUID, TRUE)) return FALSE;  	return LLInvFVBridge::isItemRemovable();  } -LLFontGL::StyleFlags LLWearableBridge::getLabelStyle() const -{  -	if( gAgentWearables.isWearingItem( mUUID ) ) -	{ -		// llinfos << "BOLD" << llendl; -		return LLFontGL::BOLD; -	} -	else -	{ -		return LLFontGL::NORMAL; -	} -} -  std::string LLWearableBridge::getLabelSuffix() const  {  	if( gAgentWearables.isWearingItem( mUUID ) ) @@ -4300,6 +4510,13 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  		{  			disabled_items.push_back(std::string("Wearable Edit"));  		} +		// Don't allow items to be worn if their baseobj is in the trash. +		if (isLinkedObjectInTrash()) +		{ +			disabled_items.push_back(std::string("Wearable Wear")); +			disabled_items.push_back(std::string("Wearable Add")); +			disabled_items.push_back(std::string("Wearable Edit")); +		}  		if( item && (item->getType() == LLAssetType::AT_CLOTHING) )  		{ @@ -4534,9 +4751,8 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,  	delete item_id;  } -  LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, -									   const LLUUID& uuid,LLInventoryModel* model) +													   const LLUUID& uuid,LLInventoryModel* model)  {  	LLInvFVBridgeAction* action = NULL;  	switch(asset_type) @@ -4819,3 +5035,44 @@ void	LLWearableBridgeAction::doIt()  	LLInvFVBridgeAction::doIt();  } + +// +=================================================+ +// |        LLLinkItemBridge                         | +// +=================================================+ +// For broken links + +std::string LLLinkItemBridge::sPrefix("Link: "); + + +LLUIImagePtr LLLinkItemBridge::getIcon() const +{ +	return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE); +} + +void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ +	// *TODO: Translate +	lldebugs << "LLLink::buildContextMenu()" << llendl; +	std::vector<std::string> items; +	std::vector<std::string> disabled_items; + +	if(isInTrash()) +	{ +		items.push_back(std::string("Purge Item")); +		if (!isItemRemovable()) +		{ +			disabled_items.push_back(std::string("Purge Item")); +		} + +		items.push_back(std::string("Restore Item")); +	} +	else +	{	 +		items.push_back(std::string("Delete")); +		if (!isItemRemovable()) +		{ +			disabled_items.push_back(std::string("Delete")); +		} +	} +	hideContextEntries(menu, items, disabled_items); +} diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3958f7e9c2..016eb701d6 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -167,7 +167,9 @@ public:  	virtual BOOL copyToClipboard() const { return FALSE; }  	virtual void cutToClipboard() {}  	virtual BOOL isClipboardPasteable() const; +	virtual BOOL isClipboardPasteableAsLink() const;  	virtual void pasteFromClipboard() {} +	virtual void pasteLinkFromClipboard() {}  	void getClipboardEntries(bool show_asset_id, std::vector<std::string> &items,   		std::vector<std::string> &disabled_items, U32 flags);  	virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -191,6 +193,8 @@ protected:  	LLInventoryModel* getInventoryModel() const;  	BOOL isInTrash() const; +	BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash? +  	// return true if the item is in agent inventory. if false, it  	// must be lost or in the inventory library.  	BOOL isAgentInventory() const; @@ -204,11 +208,13 @@ protected:  									 const LLUUID& new_parent,  									 BOOL restamp);  	void removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*>& batch); -	 +	void renameLinkedItems(const LLUUID &item_id, const std::string& new_name); +  protected:  	LLHandle<LLPanel> mInventoryPanel; -	LLUUID mUUID;	// item id +	const LLUUID mUUID;	// item id  	LLInventoryType::EType mInvType; +	void purgeItem(LLInventoryModel *model, const LLUUID &uuid);  }; @@ -227,6 +233,7 @@ public:  	virtual LLUIImagePtr getIcon() const;  	virtual const std::string& getDisplayName() const;  	virtual std::string getLabelSuffix() const; +	virtual LLFontGL::StyleFlags getLabelStyle() const;  	virtual PermissionMask getPermissionMask() const;  	virtual time_t getCreationDate() const;  	virtual BOOL isItemRenameable() const; @@ -267,8 +274,8 @@ public:  	virtual LLUIImagePtr getIcon() const;  	virtual BOOL renameItem(const std::string& new_name);  	virtual BOOL removeItem(); -	virtual BOOL isClipboardPasteable() const;  	virtual void pasteFromClipboard(); +	virtual void pasteLinkFromClipboard();  	virtual void buildContextMenu(LLMenuGL& menu, U32 flags);  	virtual BOOL hasChildren() const;  	virtual BOOL dragOrDrop(MASK mask, BOOL drop, @@ -278,7 +285,9 @@ public:  	virtual BOOL isItemRemovable();  	virtual BOOL isItemMovable();  	virtual BOOL isUpToDate() const; - +	virtual BOOL isItemCopyable() const; +	virtual BOOL copyToClipboard() const; +	  	static void createWearable(LLFolderBridge* bridge, EWearableType type);  	static void createWearable(LLUUID parent_folder_id, EWearableType type); @@ -489,6 +498,8 @@ public:  	virtual BOOL			isItemRemovable();  	virtual BOOL renameItem(const std::string& new_name); +	LLInventoryObject* getObject() const; +  protected:  	LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) :  		LLItemBridge(inventory, uuid), mInvType(type) @@ -527,7 +538,6 @@ public:  	virtual void	performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);  	virtual void	openItem();  	virtual void	buildContextMenu(LLMenuGL& menu, U32 flags); -	virtual LLFontGL::StyleFlags getLabelStyle() const;  	virtual std::string getLabelSuffix() const;  	virtual BOOL	isItemRemovable();  	virtual BOOL renameItem(const std::string& new_name); @@ -562,8 +572,25 @@ protected:  	EWearableType  mWearableType;  }; +class LLLinkItemBridge : public LLItemBridge +{ +	friend class LLInvFVBridge; +public: +	virtual const std::string& getPrefix() { return sPrefix; } + +	virtual LLUIImagePtr getIcon() const; +	virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + +protected: +	LLLinkItemBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : +		LLItemBridge(inventory, uuid) {} + +protected: +	static std::string sPrefix; +}; +  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInvFVBridgeAction (& it's derived classes) +// Class LLInvFVBridgeAction (& its derived classes)  //  // This is an implementation class to be able to   // perform action to view inventory items. diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9177d51d5c..5a14bdd55e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -464,6 +464,18 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,  	}  } +void LLInventoryModel::collectLinkedItems(const LLUUID& id, +										  item_array_t& items) +{ +	LLInventoryModel::cat_array_t cat_array; +	LLLinkedItemIDMatches is_linked_item_match(id); +	collectDescendentsIf(gAgent.getInventoryRootID(), +						 cat_array, +						 items, +						 LLInventoryModel::INCLUDE_TRASH, +						 is_linked_item_match); +} +  // Generates a string containing the path to the item specified by  // item_id.  void LLInventoryModel::appendPath(const LLUUID& id, std::string& path) @@ -747,6 +759,7 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id)  // Delete a particular inventory object by ID.  void LLInventoryModel::deleteObject(const LLUUID& id)  { +	purgeLinkedObjects(id);  	lldebugs << "LLInventoryModel::deleteObject()" << llendl;  	LLPointer<LLInventoryObject> obj = getObject(id);  	if(obj) @@ -786,6 +799,42 @@ void LLInventoryModel::deleteObject(const LLUUID& id)  	}  } +// Delete a particular inventory item by ID, and remove it from the server. +void LLInventoryModel::purgeObject(const LLUUID &id) +{ +	lldebugs << "LLInventoryModel::purgeObject()" << llendl; +	LLPointer<LLInventoryObject> obj = getObject(id); +	if(obj) +	{ +		obj->removeFromServer(); +		LLPreview::hide(id); +		deleteObject(id); +	} +} + +void LLInventoryModel::purgeLinkedObjects(const LLUUID &id) +{ +	LLInventoryItem* itemp = getItem(id); +	if (!itemp) return; + +	if (LLAssetType::lookupIsLinkType(itemp->getActualType())) +	{ +		return; +	} + +	LLInventoryModel::item_array_t item_array; +	collectLinkedItems(id, item_array); +	 +	for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); +		 iter != item_array.end(); +		 iter++) +	{ +		LLViewerInventoryItem *linked_item = (*iter); +		if (linked_item->getUUID() == id) continue; +		purgeObject(linked_item->getUUID()); +	} +} +  // This is a method which collects the descendents of the id  // provided. If the category is not found, no action is  // taken. This method goes through the long winded process of @@ -3914,11 +3963,20 @@ void LLInventoryTransactionObserver::changed(U32 mask)  ///----------------------------------------------------------------------------  /// LLAssetIDMatches   ///---------------------------------------------------------------------------- -bool LLAssetIDMatches ::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  {  	return (item && item->getAssetUUID() == mAssetID);  } +///---------------------------------------------------------------------------- +/// LLLinkedItemIDMatches  +///---------------------------------------------------------------------------- +bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +	return (item &&  +			(LLAssetType::lookupIsLinkType(item->getActualType())) && +			(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. +}  ///----------------------------------------------------------------------------  /// Local function definitions diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 77e604769e..46288700d2 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -169,7 +169,7 @@ public:  									item_array_t*& items);  	void unlockDirectDescendentArrays(const LLUUID& cat_id); -	// Starting with the object specified, add it's descendents to the +	// Starting with the object specified, add its descendents to the  	// array provided, but do not add the inventory object specified  	// by id. There is no guaranteed order. Neither array will be  	// erased before adding objects to it. Do not store a copy of the @@ -187,6 +187,11 @@ public:  							  BOOL include_trash,  							  LLInventoryCollectFunctor& add); +	// Collect all items in inventory that are linked to item_id. +	// Assumes item_id is itself not a linked item. +	void collectLinkedItems(const LLUUID& item_id, +							item_array_t& items); +	  	// This method will return false if this inventory model is in an usabel state.  	// The inventory model usage is sensitive to the initial construction of the   	// model.  @@ -227,8 +232,13 @@ public:  	// delete a particular inventory object by ID. This will purge one  	// object from the internal data structures maintaining a  	// cosistent internal state. No cache accounting, observer -	// notification, or server update is performed. +	// notification, or server update is performed.  Purges linked items.  	void deleteObject(const LLUUID& id); +	 +	// delete a particular inventory object by ID, and delete it from +	// the server.  Also purges linked items via purgeLinkedObjects. +	void purgeObject(const LLUUID& id); +	void purgeLinkedObjects(const LLUUID& id);  	// This is a method which collects the descendents of the id  	// provided. If the category is not found, no action is @@ -530,6 +540,22 @@ protected:  	LLUUID mAssetID;  }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLLinkedItemIDMatches +// +// This functor finds inventory items linked to the specific inventory id. +// Assumes the inventory id is itself not a linked item. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLLinkedItemIDMatches : public LLInventoryCollectFunctor +{ +public: +	LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} +	virtual ~LLLinkedItemIDMatches() {} +	bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +	 +protected: +	LLUUID mBaseItemID; +};  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLIsType diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 45d24ee7e8..2c79e67ebc 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -244,8 +244,7 @@ BOOL LLViewerInventoryItem::unpackMessage(LLSD item)  }  // virtual -BOOL LLViewerInventoryItem::unpackMessage( -	LLMessageSystem* msg, const char* block, S32 block_num) +BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)  {  	BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num);  	mIsComplete = TRUE; @@ -742,6 +741,32 @@ void copy_inventory_item(  	gAgent.sendReliableMessage();  } +void link_inventory_item( +	const LLUUID& agent_id, +	const LLUUID& item_id, +	const LLUUID& parent_id, +	const std::string& new_name, +	const LLAssetType::EType asset_type, +	LLPointer<LLInventoryCallback> cb) +{ +	LLMessageSystem* msg = gMessageSystem; +	msg->newMessageFast(_PREHASH_LinkInventoryItem); +	msg->nextBlockFast(_PREHASH_AgentData); +	{ +		msg->addUUIDFast(_PREHASH_AgentID, agent_id); +		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +	} +	msg->nextBlockFast(_PREHASH_InventoryData); +	{ +		msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); +		msg->addUUIDFast(_PREHASH_FolderID, parent_id); +		msg->addUUIDFast(_PREHASH_OldItemID, item_id); +		msg->addStringFast(_PREHASH_Name, new_name); +		msg->addU8Fast(_PREHASH_AssetType, asset_type); +	} +	gAgent.sendReliableMessage(); +} +  void move_inventory_item(  	const LLUUID& agent_id,  	const LLUUID& session_id, @@ -948,26 +973,19 @@ void menu_create_inventory_item(LLFolderView* folder, LLFolderBridge *bridge, co  LLAssetType::EType LLViewerInventoryItem::getType() const  { -	if (mType == LLAssetType::AT_LINK) +	if (const LLViewerInventoryItem *linked_item = getLinkedItem())  	{ -		LLInventoryItem *linked_item = gInventory.getItem(mAssetUUID); -		if (linked_item) -		{ -			return linked_item->getType(); -		} +		return linked_item->getType();  	} +	  	return LLInventoryItem::getType();  }  const LLUUID& LLViewerInventoryItem::getAssetUUID() const  { -	if (mType == LLAssetType::AT_LINK) +	if (const LLViewerInventoryItem *linked_item = getLinkedItem())  	{ -		LLInventoryItem *linked_item = gInventory.getItem(mAssetUUID); -		if (linked_item) -		{ -			return linked_item->getAssetUUID(); -		} +		return linked_item->getAssetUUID();  	}  	return LLInventoryItem::getAssetUUID(); @@ -975,11 +993,96 @@ const LLUUID& LLViewerInventoryItem::getAssetUUID() const  const std::string& LLViewerInventoryItem::getName() const  { -	if (mType == LLAssetType::AT_LINK) +	if (const LLViewerInventoryItem *linked_item = getLinkedItem())  	{ -		return LLInventoryItem::getName(); //+" link"; +		return linked_item->getName();  	}  	return LLInventoryItem::getName();  } +const LLPermissions& LLViewerInventoryItem::getPermissions() const +{ +	// Use the actual permissions of the symlink, not its parent. +	return LLInventoryItem::getPermissions();	 +} + +const LLUUID& LLViewerInventoryItem::getCreatorUUID() const +{ +	if (const LLViewerInventoryItem *linked_item = getLinkedItem()) +	{ +		return linked_item->getCreatorUUID(); +	} + +	return LLInventoryItem::getCreatorUUID(); +} + +const std::string& LLViewerInventoryItem::getDescription() const +{ +	if (const LLViewerInventoryItem *linked_item = getLinkedItem()) +	{ +		return linked_item->getDescription(); +	} + +	return LLInventoryItem::getDescription(); +} + +const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const +{	 +	if (const LLViewerInventoryItem *linked_item = getLinkedItem()) +	{ +		return linked_item->getSaleInfo(); +	} + +	return LLInventoryItem::getSaleInfo(); +} + +LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const +{ +	if (const LLViewerInventoryItem *linked_item = getLinkedItem()) +	{ +		return linked_item->getInventoryType(); +	} + +	return LLInventoryItem::getInventoryType(); +} + +U32 LLViewerInventoryItem::getFlags() const +{ +	if (const LLViewerInventoryItem *linked_item = getLinkedItem()) +	{ +		return linked_item->getFlags(); +	} + +	return LLInventoryItem::getFlags(); +} + +time_t LLViewerInventoryItem::getCreationDate() const +{ +	return LLInventoryItem::getCreationDate(); +} + +U32 LLViewerInventoryItem::getCRC32() const +{ +	return LLInventoryItem::getCRC32();	 +} + +const LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const +{ +	if (mType == LLAssetType::AT_LINK) +	{ +		const LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID); +		return linked_item; +	} +	return NULL; +} + +const LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const +{ +	if (mType == LLAssetType::AT_LINK_FOLDER) +	{ +		const LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID); +		return linked_category; +	} +	return NULL; +} diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 8318931dde..7084c9f37a 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -39,6 +39,7 @@  class LLFolderView;  class LLFolderBridge; +class LLViewerInventoryCategory;  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLViewerInventoryItem @@ -59,7 +60,15 @@ public:  	virtual LLAssetType::EType getType() const;  	virtual const LLUUID& getAssetUUID() const;  	virtual const std::string& getName() const; -	 +	virtual const LLPermissions& getPermissions() const; +	virtual const LLUUID& getCreatorUUID() const; +	virtual const std::string& getDescription() const; +	virtual const LLSaleInfo& getSaleInfo() const; +	virtual LLInventoryType::EType getInventoryType() const; +	virtual U32 getFlags() const; +	virtual time_t getCreationDate() const; +	virtual U32 getCRC32() const; // really more of a checksum. +  	// construct a complete viewer inventory item  	LLViewerInventoryItem(const LLUUID& uuid, const LLUUID& parent_uuid,  						  const LLPermissions& permissions, @@ -133,6 +142,9 @@ public:  	LLTransactionID getTransactionID() const { return mTransactionID; }  protected: +	const LLViewerInventoryItem *getLinkedItem() const; +	const LLViewerInventoryCategory *getLinkedCategory() const; +  	BOOL mIsComplete;  	LLTransactionID mTransactionID;  }; @@ -279,6 +291,14 @@ void copy_inventory_item(  	const std::string& new_name,  	LLPointer<LLInventoryCallback> cb); +void link_inventory_item( +	const LLUUID& agent_id, +	const LLUUID& item_id, +	const LLUUID& parent_id, +	const std::string& new_name, +	const LLAssetType::EType asset_type, +	LLPointer<LLInventoryCallback> cb); +  void move_inventory_item(  	const LLUUID& agent_id,  	const LLUUID& session_id, diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index d629767bbe..e7d7d74f62 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -907,18 +907,43 @@ void LLVOAvatarSelf::wearableUpdated( EWearableType type )  //-----------------------------------------------------------------------------  // isWearingAttachment()  //----------------------------------------------------------------------------- -BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id ) +// Warning: include_linked_items = TRUE makes this operation expensive. +BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id , BOOL include_linked_items ) const  { -	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();  +	for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end(); )  	{ -		attachment_map_t::iterator curiter = iter++; -		LLViewerJointAttachment* attachment = curiter->second; +		attachment_map_t::const_iterator curiter = iter++; +		const LLViewerJointAttachment* attachment = curiter->second;  		if( attachment->getItemID() == inv_item_id )  		{  			return TRUE;  		}  	} + +	if (include_linked_items) +	{ +		LLInventoryModel::item_array_t item_array; +		gInventory.collectLinkedItems(inv_item_id, item_array); +		for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); +			 iter != item_array.end(); +			 iter++) +		{ +			const LLViewerInventoryItem *linked_item = (*iter); +			const LLUUID &item_id = linked_item->getUUID(); +			for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();  +				 iter != mAttachmentPoints.end(); ) +			{ +				attachment_map_t::const_iterator curiter = iter++; +				const LLViewerJointAttachment* attachment = curiter->second; +				if( attachment->getItemID() == item_id ) +				{ +					return TRUE; +				} +			} +		} +	} +  	return FALSE;  } diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 431c814382..02a77cba90 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -267,7 +267,7 @@ public:  	//--------------------------------------------------------------------  public:  	void 				updateAttachmentVisibility(U32 camera_mode); -	BOOL 				isWearingAttachment(const LLUUID& inv_item_id); +	BOOL 				isWearingAttachment(const LLUUID& inv_item_id, BOOL include_linked_items = FALSE) const;  	LLViewerObject* 	getWornAttachment(const LLUUID& inv_item_id ) const;  	const std::string   getAttachedPointName(const LLUUID& inv_item_id) const;  	/*virtual*/ LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 92de94636b..1275312676 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -77,14 +77,17 @@ LLWearableList::~LLWearableList()  void LLWearableList::getAsset(const LLAssetID& _assetID, const std::string& wearable_name, LLAssetType::EType asset_type, void(*asset_arrived_callback)(LLWearable*, void* userdata), void* userdata)  {  	LLAssetID assetID = _assetID; -	if (asset_type == LLAssetType::AT_LINK) + +	// A bit of a hack since wearables database doesn't contain asset types... +	// Perform indirection in case this assetID is in fact a link.  This only works +	// because of the assumption that all assetIDs and itemIDs are unique (i.e. +	// no assetID is also used as an itemID elsewhere); therefore if the assetID +	// exists as an itemID in the user's inventory, then this must be a link. +	const LLInventoryItem *linked_item = gInventory.getItem(_assetID); +	if (linked_item)  	{ -		LLInventoryItem *linked_item = gInventory.getItem(_assetID); -		if (linked_item) -		{ -			assetID = linked_item->getAssetUUID(); -			asset_type = linked_item->getType(); -		} +		assetID = linked_item->getAssetUUID(); +		asset_type = linked_item->getType();  	}  	llassert( (asset_type == LLAssetType::AT_CLOTHING) || (asset_type == LLAssetType::AT_BODYPART) );  	LLWearable* instance = get_if_there(mList, assetID, (LLWearable*)NULL ); diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 808618ba96..6f2fd5e5e5 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -320,6 +320,14 @@           function="Inventory.DoToSelected"           parameter="paste" />      </menu_item_call> +    <menu_item_call +     label="Paste As Link" +     layout="topleft" +     name="Paste As Link"> +        <menu_item_call.on_click +         function="Inventory.DoToSelected" +         parameter="paste_link" /> +    </menu_item_call>      <menu_item_separator       layout="topleft" />      <menu_item_call | 
