diff options
| author | Igor Borovkov <iborovkov@productengine.com> | 2010-04-21 12:43:03 +0300 | 
|---|---|---|
| committer | Igor Borovkov <iborovkov@productengine.com> | 2010-04-21 12:43:03 +0300 | 
| commit | ccd0418ddf75dabe7101d2faa16c39213e344925 (patch) | |
| tree | 7529cb64778610b7fe23ff80364181667341bcfe | |
| parent | 5acf8a5f13e064fcfb5d8fbd42e631a18244a674 (diff) | |
completed EXT-6719 Utilize the "description" field of outfit wearable links to store order information
- COF items get checked for correct ordering when COF is loaded (LLAppearanceMgr::updateAppearanceFromCOF..., LLAppearanceMgr::updateClothingOrderingInfo() ), and also when COF is saved to a new outfit, base outfit.
- wearables are arranged in LLAgentWearables in a proper order
* updateClothingOrderingInfo() [struggling with naming] does integrity checking and updates "invalid" items (items with wrong, gapped descriptions)
* moved LLAgentWearables::makeNewOutfitLinks(...) and LLShowCreatedOutfit  to a more natural place (llappearancemgr.cpp), because they use LLAppearanceMgr's methods a lot
* changed link_inventory_item(...), added the "new_description" parameter
Reviewed by Neal Orman at https://codereview.productengine.com/secondlife/r/268/
--HG--
branch : product-engine
| -rw-r--r-- | indra/newview/llagentwearables.cpp | 18 | ||||
| -rw-r--r-- | indra/newview/llagentwearables.h | 3 | ||||
| -rw-r--r-- | indra/newview/llagentwearablesfetch.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llappearancemgr.cpp | 216 | ||||
| -rw-r--r-- | indra/newview/llappearancemgr.h | 11 | ||||
| -rw-r--r-- | indra/newview/llinventorybridge.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llpaneloutfitsinventory.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerinventory.cpp | 4 | ||||
| -rw-r--r-- | indra/newview/llviewerinventory.h | 1 | 
9 files changed, 218 insertions, 41 deletions
| diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 7f248eee30..7a088fc7bf 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1361,24 +1361,6 @@ private:  	LLUUID mFolderID;  }; -LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name) -{ -	if (!isAgentAvatarValid()) return LLUUID::null; - -	// First, make a folder in the My Outfits directory. -	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	LLUUID folder_id = gInventory.createNewCategory( -		parent_id, -		LLFolderType::FT_OUTFIT, -		new_folder_name); - -	LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id); -	LLAppearanceMgr::instance().shallowCopyCategoryContents(LLAppearanceMgr::instance().getCOF(),folder_id, cb); -	LLAppearanceMgr::instance().createBaseOutfitLink(folder_id, cb); - -	return folder_id; -} -  void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)  {  	LLUUID first_item_id = getWearableItemID((EWearableType)type, index); diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index b76367324c..585fd3f8b3 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -169,8 +169,7 @@ public:  								  const LLDynamicArray<S32>& wearables_to_include,  								  const LLDynamicArray<S32>& attachments_to_include,  								  BOOL rename_clothing); -	 -	LLUUID			makeNewOutfitLinks(const std::string& new_folder_name); +  	// Should only be called if we *know* we've never done so before, since users may  	// not want the Library outfits to stay in their quick outfit selector and can delete them. diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp index 08d8ccfd23..03d09a3798 100644 --- a/indra/newview/llagentwearablesfetch.cpp +++ b/indra/newview/llagentwearablesfetch.cpp @@ -119,6 +119,7 @@ public:  								item->getLinkedUUID(),  								LLAppearanceMgr::instance().getCOF(),  								item->getName(), +								item->getDescription(),  								LLAssetType::AT_LINK,  								link_waiter);  		} @@ -507,6 +508,7 @@ void LLLibraryOutfitsFetch::contentsDone()  								item->getLinkedUUID(),  								new_outfit_folder_id,  								item->getName(), +								item->getDescription(),  								LLAssetType::AT_LINK,  								NULL);  		} diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 4d18ff57fe..9e02886e4f 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -32,6 +32,7 @@  #include "llviewerprecompiledheaders.h" +#include "llaccordionctrltab.h"  #include "llagent.h"  #include "llagentwearables.h"  #include "llappearancemgr.h" @@ -42,6 +43,7 @@  #include "llinventoryfunctions.h"  #include "llinventoryobserver.h"  #include "llnotificationsutil.h" +#include "llpaneloutfitsinventory.h"  #include "llselectmgr.h"  #include "llsidepanelappearance.h"  #include "llsidetray.h" @@ -51,6 +53,8 @@  #include "llviewerregion.h"  #include "llwearablelist.h" +char ORDER_NUMBER_SEPARATOR('@'); +  LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name)  {  	LLInventoryModel::cat_array_t cat_array; @@ -400,6 +404,7 @@ public:  					     item_id,  					     LLAppearanceMgr::instance().getCOF(),  					     itemp->getName(), +						 itemp->getDescription(),  					     LLAssetType::AT_LINK,  					     cb);  		} @@ -691,10 +696,13 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  		{  			case LLAssetType::AT_LINK:  			{ +				//LLInventoryItem::getDescription() is used for a new description  +				//to propagate ordering information saved in descriptions of links  				link_inventory_item(gAgent.getID(),  									item->getLinkedUUID(),  									dst_id,  									item->getName(), +									item->LLInventoryItem::getDescription(),  									LLAssetType::AT_LINK, cb);  				break;  			} @@ -708,6 +716,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  										item->getLinkedUUID(),  										dst_id,  										item->getName(), +										item->getDescription(),  										LLAssetType::AT_LINK_FOLDER, cb);  				}  				break; @@ -811,20 +820,7 @@ void LLAppearanceMgr::filterWearableItems(  {  	// Divvy items into arrays by wearable type.  	std::vector<LLInventoryModel::item_array_t> items_by_type(WT_COUNT); -	for (S32 i=0; i<items.count(); i++) -	{ -		LLViewerInventoryItem *item = items.get(i); -		// Ignore non-wearables. -		if (!item->isWearableType()) -			continue; -		EWearableType type = item->getWearableType(); -		if(type < 0 || type >= WT_COUNT) -		{ -			LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; -			continue; -		} -		items_by_type[type].push_back(item); -	} +	divvyWearablesByType(items, items_by_type);  	// rebuild items list, retaining the last max_per_type of each array  	items.clear(); @@ -853,6 +849,7 @@ void LLAppearanceMgr::linkAll(const LLUUID& category,  							item->getLinkedUUID(),  							category,  							item->getName(), +							item->LLInventoryItem::getDescription(),  							LLAssetType::AT_LINK,  							cb);  	} @@ -956,7 +953,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI  	if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)  	{ -		link_inventory_item(gAgent.getID(), category, cof, catp->getName(), +		link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "",  							LLAssetType::AT_LINK_FOLDER, link_waiter);  		new_outfit_name = catp->getName();  	} @@ -1016,6 +1013,18 @@ static void remove_non_link_items(LLInventoryModel::item_array_t &items)  	items = pruned_items;  } +//a predicate for sorting inventory items by actual descriptions +bool sort_by_description(const LLInventoryItem* item1, const LLInventoryItem* item2) +{ +	if (!item1 || !item2)  +	{ +		llwarning("either item1 or item2 is NULL", 0); +		return true; +	} + +	return item1->LLInventoryItem::getDescription() < item2->LLInventoryItem::getDescription(); +} +  void LLAppearanceMgr::updateAppearanceFromCOF()  {  	// update dirty flag to see if the state of the COF matches @@ -1026,6 +1035,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF()  	dumpCat(getCOF(),"COF, start"); +	updateClothingOrderingInfo(); +  	bool follow_folder_links = true;  	LLUUID current_outfit_id = getCOF(); @@ -1046,6 +1057,9 @@ void LLAppearanceMgr::updateAppearanceFromCOF()  		return;  	} +	//preparing the list of wearables in the correct order for LLAgentWearables +	std::sort(wear_items.begin(), wear_items.end(), sort_by_description); +  	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;  	holder->mObjItems = obj_items; @@ -1079,8 +1093,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF()  			}  #endif - -			holder->mFoundList.push_front(found); +			//pushing back, not front, to preserve order of wearables for LLAgentWearables +			holder->mFoundList.push_back(found);  		}  		else  		{ @@ -1407,7 +1421,7 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update  		// Are these links to different items of the same wearable  		// type? If so, new item will replace old.  		// MULTI-WEARABLES: revisit if more than one per type is allowed. -		else if (areMatchingWearables(vitem,inv_item)) +		else if (FALSE/*areMatchingWearables(vitem,inv_item)*/)  		{  			if (inv_item->getIsLinkType())  			{ @@ -1430,6 +1444,7 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update  							 vitem->getLinkedUUID(),  							 getCOF(),  							 vitem->getName(), +							 vitem->getDescription(),  							 LLAssetType::AT_LINK,  							 cb);  	} @@ -1446,6 +1461,7 @@ void LLAppearanceMgr::addEnsembleLink( LLInventoryCategory* cat, bool do_update  						 cat->getLinkedUUID(),  						 getCOF(),  						 cat->getName(), +						 cat->getDescription(),  						 LLAssetType::AT_LINK_FOLDER,  						 cb);  #endif @@ -1572,6 +1588,8 @@ bool LLAppearanceMgr::updateBaseOutfit()  	const LLUUID base_outfit_id = getBaseOutfitUUID();  	if (base_outfit_id.isNull()) return false; +	updateClothingOrderingInfo(); +  	// in a Base Outfit we do not remove items, only links  	purgeCategory(base_outfit_id, false); @@ -1581,6 +1599,168 @@ bool LLAppearanceMgr::updateBaseOutfit()  	return true;  } +void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type) +{ +	items_by_type.reserve(WT_COUNT); +	if (items.empty()) return; + +	for (S32 i=0; i<items.count(); i++) +	{ +		LLViewerInventoryItem *item = items.get(i); +		// Ignore non-wearables. +		if (!item->isWearableType()) +			continue; +		EWearableType type = item->getWearableType(); +		if(type < 0 || type >= WT_COUNT) +		{ +			LL_WARNS("Appearance") << "Invalid wearable type. Inventory type does not match wearable flag bitfield." << LL_ENDL; +			continue; +		} +		items_by_type[type].push_back(item); +	} +} + +std::string build_order_string(EWearableType type, U32 i) +{ +		std::ostringstream order_num; +		order_num << ORDER_NUMBER_SEPARATOR << type * 100 + i; +		return order_num.str(); +} + +struct WearablesOrderComparator +{ +	WearablesOrderComparator(const EWearableType type) +	{ +		mControlSize = build_order_string(type, 0).size(); +	}; + +	bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2) +	{ +		if (!item1 || !item2) +		{ +			llwarning("either item1 or item2 is NULL", 0); +			return true; +		} +		 +		const std::string& desc1 = item1->LLInventoryItem::getDescription(); +		const std::string& desc2 = item2->LLInventoryItem::getDescription(); +		 +		bool item1_valid = (desc1.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc1[0]); +		bool item2_valid = (desc2.size() == mControlSize) && (ORDER_NUMBER_SEPARATOR == desc2[0]); + +		if (item1_valid && item2_valid) +			return desc1 < desc2; + +		//we need to sink down invalid items: items with empty descriptions, items with "Broken link" descriptions, +		//items with ordering information but not for the associated wearables type +		if (!item1_valid && item2_valid)  +			return false; + +		return true; +	} + +	U32 mControlSize; +}; + +void LLAppearanceMgr::updateClothingOrderingInfo() +{ +	LLInventoryModel::item_array_t wear_items; +	getDescendentsOfAssetType(getCOF(), wear_items, LLAssetType::AT_CLOTHING, false); + +	wearables_by_type_t items_by_type(WT_COUNT); +	divvyWearablesByType(wear_items, items_by_type); + +	bool inventory_changed = false; +	for (U32 type = WT_SHIRT; type < WT_COUNT; type++) +	{ +		 +		U32 size = items_by_type[type].size(); +		if (!size) continue; + +		//sinking down invalid items which need reordering +		std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((EWearableType) type)); + +		//requesting updates only for those links which don't have "valid" descriptions +		for (U32 i = 0; i < size; i++) +		{ +			LLViewerInventoryItem* item = items_by_type[type][i]; +			if (!item) continue; + +			std::string new_order_str = build_order_string((EWearableType)type, i); +			if (new_order_str == item->LLInventoryItem::getDescription()) continue; + +			item->setDescription(new_order_str); +			item->setComplete(TRUE); + 			item->updateServer(FALSE); +			gInventory.updateItem(item); +			inventory_changed = true; +		} +	} + +	//*TODO do we really need to notify observers? +	if (inventory_changed) gInventory.notifyObservers(); +} + + + + +class LLShowCreatedOutfit: public LLInventoryCallback +{ +public: +	LLShowCreatedOutfit(LLUUID& folder_id): mFolderID(folder_id) +	{} + +	virtual ~LLShowCreatedOutfit() +	{ +		LLSD key; +		LLSideTray::getInstance()->showPanel("panel_outfits_inventory", key); +		LLPanelOutfitsInventory *outfit_panel = +			dynamic_cast<LLPanelOutfitsInventory*>(LLSideTray::getInstance()->getPanel("panel_outfits_inventory")); +		if (outfit_panel) +		{ +			outfit_panel->getRootFolder()->clearSelection(); +			outfit_panel->getRootFolder()->setSelectionByID(mFolderID, TRUE); +		} +		 +		LLAccordionCtrlTab* tab_outfits = outfit_panel ? outfit_panel->findChild<LLAccordionCtrlTab>("tab_outfits") : 0; +		if (tab_outfits && !tab_outfits->getDisplayChildren()) +		{ +			tab_outfits->changeOpenClose(tab_outfits->getDisplayChildren()); +		} + +		LLAppearanceMgr::getInstance()->updateIsDirty(); +		LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); +	} + +	virtual void fire(const LLUUID&) +	{} + +private: +	LLUUID mFolderID; +}; + +LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name) +{ +	if (!isAgentAvatarValid()) return LLUUID::null; + +	// First, make a folder in the My Outfits directory. +	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); +	LLUUID folder_id = gInventory.createNewCategory( +		parent_id, +		LLFolderType::FT_OUTFIT, +		new_folder_name); + +	updateClothingOrderingInfo(); + +	LLPointer<LLInventoryCallback> cb = new LLShowCreatedOutfit(folder_id); +	shallowCopyCategoryContents(getCOF(),folder_id, cb); +	createBaseOutfitLink(folder_id, cb); + +	dumpCat(folder_id,"COF, new outfit"); + +	return folder_id; +} +  void LLAppearanceMgr::wearBaseOutfit()  {  	const LLUUID& base_outfit_id = getBaseOutfitUUID(); diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 7e35919892..efb5274c5b 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -138,12 +138,23 @@ public:  	//Remove clothing or detach an object from the agent (a bodypart cannot be removed)  	void removeItemFromAvatar(const LLUUID& item_id); + +	LLUUID makeNewOutfitLinks(const std::string& new_folder_name); +  protected:  	LLAppearanceMgr();  	~LLAppearanceMgr();  private: +	typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t; + +	//Divvy items into arrays by wearable type +	static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type); + +	//Check ordering information on wearables stored in links' descriptions and update if it is invalid +	void updateClothingOrderingInfo(); +  	void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type);  	void getDescendentsOfAssetType(const LLUUID& category,  diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index b85bf0d518..b4a1bf2758 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2520,6 +2520,7 @@ void LLFolderBridge::pasteLinkFromClipboard()  						item->getLinkedUUID(),  						parent_id,  						item->getName(), +						item->getDescription(),  						LLAssetType::AT_LINK,  						LLPointer<LLInventoryCallback>(NULL));  				} @@ -3166,6 +3167,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,  						inv_item->getLinkedUUID(),  						mUUID,  						inv_item->getName(), +						inv_item->getDescription(),  						LLAssetType::AT_LINK,  						cb);  				} diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index b78268da7b..367ce46ce6 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -216,7 +216,7 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD&  		LLStringUtil::trim(outfit_name);  		if( !outfit_name.empty() )  		{ -			LLUUID outfit_folder = gAgentWearables.makeNewOutfitLinks(outfit_name); +			LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name);  			LLSidepanelAppearance* panel_appearance =  				dynamic_cast<LLSidepanelAppearance *>(LLSideTray::getInstance()->getPanel("sidepanel_appearance")); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 8a891b1462..f434d15843 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -923,6 +923,7 @@ void link_inventory_item(  	const LLUUID& item_id,  	const LLUUID& parent_id,  	const std::string& new_name, +	const std::string& new_description,  	const LLAssetType::EType asset_type,  	LLPointer<LLInventoryCallback> cb)  { @@ -948,7 +949,6 @@ void link_inventory_item(  	}  	LLUUID transaction_id; -	std::string desc = "Broken link"; // This should only show if the object can't find its baseobj.  	LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;  	if (dynamic_cast<const LLInventoryCategory *>(baseobj))  	{ @@ -979,7 +979,7 @@ void link_inventory_item(  		msg->addS8Fast(_PREHASH_Type, (S8)asset_type);  		msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);  		msg->addStringFast(_PREHASH_Name, new_name); -		msg->addStringFast(_PREHASH_Description, desc); +		msg->addStringFast(_PREHASH_Description, new_description);  	}  	gAgent.sendReliableMessage();  } diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 9d449399e8..f296ce35ff 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -339,6 +339,7 @@ void link_inventory_item(  	const LLUUID& item_id,  	const LLUUID& parent_id,  	const std::string& new_name, +	const std::string& new_description,  	const LLAssetType::EType asset_type,  	LLPointer<LLInventoryCallback> cb); | 
