diff options
| author | Loren Shih <seraph@lindenlab.com> | 2009-08-12 19:03:20 +0000 | 
|---|---|---|
| committer | Loren Shih <seraph@lindenlab.com> | 2009-08-12 19:03:20 +0000 | 
| commit | 7bbc5cdea6beb4e05c26d1472f789fe6fa536ee3 (patch) | |
| tree | 9e496156bb377c9bdf0b793a1b07b72dfa4f032c | |
| parent | 0bf4b5f2222ffb8171be094613363427f3b8470a (diff) | |
svn merge -r129617:130277 svn+ssh://svn.lindenlab.com/svn/linden/branches/avatar-pipeline/currently-worn-folder-5 into svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-3
For DEV-34223 : AVP Current Outfit Folder
For DEV-37485 : AVP Appearance Side Panel
For DEV-35335 : AVP Automatic Folder Classification
This merges the Appearance Side Panel / Ensemble Typing / Current Outfit Folder work for the AVP team.
32 files changed, 854 insertions, 121 deletions
| diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index d431071c25..835cdbca04 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -282,6 +282,12 @@ bool LLAssetType::lookupIsProtectedCategoryType(EType asset_type)  	return true;  } +// static +bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type) +{ +	return (asset_type >= AT_FOLDER_ENSEMBLE_START && +			asset_type <= AT_FOLDER_ENSEMBLE_END); +}  // static. Generate a good default description  void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type, diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 8ab7510494..5e51188541 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -186,6 +186,7 @@ public:  	static const char*  		lookupCategoryName(EType asset_type);  	static bool 				lookupIsProtectedCategoryType(EType asset_type); +	static bool 				lookupIsEnsembleCategoryType(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 59aca12de2..e2a77f1d1e 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -133,6 +133,11 @@ LLAssetType::EType LLInventoryObject::getActualType() const  	return mType;  } +BOOL LLInventoryObject::getIsLinkType() const +{ +	return LLAssetType::lookupIsLinkType(mType); +} +  // See LLInventoryItem override.  // virtual  const LLUUID& LLInventoryObject::getLinkedUUID() const diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 5b8f7ba661..2b4d8ed831 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -97,7 +97,7 @@ public:  	virtual const std::string& getName() const;  	virtual LLAssetType::EType getType() const;  	LLAssetType::EType getActualType() const; // bypasses indirection for linked items - +	BOOL getIsLinkType() const;  	// mutators - will not call updateServer();  	void setUUID(const LLUUID& new_uuid);  	void rename(const std::string& new_name); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a25ea01d11..e52b523a7f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -278,6 +278,8 @@ set(viewer_SOURCE_FILES      llnotify.cpp      lloutputmonitorctrl.cpp      lloverlaybar.cpp +    llpanelappearance.cpp +    llpanelappearancetab.cpp      llpanelavatar.cpp      llpanelavatarrow.cpp      llpanelavatartag.cpp @@ -305,6 +307,8 @@ set(viewer_SOURCE_FILES      llpanellandmarks.cpp      llpanellandmedia.cpp      llpanellogin.cpp +    llpanellookinfo.cpp +    llpanellooks.cpp      llpanelmedia.cpp      llpanelmeprofile.cpp      llpanelmovetip.cpp @@ -719,6 +723,8 @@ set(viewer_HEADER_FILES      llnotify.h      lloutputmonitorctrl.h      lloverlaybar.h +    llpanelappearance.h +    llpanelappearancetab.h      llpanelavatar.h      llpanelavatarrow.h      llpanelavatartag.h @@ -746,6 +752,8 @@ set(viewer_HEADER_FILES      llpanellandmarks.h      llpanellandmedia.h      llpanellogin.h +    llpanellookinfo.h +    llpanellooks.h      llpanelmedia.h      llpanelmeprofile.h      llpanelmovetip.h diff --git a/indra/newview/app_settings/foldertypes.xml b/indra/newview/app_settings/foldertypes.xml index 4d4d479bdd..698158308e 100644 --- a/indra/newview/app_settings/foldertypes.xml +++ b/indra/newview/app_settings/foldertypes.xml @@ -9,50 +9,66 @@      asset_num="27"      xui_name="head"      icon_name="inv_folder_outfit_head.tga" +	allowed="hair,eyes"       />    <ensemble      asset_num="28"      xui_name="gloves"      icon_name="inv_folder_outfit_gloves.tga" +	allowed="gloves"       />    <ensemble      asset_num="29"      xui_name="jacket"      icon_name="inv_folder_outfit_jacket.tga" +	allowed="jacket"       />    <ensemble      asset_num="30"      xui_name="pants"      icon_name="inv_folder_outfit_pants.tga" +	allowed="pants,underpants"       />    <ensemble      asset_num="31"      xui_name="shape"      icon_name="inv_folder_outfit_shape.tga" +	allowed="shape,skin,hair,eyes"       />    <ensemble      asset_num="32"      xui_name="shoes"      icon_name="inv_folder_outfit_shoes.tga" +	allowed="shoes,socks"       />    <ensemble      asset_num="33"      xui_name="shirt"      icon_name="inv_folder_outfit_shirt.tga" +	allowed="shirt,undershirt"       />    <ensemble      asset_num="34"      xui_name="skirt"      icon_name="inv_folder_outfit_skirt.tga" +	allowed=""       />    <ensemble      asset_num="35"      xui_name="underpants"      icon_name="inv_folder_outfit_underpants.tga" +	allowed="underpants"       />    <ensemble      asset_num="36"      xui_name="undershirt"      icon_name="inv_folder_outfit_undershirt.tga" +	allowed="undershirt" +     /> +  <ensemble +    asset_num="47" +    xui_name="outfit" +    icon_name="inv_folder_outfit.tga" +	allowed="outfit"       />  </ensemble_defs> diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 22875cbca2..e5e456acb8 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -37,6 +37,7 @@  #include "llfloatercustomize.h"  #include "llfloaterinventory.h" +#include "llinventorybridge.h"  #include "llinventorymodel.h"  #include "llnotify.h"  #include "llviewerregion.h" @@ -46,6 +47,9 @@  #include <boost/scoped_ptr.hpp> +// For viewer2.0 internal demo, don't use current outfit folder contents at all during initial startup.  Will reenable +// this once we're sure this works completely. +// #define USE_CURRENT_OUTFIT_FOLDER  LLAgentWearables gAgentWearables; @@ -662,13 +666,6 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_  	return FALSE;  } -struct InitialWearableData -{ -	S32 mType; -	U32 mIndex; -	LLUUID mItemID; -}; -  // MULTI-WEARABLE: update for multiple  // static  void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) @@ -696,14 +693,18 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs  			return;  		} +		// Get the UUID of the current outfit folder (will be created if it doesn't exist) +		LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); +		 +		LLOutfitFolderFetch* outfit = new LLOutfitFolderFetch(); +		  		//lldebugs << "processAgentInitialWearablesUpdate()" << llendl;  		// Add wearables -		LLUUID asset_id_array[WT_COUNT]; -		LLUUID item_id_array[WT_COUNT];  		// MULTI-WEARABLE: TODO: update once messages change.  Currently use results to populate the zeroth element.  		gAgentWearables.mItemsAwaitingWearableUpdate.clear();  		for (S32 i=0; i < num_wearables; i++)  		{ +			// Parse initial werables data from message system  			U8 type_u8 = 0;  			gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);  			if (type_u8 >= WT_COUNT) @@ -711,10 +712,10 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs  				continue;  			}  			const EWearableType type = (EWearableType) type_u8; - +			  			LLUUID item_id;  			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i); - +			  			LLUUID asset_id;  			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i);  			if (asset_id.isNull()) @@ -728,34 +729,77 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs  				{  					continue;  				} - -				// MULTI-WEARABLE: extend arrays to index by type + index. -				gAgentWearables.mItemsAwaitingWearableUpdate.insert(item_id); -				item_id_array[type] = item_id; -				asset_id_array[type] = asset_id; +				 +				// MULTI-WEARABLE: TODO: update once messages change.  Currently use results to populate the zeroth element. +				 +				// Store initial wearables data until we know whether we have the current outfit folder or need to use the data. +				InitialWearableData * temp_wearable_data = new InitialWearableData(type, 0, item_id, asset_id); // MULTI-WEARABLE: update +				outfit->mAgentInitialWearables.push_back(temp_wearable_data); +				  			}  			lldebugs << "       " << LLWearableDictionary::getTypeLabel(type) << llendl;  		} +		 +		// What we do here is get the complete information on the items in +		// the inventory, and set up an observer that will wait for that to +		// happen. +		LLInventoryFetchDescendentsObserver::folder_ref_t folders; +		folders.push_back(current_outfit_id); +		outfit->fetchDescendents(folders); +		if(outfit->isEverythingComplete()) +		{ +			// everything is already here - call done. +			outfit->done(); +		} +		else +		{ +			// it's all on it's way - add an observer, and the inventory +			// will call done for us when everything is here. +			gInventory.addObserver(outfit); +		} +	} +} -		// now that we have the asset ids...request the wearable assets -		for (S32 i = 0; i < WT_COUNT; i++) +// static  +void LLAgentWearables::fetchInitialWearables(initial_wearable_data_vec_t & current_outfit_links, initial_wearable_data_vec_t & message_wearables) +{ +#ifdef USE_CURRENT_OUTFIT_FOLDER +	if (!current_outfit_links.empty()) +	{ +		for (U8 i = 0; i < current_outfit_links.size(); ++i)  		{ -			// MULTI-WEARABLE: TODO: update once messages change. -			// Currently use results to populate the zeroth element. -			if (!item_id_array[i].isNull()) -			{ -				InitialWearableData *wear_data = new InitialWearableData; -				wear_data->mType = i; -				wear_data->mIndex = 0; // MULTI-WEARABLE: update -				wear_data->mItemID = item_id_array[i]; -				LLWearableList::instance().getAsset(asset_id_array[i], -													LLStringUtil::null, -													LLWearableDictionary::getAssetType((EWearableType) i),  -													onInitialWearableAssetArrived, (void*)wear_data); -			} +			// Fetch the wearables in the current outfit folder +			LLWearableList::instance().getAsset(current_outfit_links[i]->mAssetID, +												LLStringUtil::null, +												LLWearableDictionary::getAssetType(current_outfit_links[i]->mType), +												onInitialWearableAssetArrived, (void*)(current_outfit_links[i]));			 +		} +	} +	else  +#endif +	if (!message_wearables.empty()) // We have an empty current outfit folder, use the message data instead. +	{ +		LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); +		for (U8 i = 0; i < message_wearables.size(); ++i) +		{ +			// Populate the current outfit folder with links to the wearables passed in the message +#ifdef USE_CURRENT_OUTFIT_FOLDER +			std::string link_name = "WearableLink"; +			link_inventory_item(gAgent.getID(), message_wearables[i]->mItemID, current_outfit_id, link_name, +								LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL)); +#endif +			// Fetch the wearables +			LLWearableList::instance().getAsset(message_wearables[i]->mAssetID, +												LLStringUtil::null, +												LLWearableDictionary::getAssetType(message_wearables[i]->mType), +												onInitialWearableAssetArrived, (void*)(message_wearables[i]));  		}  	} +	else +	{ +		LL_WARNS("Wearables") << "No current outfit folder iterms found and no initial wearables fallback message received." << LL_ENDL; +	}  }  // A single wearable that the avatar was wearing on start-up has arrived from the database. @@ -763,7 +807,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs  void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* userdata)  {  	boost::scoped_ptr<InitialWearableData> wear_data((InitialWearableData*)userdata);  -	const EWearableType type = (EWearableType)wear_data->mType; +	const EWearableType type = wear_data->mType;  	const U32 index = wear_data->mIndex;  	LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); @@ -775,10 +819,11 @@ void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void*  	if (wearable)  	{  		llassert(type == wearable->getType()); +		// MULTI-WEARABLE: is this always zeroth element?  Change sometime.  		wearable->setItemID(wear_data->mItemID); -		gAgentWearables.setWearable(type,index,wearable); +		gAgentWearables.setWearable(type, index, wearable);  		gAgentWearables.mItemsAwaitingWearableUpdate.erase(wear_data->mItemID); -		 +  		// disable composites if initial textures are baked  		avatar->setupComposites(); @@ -954,6 +999,8 @@ void LLAgentWearables::createStandardWearablesAllDone()  	mAvatarObject->onFirstTEMessageReceived();  } +// Note:	wearables_to_include should be a list of EWearableType types +//			attachments_to_include should be a list of attachment points  void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,  									 const LLDynamicArray<S32>& wearables_to_include,  									 const LLDynamicArray<S32>& attachments_to_include, @@ -1087,6 +1134,98 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,  	}   } +// Note:	wearables_to_include should be a list of EWearableType types +//			attachments_to_include should be a list of attachment points +void LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name, +										  const LLDynamicArray<S32>& wearables_to_include, +										  const LLDynamicArray<S32>& attachments_to_include, +										  BOOL rename_clothing) +{ +	if (mAvatarObject.isNull()) +	{ +		return; +	} + +	// First, make a folder in the Clothes directory. +	LLUUID folder_id = gInventory.createNewCategory( +		gInventory.findCategoryUUIDForType(LLAssetType::AT_MY_OUTFITS), +		LLAssetType::AT_OUTFIT, +		new_folder_name); + +//	bool found_first_item = false; + +	/////////////////// +	// Wearables + +	if (wearables_to_include.count()) +	{ +		// Then, iterate though each of the wearables and save links to them in the folder. +		S32 i; +		S32 count = wearables_to_include.count(); +		LLDynamicArray<LLUUID> delete_items; +		LLPointer<LLRefCount> cbdone = NULL; +		for (i = 0; i < count; ++i) +		{ +			const S32 type = wearables_to_include[i]; +			for (U32 j=0; j<getWearableCount((EWearableType)i); j++) +			{ +				LLWearable* old_wearable = getWearable((EWearableType)type,j); +				if (old_wearable) +				{ +					std::string new_name; +					if (rename_clothing) +					{ +						new_name = new_folder_name; +						new_name.append(" "); +						new_name.append(old_wearable->getTypeLabel()); +						LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); +					} + +					LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((EWearableType) type, j)); +					// BAP TODO +					LLPointer<LLInventoryCallback> cb = NULL; +					link_inventory_item(gAgent.getID(), +										item->getUUID(), +										folder_id, +										new_name, +										LLAssetType::AT_LINK, +										cb); +				} +			} +		} +		gInventory.notifyObservers(); +	} + + +	/////////////////// +	// Attachments + +	if (attachments_to_include.count()) +	{ +		for (S32 i = 0; i < attachments_to_include.count(); i++) +		{ +			S32 attachment_pt = attachments_to_include[i]; +			LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL); +			if (!attachment) continue; +			LLViewerObject* attached_object = attachment->getObject(); +			if (!attached_object) continue; +			const LLUUID& item_id = attachment->getItemID(); +			if (item_id.isNull()) continue; +			LLInventoryItem* item = gInventory.getItem(item_id); +			if (!item) continue; + +			// BAP link here +			LLPointer<LLInventoryCallback> cb = NULL; +			link_inventory_item(gAgent.getID(), +								item->getUUID(), +								folder_id, +								item->getName(), +								LLAssetType::AT_LINK, +								cb); +		} +	}  +} +  void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)  {  	LLUUID first_item_id = getWearableItemID((EWearableType)type, index); @@ -1635,3 +1774,56 @@ void LLAgentWearables::updateServer()  	sendAgentWearablesUpdate();  	gAgent.sendAgentSetAppearance();  } + +void LLAgentWearables::LLOutfitFolderFetch::done() +{ +	// What we do here is get the complete information on the items in +	// the library, and set up an observer that will wait for that to +	// happen. +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t item_array; +	gInventory.collectDescendents(mCompleteFolders.front(), +								  cat_array, +								  item_array, +								  LLInventoryModel::EXCLUDE_TRASH); +	S32 count = item_array.count(); +	LLAgentWearables::initial_wearable_data_vec_t current_outfit_links; +	current_outfit_links.reserve(count); +	 +	for(S32 i = 0; i < count; ++i) +	{ +		// 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(item_array.get(i)->getUUID()); +		LLAssetType::EType asset_type = (LLAssetType::EType) 0; +		if (linked_item) +		{ +			asset_type = linked_item->getType(); +			LLInventoryItem * base_item = gInventory.getItem(linked_item->getLinkedUUID()); +			if (base_item) +			{ +				EWearableType type = (EWearableType) (base_item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); +				// MULTI-WEARABLE: update +				InitialWearableData * temp_wearable_data = new InitialWearableData(type, 0, linked_item->getLinkedUUID(), base_item->getAssetUUID()); +				current_outfit_links.push_back(temp_wearable_data); +			} +			else +			{ +				llwarns << "Null base_item in LLOutfitFolderFetch::done, linkedUUID is " << linked_item->getLinkedUUID().asString() << llendl; +			} +		} +		else +		{ +			llwarns << "Null linked_item in LLOutfitFolderFetch::done, UUID is " << item_array.get(i)->getUUID().asString() << llendl; +		} +	} +	 +	gInventory.removeObserver(this); +	LLAgentWearables::fetchInitialWearables(current_outfit_links, mAgentInitialWearables); +	mAgentInitialWearables.clear(); +	delete this; +} + diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 977efd71b4..971fd9ee37 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -36,15 +36,34 @@  #include "llmemory.h"  #include "lluuid.h"  #include "llinventory.h" +#include "llinventorymodel.h"  #include "llviewerinventory.h" +#include "llvoavatardefines.h"  class LLInventoryItem;  class LLVOAvatarSelf;  class LLWearable; +// Forward Declaration +class LLInventoryFetchDescendentsObserver; +  class LLAgentWearables  {  	//-------------------------------------------------------------------- +	// Data Types +	//-------------------------------------------------------------------- +	typedef struct _InitialWearableData +	{ +		EWearableType mType; +		U32 mIndex; +		LLUUID mItemID; +		LLUUID mAssetID; +		_InitialWearableData(EWearableType type, U32 index, LLUUID itemID, LLUUID assetID) : +		mType(type), mIndex(index), mItemID(itemID), mAssetID(assetID) { } +	} InitialWearableData; +	typedef std::vector<InitialWearableData *> initial_wearable_data_vec_t; +	 +	//--------------------------------------------------------------------  	// Constructors / destructors / Initializers  	//--------------------------------------------------------------------  public: @@ -85,13 +104,14 @@ public:  	U32				getWearableCount(const EWearableType type) const; +	//-------------------------------------------------------------------- +	// Setters +	//-------------------------------------------------------------------- +  private:  	// Low-level data structure setter - public access is via setWearableItem, etc.  	void 			setWearable(const EWearableType type, U32 index, LLWearable *wearable); -	//-------------------------------------------------------------------- -	// Setters -	//--------------------------------------------------------------------  public:  	void			setWearableItem(LLInventoryItem* new_item, LLWearable* wearable, bool do_append = false);  	void			setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove); @@ -127,7 +147,9 @@ protected:  	// Server Communication  	//--------------------------------------------------------------------  public: +	// Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant)  	static void		processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); +	static void		fetchInitialWearables(initial_wearable_data_vec_t & current_outfit_links, initial_wearable_data_vec_t & message_wearables);  protected:  	void			sendAgentWearablesUpdate();  	void			sendAgentWearablesRequest(); @@ -139,10 +161,19 @@ protected:  	// Outfits  	//--------------------------------------------------------------------  public: +	// Note:	wearables_to_include should be a list of EWearableType types +	//			attachments_to_include should be a list of attachment points  	void			makeNewOutfit(const std::string& new_folder_name,  								  const LLDynamicArray<S32>& wearables_to_include,  								  const LLDynamicArray<S32>& attachments_to_include, -								  BOOL rename_clothing);protected: +								  BOOL rename_clothing); +	 +	// Note:	wearables_to_include should be a list of EWearableType types +	//			attachments_to_include should be a list of attachment points +	void			makeNewOutfitLinks(const std::string& new_folder_name, +									   const LLDynamicArray<S32>& wearables_to_include, +									   const LLDynamicArray<S32>& attachments_to_include, +									   BOOL rename_clothing);  private:  	void			makeNewOutfitDone(S32 type, U32 index);  @@ -223,6 +254,17 @@ private:  		U32 mTodo;  		LLPointer<LLRefCount> mCB;  	}; +	 +	// Outfit folder fetching callback structure. +	class LLOutfitFolderFetch : public LLInventoryFetchDescendentsObserver +	{ +	public: +		LLOutfitFolderFetch() {} +		~LLOutfitFolderFetch() {} +		virtual void done(); +		 +		LLAgentWearables::initial_wearable_data_vec_t mAgentInitialWearables; +	};  }; // LLAgentWearables diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index 33a99facad..718719fe57 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1274,9 +1274,9 @@ void LLInventoryPanel::draw()  	LLPanel::draw();  } -void LLInventoryPanel::setFilterTypes(U32 filter_types) +void LLInventoryPanel::setFilterTypes(U64 filter_types, BOOL filter_for_categories)  { -	mFolders->getFilter()->setFilterTypes(filter_types); +	mFolders->getFilter()->setFilterTypes(filter_types, filter_for_categories);  }	  void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) diff --git a/indra/newview/llfloaterinventory.h b/indra/newview/llfloaterinventory.h index 734ab5032e..fd61e121ea 100644 --- a/indra/newview/llfloaterinventory.h +++ b/indra/newview/llfloaterinventory.h @@ -133,7 +133,7 @@ public:  	void setSelectCallback(const LLFolderView::signal_t::slot_type& cb) { if (mFolders) mFolders->setSelectCallback(cb); }  	void clearSelection();  	LLInventoryFilter* getFilter() { return mFolders->getFilter(); } -	void setFilterTypes(U32 filter); +	void setFilterTypes(U64 filter, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type  	U32 getFilterTypes() const { return mFolders->getFilterTypes(); }  	void setFilterPermMask(PermissionMask filter_perm_mask);  	U32 getFilterPermMask() const { return mFolders->getFilterPermissions(); } diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index cafaa6dd79..8ac00832c9 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -244,7 +244,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)  	const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,   													  GP_OBJECT_SET_SALE) &&  		!cannot_restrict_permissions; -	const BOOL is_link = LLAssetType::lookupIsLinkType(i->getActualType()); +	const BOOL is_link = i->getIsLinkType();  	// You need permission to modify the object to modify an inventory  	// item in it. diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index c54eafb67a..4a5a775a05 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1103,26 +1103,7 @@ void LLFolderView::changeType(LLInventoryModel *model, LLAssetType::EType new_fo  	if (!folder_bridge) return;  	LLViewerInventoryCategory *cat = folder_bridge->getCategory();  	if (!cat) return; -		 -	const LLUUID &folder_id = cat->getUUID(); -	const LLUUID &parent_id = cat->getParentUUID(); -	const std::string &name = cat->getName(); -		 -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_UpdateInventoryFolder); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	msg->nextBlockFast(_PREHASH_FolderData); -	msg->addUUIDFast(_PREHASH_FolderID, folder_id); -	msg->addUUIDFast(_PREHASH_ParentID, parent_id); -	msg->addS8Fast(_PREHASH_Type, new_folder_type); -	msg->addStringFast(_PREHASH_Name, name); -	gAgent.sendReliableMessage(); - -	cat->setPreferredType(new_folder_type); -	gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); -	gInventory.updateLinkedObjects(folder_id); +	cat->changeType(new_folder_type);  }  void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index eb06123b46..254ce4062a 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -62,6 +62,7 @@ public:  	virtual LLFontGL::StyleFlags getLabelStyle() const = 0;  	virtual std::string getLabelSuffix() const = 0;  	virtual void openItem( void ) = 0; +	virtual void closeItem( void ) = 0;  	virtual void previewItem( void ) = 0;  	virtual void selectItem(void) = 0;  	virtual void showProperties(void) = 0; diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index a6a8da2a76..69ce2f0e0e 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -1912,12 +1912,16 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r  {  	BOOL was_open = mIsOpen;  	mIsOpen = openitem; -	if(!was_open && openitem) +	if (mListener)  	{ -		if(mListener) +		if(!was_open && openitem)  		{  			mListener->openItem();  		} +		else if(was_open && !openitem) +		{ +			mListener->closeItem(); +		}  	}  	if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 2ef643e3f7..5f634496d3 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -113,7 +113,7 @@ void dec_busy_count()  struct LLWearableHoldingPattern;  void wear_add_inventory_item_on_avatar(LLInventoryItem* item);  void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append); -void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append); +void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links);  void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*);  void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append);  void remove_inventory_category_from_avatar(LLInventoryCategory* category); @@ -219,7 +219,7 @@ void LLInvFVBridge::renameLinkedItems(const LLUUID &item_id, const std::string&  	LLInventoryItem* itemp = model->getItem(mUUID);  	if (!itemp) return; -	if (LLAssetType::lookupIsLinkType(itemp->getActualType())) +	if (itemp->getIsLinkType())  	{  		return;  	} @@ -654,7 +654,7 @@ BOOL LLInvFVBridge::isLinkedObjectInTrash() const  	if (isInTrash()) return TRUE;  	LLInventoryObject *obj = getInventoryObject(); -	if (obj && LLAssetType::lookupIsLinkType(obj->getActualType())) +	if (obj && obj->getIsLinkType())  	{  		LLInventoryModel* model = getInventoryModel();  		if(!model) return FALSE; @@ -1023,7 +1023,7 @@ void LLItemBridge::restoreToWorld()  void LLItemBridge::gotoItem(LLFolderView *folder)  {  	LLInventoryObject *obj = getInventoryObject(); -	if (obj && LLAssetType::lookupIsLinkType(obj->getActualType())) +	if (obj && obj->getIsLinkType())  	{  		LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel();  		if (active_panel) @@ -1089,7 +1089,7 @@ LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const  	}  	const LLViewerInventoryItem* item = getItem(); -	if (item && LLAssetType::lookupIsLinkType(item->getActualType())) +	if (item && item->getIsLinkType())  	{  		font |= LLFontGL::ITALIC;  	} @@ -1116,7 +1116,7 @@ std::string LLItemBridge::getLabelSuffix() const  			BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType());  			if (broken_link) return BROKEN_LINK; -			BOOL link = LLAssetType::lookupIsLinkType(item->getActualType()); +			BOOL link = item->getIsLinkType();  			if (link) return LINK;  			BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); @@ -1241,7 +1241,7 @@ BOOL LLItemBridge::isItemCopyable() const  		// 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 (LLAssetType::lookupIsLinkType(item->getActualType())) +		if (item->getIsLinkType())  		{  			return FALSE;  		} @@ -1441,6 +1441,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  		BOOL move_is_into_trash = (mUUID == trash_id)  				|| model->isObjectDescendentOf(mUUID, trash_id);  		BOOL is_movable = (!LLAssetType::lookupIsProtectedCategoryType(inv_cat->getPreferredType())); +		LLUUID current_outfit_id = model->findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); +		BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); +		if (move_is_into_current_outfit) +		{ +			// BAP - restrictions? +			is_movable = true; +		}  		if( is_movable )  		{  			gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); @@ -1507,13 +1514,27 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,  				}  			} -			// Reparent the folder and restamp children if it's moving -			// into trash. -			LLInvFVBridge::changeCategoryParent( -				model, -				(LLViewerInventoryCategory*)inv_cat, -				mUUID, -				move_is_into_trash); +			if (current_outfit_id == mUUID) // if target is current outfit folder we use link +			{ +				link_inventory_item( +					gAgent.getID(), +					inv_cat->getUUID(), +					mUUID, +					inv_cat->getName(), +					LLAssetType::AT_LINK_FOLDER, +					LLPointer<LLInventoryCallback>(NULL)); +			} +			else +			{ +				 +				// Reparent the folder and restamp children if it's moving +				// into trash. +				LLInvFVBridge::changeCategoryParent( +					model, +					(LLViewerInventoryCategory*)inv_cat, +					mUUID, +					move_is_into_trash); +			}  		}  	}  	else if(LLToolDragAndDrop::SOURCE_WORLD == source) @@ -1899,7 +1920,29 @@ void LLFolderBridge::openItem()  	lldebugs << "LLFolderBridge::openItem()" << llendl;  	LLInventoryModel* model = getInventoryModel();  	if(!model) return; -	model->fetchDescendentsOf(mUUID); +	bool fetching_inventory = model->fetchDescendentsOf(mUUID); +	// Only change folder type if we have the folder contents. +	if (!fetching_inventory) +	{ +		// Disabling this for now, it's causing crash when new items are added to folders +		// since folder type may change before new item item has finished processing. +		// determineFolderType(); +	} +} + +void LLFolderBridge::closeItem() +{ +	determineFolderType(); +} + +void LLFolderBridge::determineFolderType() +{ +	if (isUpToDate()) +	{ +		LLInventoryModel* model = getInventoryModel(); +		LLViewerInventoryCategory* category = model->getCategory(mUUID); +		category->determineFolderType(); +	}  }  BOOL LLFolderBridge::isItemRenameable() const @@ -2013,6 +2056,15 @@ LLUIImagePtr LLFolderBridge::getIcon(LLAssetType::EType preferred_type)  			//TODO - need icon  			control = "inv_folder_plain_closed.tga";  			break; +		case LLAssetType::AT_OUTFIT: +			control = "inv_folder_outfit.tga"; +			break; +		case LLAssetType::AT_CURRENT_OUTFIT: +			control = "inv_folder_current_outfit.tga"; +			break; +		case LLAssetType::AT_MY_OUTFITS: +			control = "inv_folder_my_outfits.tga"; +			break;  		default:  			control = "inv_folder_plain_closed.tga";  			break; @@ -2199,6 +2251,10 @@ void LLFolderBridge::folderOptionsMenu()  		}  		mItems.push_back(std::string("Take Off Items"));  	} +	if (LLAssetType::AT_CURRENT_OUTFIT == category->getPreferredType()) +	{ +		mItems.push_back(std::string("Replace Outfit")); +	}  	hideContextEntries(*mMenu, mItems, disabled_items);  } @@ -2253,6 +2309,8 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  	else if(isAgentInventory()) // do not allow creating in library  	{  		mItems.push_back(std::string("New Folder")); +		mItems.push_back(std::string("New Outfit")); +		mItems.push_back(std::string("New My Outfits"));  		mItems.push_back(std::string("New Script"));  		mItems.push_back(std::string("New Note"));  		mItems.push_back(std::string("New Gesture")); @@ -2492,7 +2550,9 @@ void LLFolderBridge::modifyOutfit(BOOL append)  	LLViewerInventoryCategory* cat = getCategory();  	if(!cat) return; -	wear_inventory_category_on_avatar( cat, append ); +	// BAP - was: +	// wear_inventory_category_on_avatar( cat, append ); +	wear_inventory_category( cat, FALSE, append );  }  // helper stuff @@ -3500,7 +3560,7 @@ LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const  	}  	LLInventoryItem* item = getItem(); -	if (LLAssetType::lookupIsLinkType(item->getActualType())) +	if (item && item->getIsLinkType())  	{  		font |= LLFontGL::ITALIC;  	} @@ -3599,7 +3659,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  	else  	{  		LLInventoryItem* item = getItem(); -		if (item && LLAssetType::lookupIsLinkType(item->getActualType())) +		if (item && item->getIsLinkType())  		{  			items.push_back(std::string("Goto Link"));  		} @@ -4086,17 +4146,18 @@ void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL appe  	lldebugs << "wear_inventory_category_on_avatar( " << category->getName()  			 << " )" << llendl; +	BOOL follow_folder_links = (category->getPreferredType() == LLAssetType::AT_CURRENT_OUTFIT || category->getPreferredType() == LLAssetType::AT_OUTFIT );   	if( gFloaterCustomize )  	{ -		gFloaterCustomize->askToSaveIfDirty(boost::bind(wear_inventory_category_on_avatar_step2, _1, category->getUUID(), append)); +		gFloaterCustomize->askToSaveIfDirty(boost::bind(wear_inventory_category_on_avatar_step2, _1, category->getUUID(), append, follow_folder_links));  	}  	else  	{ -		wear_inventory_category_on_avatar_step2(TRUE, category->getUUID(), append ); +		wear_inventory_category_on_avatar_step2(TRUE, category->getUUID(), append, follow_folder_links );  	}  } -void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append ) +void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links )  {  	// Find all the wearables that are in the category's subtree.	  	lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl; @@ -4109,7 +4170,8 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO  										cat_array,  										item_array,  										LLInventoryModel::EXCLUDE_TRASH, -										is_wearable); +										is_wearable, +										follow_folder_links);  		S32 i;  		S32 wearable_count = item_array.count(); @@ -4120,7 +4182,8 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO  										obj_cat_array,  										obj_item_array,  										LLInventoryModel::EXCLUDE_TRASH, -										is_object); +										is_object, +										follow_folder_links);  		S32 obj_count = obj_item_array.count();  		// Find all gestures in this folder @@ -4131,7 +4194,8 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO  										gest_cat_array,  										gest_item_array,  										LLInventoryModel::EXCLUDE_TRASH, -										is_gesture); +										is_gesture, +										follow_folder_links);  		S32 gest_count = gest_item_array.count();  		if( !wearable_count && !obj_count && !gest_count) @@ -4139,11 +4203,26 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO  			LLNotifications::instance().add("CouldNotPutOnOutfit");  			return;  		} +		 +		const LLUUID ¤t_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); -		// Processes that take time should show the busy cursor  		if (wearable_count > 0 || obj_count > 0)  		{ +			// Processes that take time should show the busy cursor  			inc_busy_count(); +			 +			// Remove all current outfit folder links if we're now replacing the contents. +			if (!append) +			{ +				LLInventoryModel::cat_array_t cat_array; +				LLInventoryModel::item_array_t item_array; +				gInventory.collectDescendents(current_outfit_id, cat_array, item_array, +											  LLInventoryModel::EXCLUDE_TRASH); +				for (i = 0; i < item_array.count(); ++i) +				{ +					gInventory.purgeObject(item_array.get(i)->getUUID()); +				} +			}  		}  		// Activate all gestures in this folder @@ -4184,8 +4263,14 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO  			for(i = 0; i < wearable_count; ++i)  			{  				gAddToOutfit = append; -  				found = found_container.get(i); +				 +				// Populate the current outfit folder with links to the newly added wearables +				std::string link_name = "WearableLink"; +				link_inventory_item(gAgent.getID(), found->mItemID, current_outfit_id, link_name, +									LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL)); + +				// Fetch the wearables about to be worn.  				LLWearableList::instance().getAsset(found->mAssetID,  										found->mName,  									   found->mAssetType, @@ -4240,9 +4325,9 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO  						msg->addBOOLFast(_PREHASH_FirstDetachAll, !append );  					} -					LLInventoryItem* item = obj_item_array.get(i); +					const LLInventoryItem* item = obj_item_array.get(i).get();  					msg->nextBlockFast(_PREHASH_ObjectData ); -					msg->addUUIDFast(_PREHASH_ItemID, item->getUUID() ); +					msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());  					msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());  					msg->addU8Fast(_PREHASH_AttachmentPt, 0 );	// Wear at the previous or default attachment point  					pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); @@ -4254,9 +4339,26 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO  						// End of message chunk  						msg->sendReliable( gAgent.getRegion()->getHost() );  					} + +				} + +				for(i = 0; i < obj_count; ++i) +				{ +					const std::string link_name = "AttachmentLink"; +					const LLInventoryItem* item = obj_item_array.get(i).get(); +					link_inventory_item(gAgent.getID(), item->getLinkedUUID(), current_outfit_id, link_name, +										LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));  				}  			}  		} + +		// Create a link to the folder that we wore. +		LLViewerInventoryCategory* catp = gInventory.getCategory(category); +		if (catp) +		{ +			link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(), +								LLAssetType::AT_LINK_FOLDER, LLPointer<LLInventoryCallback>(NULL)); +		}  	}  } @@ -4583,7 +4685,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)  			items.push_back(std::string("Open"));  		} -		if (item && LLAssetType::lookupIsLinkType(item->getActualType())) +		if (item && item->getIsLinkType())  		{  			items.push_back(std::string("Goto Link"));  		} diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 915dfec629..5cfebe6c15 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -157,6 +157,7 @@ public:  	}  	virtual std::string getLabelSuffix() const { return LLStringUtil::null; }  	virtual void openItem() {} +	virtual void closeItem() {}  	virtual void gotoItem(LLFolderView *folder) {} // for links  	virtual void previewItem() {openItem();}  	virtual void showProperties(); @@ -271,6 +272,7 @@ public:  								BOOL drop);  	virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);  	virtual void openItem(); +	virtual void closeItem();  	virtual BOOL isItemRenameable() const;  	virtual void selectItem();  	virtual void restoreItem(); @@ -325,6 +327,8 @@ protected:  	BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck);  	void modifyOutfit(BOOL append); +	void determineFolderType(); +  public:  	static LLFolderBridge* sSelf;  	static void staticFolderOptionsMenu(); diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 9cbe11f5c9..596211f16c 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -39,6 +39,7 @@  #include "llfolderviewitem.h"  #include "llinventorymodel.h"	// gInventory.backgroundFetchActive()  #include "llviewercontrol.h" +#include "llviewerinventory.h"  // linden library includes  #include "lltrans.h" @@ -51,12 +52,13 @@ LLInventoryFilter::LLInventoryFilter(const std::string& name)  	mModified(FALSE),  	mNeedTextRebuild(TRUE)  { -	mFilterOps.mFilterTypes = 0xffffffff; +	mFilterOps.mFilterTypes = 0xffffffffffffffffULL;  	mFilterOps.mMinDate = time_min();  	mFilterOps.mMaxDate = time_max();  	mFilterOps.mHoursAgo = 0;  	mFilterOps.mShowFolderState = SHOW_NON_EMPTY_FOLDERS;  	mFilterOps.mPermissions = PERM_NONE; +	mFilterOps.mFilterForCategories = FALSE;  	mOrder = SO_FOLDERS_BY_NAME; // This gets overridden by a pref immediately @@ -94,7 +96,25 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item)  	}  	LLFolderViewEventListener* listener = item->getListener();  	mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; -	BOOL passed = (0x1 << listener->getInventoryType() & mFilterOps.mFilterTypes || listener->getInventoryType() == LLInventoryType::IT_NONE) + +	bool passed_type = false; +	if (mFilterOps.mFilterForCategories) +	{ +		if (listener->getInventoryType() == LLInventoryType::IT_CATEGORY) +		{ +			LLViewerInventoryCategory *cat = gInventory.getCategory(listener->getUUID()); +			if (cat) +			{ +				passed_type |= ((1LL << cat->getPreferredType() & mFilterOps.mFilterTypes) != U64(0)); +			} +		} +	} +	else +	{ +		passed_type |= ((1LL << listener->getInventoryType() & mFilterOps.mFilterTypes) != U64(0)) || listener->getInventoryType() == LLInventoryType::IT_NONE; +	} + +	BOOL passed = passed_type  		&& (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos)  		&& ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions)  		&& (listener->getCreationDate() >= earliest && listener->getCreationDate() <= mFilterOps.mMaxDate); @@ -124,7 +144,7 @@ BOOL LLInventoryFilter::isNotDefault()  BOOL LLInventoryFilter::isActive()  { -	return mFilterOps.mFilterTypes != 0xffffffff  +	return mFilterOps.mFilterTypes != 0xffffffffffffffffULL   		|| mFilterSubString.size()   		|| mFilterOps.mPermissions != PERM_NONE   		|| mFilterOps.mMinDate != time_min() @@ -144,7 +164,7 @@ BOOL LLInventoryFilter::isModifiedAndClear()  	return ret;  } -void LLInventoryFilter::setFilterTypes(U32 types) +void LLInventoryFilter::setFilterTypes(U64 types, BOOL filter_for_categories)  {  	if (mFilterOps.mFilterTypes != types)  	{ @@ -168,8 +188,8 @@ void LLInventoryFilter::setFilterTypes(U32 types)  		{  			setModified(FILTER_MORE_RESTRICTIVE);  		} -  	} +	mFilterOps.mFilterForCategories = filter_for_categories;  }  void LLInventoryFilter::setFilterSubString(const std::string& string) @@ -374,7 +394,7 @@ void LLInventoryFilter::setModified(EFilterBehavior behavior)  BOOL LLInventoryFilter::isFilterWith(LLInventoryType::EType t)  { -	return mFilterOps.mFilterTypes & (0x01 << t); +	return mFilterOps.mFilterTypes & (1LL << t);  }  std::string LLInventoryFilter::getFilterText() diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 7c5f6681cf..670b1f000b 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -64,7 +64,7 @@ public:  	LLInventoryFilter(const std::string& name);  	virtual ~LLInventoryFilter(); -	void setFilterTypes(U32 types); +	void setFilterTypes(U64 types, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type  	U32 getFilterTypes() const { return mFilterOps.mFilterTypes; }  	void setFilterSubString(const std::string& string); @@ -120,7 +120,8 @@ public:  protected:  	struct filter_ops  	{ -		U32			mFilterTypes; +		U64			mFilterTypes; +		BOOL        mFilterForCategories;  		time_t		mMinDate;  		time_t		mMaxDate;  		U32			mHoursAgo; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index b4bd312cc0..d5d2897383 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -434,7 +434,8 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,  											cat_array_t& cats,  											item_array_t& items,  											BOOL include_trash, -											LLInventoryCollectFunctor& add) +											LLInventoryCollectFunctor& add, +											BOOL follow_folder_links)  {  	// Start with categories  	if(!include_trash) @@ -458,9 +459,38 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,  		}  	} -	// Move onto items  	LLViewerInventoryItem* item = NULL;  	item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + +	// Follow folder links recursively.  Currently never goes more +	// than one level deep (for current outfit support) +	// Note: if making it fully recursive, need more checking against infinite loops. +	if (follow_folder_links && item_array) +	{ +		S32 count = item_array->count(); +		for(S32 i = 0; i < count; ++i) +		{ +			item = item_array->get(i); +			if (item->getActualType() == LLAssetType::AT_LINK_FOLDER) +			{ +				// BAP either getLinkedCategory() should return non-const, or the functor should take const. +				LLViewerInventoryCategory *linked_cat = const_cast<LLViewerInventoryCategory*>(item->getLinkedCategory()); +				if (linked_cat) +				{ +					if(add(linked_cat,NULL)) +					{ +						// BAP should this be added here?  May not +						// matter if it's only being used in current +						// outfit traversal. +						cats.put(LLPointer<LLViewerInventoryCategory>(linked_cat)); +					} +					collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); +				} +			} +		} +	} +	 +	// Move onto items  	if(item_array)  	{  		S32 count = item_array->count(); @@ -872,7 +902,7 @@ void LLInventoryModel::purgeLinkedObjects(const LLUUID &id)  	LLInventoryObject* objectp = getObject(id);  	if (!objectp) return; -	if (LLAssetType::lookupIsLinkType(objectp->getActualType())) +	if (objectp->getIsLinkType())  	{  		return;  	} @@ -1196,14 +1226,14 @@ void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::str  	gInventory.notifyObservers("fetchinventory");  } -void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) +bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)  {  	LLViewerInventoryCategory* cat = getCategory(folder_id);  	if(!cat)  	{  		llwarns << "Asked to fetch descendents of non-existent folder: "  				<< folder_id << llendl; -		return; +		return false;  	}  	//S32 known_descendents = 0;  	///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); @@ -1216,10 +1246,7 @@ void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)  	//{  	//	known_descendents += items->count();  	//} -	if(!cat->fetchDescendents()) -	{ -		//llinfos << "Not fetching descendents" << llendl; -	} +	return cat->fetchDescendents();  }  //Initialize statics. @@ -1337,6 +1364,7 @@ void  fetchDescendentsResponder::result(const LLSD& content)  			{  				cat->setVersion(version);  				cat->setDescendentCount(descendents); +				cat->determineFolderType();  			}  		} @@ -4059,7 +4087,7 @@ bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* ite  bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  {  	return (item &&  -			(LLAssetType::lookupIsLinkType(item->getActualType())) && +			(item->getIsLinkType()) &&  			(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.  } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index f470a77985..e38447a8f2 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -185,7 +185,8 @@ public:  							  cat_array_t& categories,  							  item_array_t& items,  							  BOOL include_trash, -							  LLInventoryCollectFunctor& add); +							  LLInventoryCollectFunctor& add, +							  BOOL follow_folder_links = FALSE);  	// Collect all items in inventory that are linked to item_id.  	// Assumes item_id is itself not a linked item. @@ -296,8 +297,9 @@ public:  	// minimal functionality before the actual arrival of inventory.  	//void mock(const LLUUID& root_id); -	// make sure we have the descendents in the structure. -	void fetchDescendentsOf(const LLUUID& folder_id); +	// Make sure we have the descendents in the structure.  Returns true +	// if a fetch was performed. +	bool fetchDescendentsOf(const LLUUID& folder_id);  	// Add categories to a list to be fetched in bulk.  	static void bulkFetch(std::string url); diff --git a/indra/newview/lllookshistorypanel.h b/indra/newview/lllookshistorypanel.h new file mode 100644 index 0000000000..986c9a1c4d --- /dev/null +++ b/indra/newview/lllookshistorypanel.h @@ -0,0 +1,72 @@ +/**  + * @file llpanelteleporthistory.h + * @brief Teleport history represented by a scrolling list + * class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELLOOKSHISTORY_H +#define LL_LLPANELLOOKSHISTORY_H + +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" + +#include "llpanelappearancetab.h" +#include "lllookshistory.h" + +class LLLooksHistoryPanel : public LLPanelAppearanceTab +{ +public: +	LLLooksHistoryPanel(); +	virtual ~LLLooksHistoryPanel(); + +	/*virtual*/ BOOL postBuild(); +	/*virtual*/ void onSearchEdit(const std::string& string); +	/*virtual*/ void onShowOnMap(); +	/*virtual*/ void onLooks(); +	///*virtual*/ void onCopySLURL(); + +	void showLooksHistory(); +	void handleItemSelect(const LLSD& data); + +	static void onDoubleClickItem(void* user_data); + +private: +	enum LOOKS_HISTORY_COLUMN_ORDER +	{ +		LIST_ICON, +		LIST_ITEM_TITLE, +		LIST_INDEX +	}; + +	LLLooksHistory*		mLooksHistory; +	LLScrollListCtrl*		mHistoryItems; +	std::string				mFilterSubString; +}; + +#endif //LL_LLPANELLOOKSHISTORY_H diff --git a/indra/newview/llpanelappearancetab.h b/indra/newview/llpanelappearancetab.h new file mode 100644 index 0000000000..8a9ba66ec0 --- /dev/null +++ b/indra/newview/llpanelappearancetab.h @@ -0,0 +1,65 @@ +/**  + * @file llpanelplacestab.h + * @brief Tabs interface for Side Bar "Places" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2004-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELAPPEARANCETAB_H +#define LL_LLPANELAPPEARANCETAB_H + +#include "llpanel.h" + +#include "llpanelappearance.h" + +class LLPanelAppearanceTab : public LLPanel +{ +public: +	LLPanelAppearanceTab(LLPanelAppearance *parent) :  +		LLPanel(), +		mParent(parent) +	{} +	virtual ~LLPanelAppearanceTab() {} + +	virtual void onSearchEdit(const std::string& string) = 0; +	virtual void updateVerbs() = 0;		// Updates buttons at the bottom of Appearance panel +	virtual void onWear() = 0; +	virtual void onEdit() = 0; +	virtual void onNew() = 0; + +	bool isTabVisible(); // Check if parent TabContainer is visible. + +	void setPanelAppearanceButtons(LLPanelAppearance* panel); + + +protected: +	LLButton*				mWearBtn; +	LLButton*				mEditBtn; +	LLPanelAppearance*		mParent; +}; + +#endif //LL_LLPANELAPPEARANCETAB_H diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 820abe2fbd..78e8f084c7 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -37,6 +37,7 @@  #include "indra_constants.h"  #include "llagent.h" +#include "llfoldertype.h"  #include "llviewercontrol.h"  #include "llconsole.h"  #include "llinventorymodel.h" @@ -587,6 +588,79 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const  	return true;  } +void LLViewerInventoryCategory::determineFolderType() +{ +	LLAssetType::EType original_type = getPreferredType(); +	if (LLAssetType::lookupIsProtectedCategoryType(original_type)) +		return; + +	U64 folder_valid = 0; +	U64 folder_invalid = 0; +	LLInventoryModel::cat_array_t category_array; +	LLInventoryModel::item_array_t item_array; +	gInventory.collectDescendents(getUUID(),category_array,item_array,FALSE); + +	// For ensembles +	if (category_array.empty()) +	{ +		for (LLInventoryModel::item_array_t::iterator item_iter = item_array.begin(); +			 item_iter != item_array.end(); +			 item_iter++) +		{ +			const LLViewerInventoryItem *item = (*item_iter); +			if (item->getIsLinkType()) +				return; +			if (item->getInventoryType() == LLInventoryType::IT_WEARABLE) +			{ +				U32 flags = item->getFlags(); +				if (flags > WT_COUNT) +					return; +				const EWearableType wearable_type = EWearableType(flags); +				const std::string& wearable_name = LLWearableDictionary::getTypeName(wearable_type); +				U64 valid_folder_types = LLFolderType::lookupValidFolderTypes(wearable_name); +				folder_valid |= valid_folder_types; +				folder_invalid |= ~valid_folder_types; +			} +		} +		for (U8 i = LLAssetType::AT_FOLDER_ENSEMBLE_START; i <= LLAssetType::AT_FOLDER_ENSEMBLE_END; i++) +		{ +			if ((folder_valid & (1LL << i)) && +				!(folder_invalid & (1LL << i))) +			{ +				changeType((LLAssetType::EType)i); +				return; +			} +		} +	} +	if (LLAssetType::lookupIsEnsembleCategoryType(original_type)) +	{ +		changeType(LLAssetType::AT_NONE); +	} +} + +void LLViewerInventoryCategory::changeType(LLAssetType::EType new_folder_type) +{ +	const LLUUID &folder_id = getUUID(); +	const LLUUID &parent_id = getParentUUID(); +	const std::string &name = getName(); +		 +	LLMessageSystem* msg = gMessageSystem; +	msg->newMessageFast(_PREHASH_UpdateInventoryFolder); +	msg->nextBlockFast(_PREHASH_AgentData); +	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +	msg->nextBlockFast(_PREHASH_FolderData); +	msg->addUUIDFast(_PREHASH_FolderID, folder_id); +	msg->addUUIDFast(_PREHASH_ParentID, parent_id); +	msg->addS8Fast(_PREHASH_Type, new_folder_type); +	msg->addStringFast(_PREHASH_Name, name); +	gAgent.sendReliableMessage(); + +	setPreferredType(new_folder_type); +	gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); +	gInventory.updateLinkedObjects(folder_id);	 +} +  ///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- @@ -880,16 +954,23 @@ void menu_create_inventory_item(LLFolderView* folder, LLFolderBridge *bridge, co  {  	std::string type = userdata.asString(); -	if ("category" == type) +	if (("category" == type) || ("current" == type) || ("outfit" == type) || ("my_otfts" == type) )  	{ +		LLAssetType::EType a_type = LLAssetType::AT_NONE; +		if ("current" == type) +			a_type = LLAssetType::AT_CURRENT_OUTFIT; +		if ("outfit" == type) +			a_type = LLAssetType::AT_OUTFIT; +		if ("my_otfts" == type) +			a_type = LLAssetType::AT_MY_OUTFITS;  		LLUUID category;  		if (bridge)  		{ -			category = gInventory.createNewCategory(bridge->getUUID(), LLAssetType::AT_NONE, LLStringUtil::null); +			category = gInventory.createNewCategory(bridge->getUUID(), a_type, LLStringUtil::null);  		}  		else  		{ -			category = gInventory.createNewCategory(gInventory.getRootFolderID(), LLAssetType::AT_NONE, LLStringUtil::null); +			category = gInventory.createNewCategory(gInventory.getRootFolderID(), a_type, LLStringUtil::null);  		}  		gInventory.notifyObservers();  		folder->setSelectionByID(category, TRUE); @@ -1029,6 +1110,11 @@ const std::string& LLViewerInventoryItem::getName() const  const LLPermissions& LLViewerInventoryItem::getPermissions() const  { +	if (const LLViewerInventoryItem *linked_item = getLinkedItem()) +	{ +		return linked_item->getPermissions(); +	} +  	// Use the actual permissions of the symlink, not its parent.  	return LLInventoryItem::getPermissions();	  } @@ -1070,6 +1156,13 @@ LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const  		return linked_item->getInventoryType();  	} +	// Categories don't have types.  If this item is an AT_FOLDER_LINK, +	// treat it as a category. +	if (getLinkedCategory()) +	{ +		return LLInventoryType::IT_CATEGORY; +	} +  	return LLInventoryItem::getInventoryType();  } @@ -1079,7 +1172,6 @@ U32 LLViewerInventoryItem::getFlags() const  	{  		return linked_item->getFlags();  	} -  	return LLInventoryItem::getFlags();  } diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 0ee9b21d3a..10309d023b 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -206,7 +206,8 @@ public:  	// other than cacheing.  	bool exportFileLocal(LLFILE* fp) const;  	bool importFileLocal(LLFILE* fp); - +	void determineFolderType(); +	void changeType(LLAssetType::EType new_folder_type);  protected:  	LLUUID mOwnerID;  	S32 mVersion; diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Off.pngBinary files differ new file mode 100644 index 0000000000..2dc32a576b --- /dev/null +++ b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Off.png diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Selected.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Selected.pngBinary files differ new file mode 100644 index 0000000000..bea218a2fb --- /dev/null +++ b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Selected.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 69742c6ecd..4b6f8ac43c 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -174,6 +174,9 @@    <texture name="Stepper_Up_Off" file_name="widgets/Stepper_Up_Off.png" preload="true"/>    <texture name="Stepper_Up_Press" file_name="widgets/Stepper_Up_Press.png" preload="true"/> +  <texture name="TabIcon_Appearance_Off" file_name="taskpanel/TabIcon_Appearance_Off.png" preload="false" /> +  <texture name="TabIcon_Appearance_Over" file_name="taskpanel/TabIcon_Appearance_Over.png" preload="false"/> +  <texture name="TabIcon_Appearance_Selected" file_name="taskpanel/TabIcon_Appearance_Selected.png" preload="false" />    <texture name="TabIcon_Close_Off" file_name="taskpanel/TabIcon_Close_Off.png" preload="false" />    <texture name="TabIcon_Close_Over" file_name="taskpanel/TabIcon_Close_Over.png" preload="false"/>    <texture name="TabIcon_Home_Off" file_name="taskpanel/TabIcon_Home_Off.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml index 37c6cbf391..610c62a21a 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -207,6 +207,22 @@                   parameter="category" />              </menu_item_call>              <menu_item_call +             label="New Outfit" +             layout="topleft" +             name="New Outfit"> +                <menu_item_call.on_click +                 function="Inventory.DoCreate" +                 parameter="outfit" /> +            </menu_item_call> +            <menu_item_call +             label="New My Outfits" +             layout="topleft" +             name="New My Outfits"> +                <menu_item_call.on_click +                 function="Inventory.DoCreate" +                 parameter="my_otfts" /> +            </menu_item_call> +            <menu_item_call               label="New Script"               layout="topleft"               name="New Script"> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index c788f8f095..dd8acea4ed 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -85,6 +85,22 @@           parameter="current" />      </menu_item_call>      <menu_item_call +       label="New Outfit" +       layout="topleft" +       name="New Outfit"> +      <menu_item_call.on_click +         function="Inventory.DoCreate" +         parameter="outfit" /> +    </menu_item_call> +    <menu_item_call +       label="New My Outfits" +       layout="topleft" +       name="New My Outfits"> +      <menu_item_call.on_click +         function="Inventory.DoCreate" +         parameter="my_otfts" /> +    </menu_item_call> +    <menu_item_call       label="New Script"       layout="topleft"       name="New Script"> @@ -322,6 +338,14 @@               function="Inventory.DoToSelected"               parameter="change_folder_type_undershirt" />          </menu_item_call> +        <menu_item_call +         label="Outfit" +         layout="topleft" +         name="Outfit"> +            <menu_item_call.on_click +             function="Inventory.DoToSelected" +             parameter="change_folder_type_outfit" /> +        </menu_item_call>      </menu>      <menu_item_call       label="Teleport" diff --git a/indra/newview/skins/default/xui/en/panel_side_tray.xml b/indra/newview/skins/default/xui/en/panel_side_tray.xml index a7b66d8555..58be74a598 100644 --- a/indra/newview/skins/default/xui/en/panel_side_tray.xml +++ b/indra/newview/skins/default/xui/en/panel_side_tray.xml @@ -74,7 +74,7 @@          class="panel_places"           name="panel_places"           filename="panel_places.xml"  -        label="Places"  +        label="Places"          border="true"        />    </sidetray_tab> @@ -586,5 +586,25 @@    </sidetray_tab>   -->  + +  <sidetray_tab +    name="sidebar_appearance" +    tab_title="Appearance" +    description="Change your looks and appearance." +    image="TabIcon_Appearance_Off" +    mouse_opaque="false"  +    background_opaque="false"  +    background_visible="true"  +    bg_opaque_color="0.5 0.5 0.5 1.0" +  > +      <panel  +        class="panel_appearance" +        name="panel_appearance"  +        filename="panel_appearance.xml"  +        border="true"  +      /> +  </sidetray_tab> + +  </side_tray> diff --git a/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml index a85662603d..f10161cecd 100644 --- a/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml +++ b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml @@ -85,6 +85,31 @@        				mouse_opaque="false" name="tab_description" >      					Change your profile, your look and quick links to your outfits.    				</text> +		</panel> +		<panel  +			left="10" width="280" height="130"  +			background_visible="true"  +			background_opaque="false"  +			bg_alpha_color="0.3 0.3 0.3 1.0"  +			name="sidebar_appearance" +			follows="left|top|right" +			class="panel_sidetray_home_info"> +    			<text +        			top="-10" width="200" left="5" height="30" follows="left|right|top" +        			font="SansSerifHugeBold" text_color="white" word_wrap="true" +        			mouse_opaque="false" name="tab_name" > +					Appearance +    			</text> +    			<icon +      				top="-10" right="-10" width="20" height="20" follows="top|right" +      				color="1 1 1 1" enabled="true" image_name="inv_item_shirt.tga" +      				mouse_opaque="false" name="tab_icon"/> +  				<text +      				top="-40" left="10" right="-10" height="120" follows="left|right|bottom" +      				font="SansSerifBig" text_color="white" word_wrap="true" +      				mouse_opaque="false" name="tab_description" >     +					Change your appearance. +  				</text>  		</panel>   </panel>     
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index ec4898448a..0ed473a01a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -409,6 +409,8 @@ this texture in your inventory  	<string name="InvFolder Animations">Animations</string>  	<string name="InvFolder Gestures">Gestures</string>  	<string name="InvFolder favorite">Favorites</string> +	<string name="InvFolder Current Outfit">Current Outfit</string> +	<string name="InvFolder My Outfits">My Outfits</string>  	<!-- inventory FVBridge -->  	<string name="Buy">Buy</string> | 
