Commits

leyla_linden  committed a6f1043 Merge

Merge

  • Participants
  • Parent commits bae3fe9, 873527d

Comments (0)

Files changed (75)

File indra/llcommon/llassettype.cpp

 {
 	//       												   DESCRIPTION			TYPE NAME	HUMAN NAME			CAN LINK?   CAN FETCH?  CAN KNOW?	
 	//      												  |--------------------|-----------|-------------------|-----------|-----------|---------|
-	addEntry(LLAssetType::AT_TEXTURE, 			new AssetEntry("TEXTURE",			"texture",	"texture",			false,		false,		true));
-	addEntry(LLAssetType::AT_SOUND, 			new AssetEntry("SOUND",				"sound",	"sound",			false,		true,		true));
-	addEntry(LLAssetType::AT_CALLINGCARD, 		new AssetEntry("CALLINGCARD",		"callcard",	"calling card",		false,		false,		false));
-	addEntry(LLAssetType::AT_LANDMARK, 			new AssetEntry("LANDMARK",			"landmark",	"landmark",			false,		true,		true));
-	addEntry(LLAssetType::AT_SCRIPT, 			new AssetEntry("SCRIPT",			"script",	"legacy script",	false,		false,		false));
+	addEntry(LLAssetType::AT_TEXTURE, 			new AssetEntry("TEXTURE",			"texture",	"texture",			true,		false,		true));
+	addEntry(LLAssetType::AT_SOUND, 			new AssetEntry("SOUND",				"sound",	"sound",			true,		true,		true));
+	addEntry(LLAssetType::AT_CALLINGCARD, 		new AssetEntry("CALLINGCARD",		"callcard",	"calling card",		true,		false,		false));
+	addEntry(LLAssetType::AT_LANDMARK, 			new AssetEntry("LANDMARK",			"landmark",	"landmark",			true,		true,		true));
+	addEntry(LLAssetType::AT_SCRIPT, 			new AssetEntry("SCRIPT",			"script",	"legacy script",	true,		false,		false));
 	addEntry(LLAssetType::AT_CLOTHING, 			new AssetEntry("CLOTHING",			"clothing",	"clothing",			true,		true,		true));
 	addEntry(LLAssetType::AT_OBJECT, 			new AssetEntry("OBJECT",			"object",	"object",			true,		false,		false));
-	addEntry(LLAssetType::AT_NOTECARD, 			new AssetEntry("NOTECARD",			"notecard",	"note card",		false,		false,		true));
+	addEntry(LLAssetType::AT_NOTECARD, 			new AssetEntry("NOTECARD",			"notecard",	"note card",		true,		false,		true));
 	addEntry(LLAssetType::AT_CATEGORY, 			new AssetEntry("CATEGORY",			"category",	"folder",			true,		false,		false));
-	addEntry(LLAssetType::AT_LSL_TEXT, 			new AssetEntry("LSL_TEXT",			"lsltext",	"lsl2 script",		false,		false,		false));
-	addEntry(LLAssetType::AT_LSL_BYTECODE, 		new AssetEntry("LSL_BYTECODE",		"lslbyte",	"lsl bytecode",		false,		false,		false));
-	addEntry(LLAssetType::AT_TEXTURE_TGA, 		new AssetEntry("TEXTURE_TGA",		"txtr_tga",	"tga texture",		false,		false,		false));
+	addEntry(LLAssetType::AT_LSL_TEXT, 			new AssetEntry("LSL_TEXT",			"lsltext",	"lsl2 script",		true,		false,		false));
+	addEntry(LLAssetType::AT_LSL_BYTECODE, 		new AssetEntry("LSL_BYTECODE",		"lslbyte",	"lsl bytecode",		true,		false,		false));
+	addEntry(LLAssetType::AT_TEXTURE_TGA, 		new AssetEntry("TEXTURE_TGA",		"txtr_tga",	"tga texture",		true,		false,		false));
 	addEntry(LLAssetType::AT_BODYPART, 			new AssetEntry("BODYPART",			"bodypart",	"body part",		true,		true,		true));
-	addEntry(LLAssetType::AT_SOUND_WAV, 		new AssetEntry("SOUND_WAV",			"snd_wav",	"sound",			false,		false,		false));
-	addEntry(LLAssetType::AT_IMAGE_TGA, 		new AssetEntry("IMAGE_TGA",			"img_tga",	"targa image",		false,		false,		false));
-	addEntry(LLAssetType::AT_IMAGE_JPEG, 		new AssetEntry("IMAGE_JPEG",		"jpeg",		"jpeg image",		false,		false,		false));
-	addEntry(LLAssetType::AT_ANIMATION, 		new AssetEntry("ANIMATION",			"animatn",	"animation",		false,		true,		true));
+	addEntry(LLAssetType::AT_SOUND_WAV, 		new AssetEntry("SOUND_WAV",			"snd_wav",	"sound",			true,		false,		false));
+	addEntry(LLAssetType::AT_IMAGE_TGA, 		new AssetEntry("IMAGE_TGA",			"img_tga",	"targa image",		true,		false,		false));
+	addEntry(LLAssetType::AT_IMAGE_JPEG, 		new AssetEntry("IMAGE_JPEG",		"jpeg",		"jpeg image",		true,		false,		false));
+	addEntry(LLAssetType::AT_ANIMATION, 		new AssetEntry("ANIMATION",			"animatn",	"animation",		true,		true,		true));
 	addEntry(LLAssetType::AT_GESTURE, 			new AssetEntry("GESTURE",			"gesture",	"gesture",			true,		true,		true));
 	addEntry(LLAssetType::AT_SIMSTATE, 			new AssetEntry("SIMSTATE",			"simstate",	"simstate",			false,		false,		false));
 

File indra/llimage/llimage.cpp

 	  mCodec(codec),
 	  mDecoding(0),
 	  mDecoded(0),
-	  mDiscardLevel(0)
+	  mDiscardLevel(-1)
 {
 	mMemType = LLMemType::MTYPE_IMAGEFORMATTED;
 }

File indra/llinventory/llinventorytype.cpp

 bool inventory_and_asset_types_match(LLInventoryType::EType inventory_type,
 									 LLAssetType::EType asset_type)
 {
+	// Links can be of any inventory type.
+	if (LLAssetType::lookupIsLinkType(asset_type))
+		return true;
+
 	const InventoryEntry *entry = LLInventoryDictionary::getInstance()->lookup(inventory_type);
 	if (!entry) return false;
 

File indra/llplugin/llpluginclassmedia.cpp

 		mPlugin->idle();
 	}
 	
-	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL))
+	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()))
 	{
 		// Can't process a size change at this time
 	}
 {
 	if(type == MOUSE_EVENT_MOVE)
 	{
+		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
+		{
+			// Don't queue up mouse move events that can't be delivered.
+			return;
+		}
+
 		if((x == mLastMouseX) && (y == mLastMouseY))
 		{
 			// Don't spam unnecessary mouse move events.

File indra/llplugin/llpluginmessagepipe.cpp

 void LLPluginMessagePipe::processInput(void)
 {
 	// Look for input delimiter(s) in the input buffer.
-	int start = 0;
 	int delim;
-	while((delim = mInput.find(MESSAGE_DELIMITER, start)) != std::string::npos)
+	while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos)
 	{	
 		// Let the owner process this message
 		if (mOwner)
 		{
-			mOwner->receiveMessageRaw(mInput.substr(start, delim - start));
+			// Pull the message out of the input buffer before calling receiveMessageRaw.
+			// It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request)
+			// and this guarantees that the messages will get dequeued correctly.
+			std::string message(mInput, 0, delim);
+			mInput.erase(0, delim + 1);
+			mOwner->receiveMessageRaw(message);
 		}
 		else
 		{
 			LL_WARNS("Plugin") << "!mOwner" << LL_ENDL;
 		}
-		
-		start = delim + 1;
 	}
-	
-	// Remove delivered messages from the input buffer.
-	if(start != 0)
-		mInput = mInput.substr(start);
-	
 }
 

File indra/llplugin/llpluginprocesschild.cpp

 	mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
 	mSleepTime = PLUGIN_IDLE_SECONDS;	// default: send idle messages at 100Hz
 	mCPUElapsed = 0.0f;
+	mBlockingRequest = false;
+	mBlockingResponseReceived = false;
 }
 
 LLPluginProcessChild::~LLPluginProcessChild()
 
 void LLPluginProcessChild::sleep(F64 seconds)
 {
+	deliverQueuedMessages();
 	if(mMessagePipe)
 	{
 		mMessagePipe->pump(seconds);
 
 void LLPluginProcessChild::pump(void)
 {
+	deliverQueuedMessages();
 	if(mMessagePipe)
 	{
 		mMessagePipe->pump(0.0f);
 
 	LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL;
 
+	// Decode this message
+	LLPluginMessage parsed;
+	parsed.parse(message);
+
+	if(mBlockingRequest)
+	{
+		// We're blocking the plugin waiting for a response.
+
+		if(parsed.hasValue("blocking_response"))
+		{
+			// This is the message we've been waiting for -- fall through and send it immediately. 
+			mBlockingResponseReceived = true;
+		}
+		else
+		{
+			// Still waiting.  Queue this message and don't process it yet.
+			mMessageQueue.push(message);
+			return;
+		}
+	}
+	
 	bool passMessage = true;
 	
 	// FIXME: how should we handle queueing here?
 	
 	{
-		// Decode this message
-		LLPluginMessage parsed;
-		parsed.parse(message);
-		
 		std::string message_class = parsed.getClass();
 		if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
 		{
 void LLPluginProcessChild::receivePluginMessage(const std::string &message)
 {
 	LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL;
-
+	
+	if(mBlockingRequest)
+	{
+		// 
+		LL_ERRS("Plugin") << "Can't send a message while already waiting on a blocking request -- aborting!" << LL_ENDL;
+	}
+	
 	// Incoming message from the plugin instance
 	bool passMessage = true;
 
 		// Decode this message
 		LLPluginMessage parsed;
 		parsed.parse(message);
+		
+		if(parsed.hasValue("blocking_request"))
+		{
+			mBlockingRequest = true;
+		}
+
 		std::string message_class = parsed.getClass();
 		if(message_class == "base")
 		{
 		LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL;
 		writeMessageRaw(message);
 	}
+	
+	while(mBlockingRequest)
+	{
+		// The plugin wants to block and wait for a response to this message.
+		sleep(mSleepTime);	// this will pump the message pipe and process messages
+
+		if(mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL))
+		{
+			// Response has been received, or we've hit an error state.  Stop waiting.
+			mBlockingRequest = false;
+			mBlockingResponseReceived = false;
+		}
+	}
 }
 
 
 	LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
 	mState = state; 
 };
+
+void LLPluginProcessChild::deliverQueuedMessages()
+{
+	if(!mBlockingRequest)
+	{
+		while(!mMessageQueue.empty())
+		{
+			receiveMessageRaw(mMessageQueue.front());
+			mMessageQueue.pop();
+		}
+	}
+}

File indra/llplugin/llpluginprocesschild.h

 	LLTimer mHeartbeat;
 	F64		mSleepTime;
 	F64		mCPUElapsed;
+	bool	mBlockingRequest;
+	bool	mBlockingResponseReceived;
+	std::queue<std::string> mMessageQueue;
+	
+	void deliverQueuedMessages();
 	
 };
 

File indra/llplugin/llpluginprocessparent.cpp

 	mCPUUsage = 0.0;
 	mDisableTimeout = false;
 	mDebug = false;
+	mBlocked = false;
 
 	mPluginLaunchTimeout = 60.0f;
 	mPluginLockupTimeout = 15.0f;
 
 void LLPluginProcessParent::sendMessage(const LLPluginMessage &message)
 {
+	if(message.hasValue("blocking_response"))
+	{
+		mBlocked = false;
+
+		// reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked.
+		mHeartbeat.setTimerExpirySec(mPluginLockupTimeout);
+	}
 	
 	std::string buffer = message.generate();
 	LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL;	
 
 void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
 {
+	if(message.hasValue("blocking_request"))
+	{
+		mBlocked = true;
+	}
+
 	std::string message_class = message.getClass();
 	if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
 	{
 {
 	bool result = false;
 	
-	if(!mDisableTimeout && !mDebug)
+	if(!mProcess.isRunning())
 	{
-		if(!mProcess.isRunning())
-		{
-			LL_WARNS("Plugin") << "child exited" << llendl;
-			result = true;
-		}
-		else if(pluginLockedUp())
-		{
-			LL_WARNS("Plugin") << "timeout" << llendl;
-			result = true;
-		}
+		LL_WARNS("Plugin") << "child exited" << llendl;
+		result = true;
+	}
+	else if(pluginLockedUp())
+	{
+		LL_WARNS("Plugin") << "timeout" << llendl;
+		result = true;
 	}
 	
 	return result;
 
 bool LLPluginProcessParent::pluginLockedUp()
 {
+	if(mDisableTimeout || mDebug || mBlocked)
+	{
+		// Never time out a plugin process in these cases.
+		return false;
+	}
+	
 	// If the timer is running and has expired, the plugin has locked up.
 	return (mHeartbeat.getStarted() && mHeartbeat.hasExpired());
 }

File indra/llplugin/llpluginprocessparent.h

 	// returns true if the process has exited or we've had a fatal error
 	bool isDone(void);	
 	
+	// returns true if the process is currently waiting on a blocking request
+	bool isBlocked(void) { return mBlocked; };
+	
 	void killSockets(void);
 	
 	// Go to the proper error state
 	
 	bool mDisableTimeout;
 	bool mDebug;
+	bool mBlocked;
 
 	LLProcessLauncher mDebugger;
 	

File indra/llui/llflatlistview.cpp

 
 }
 
-void LLFlatListViewEx::updateNoItemsMessage(bool items_filtered)
+void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string)
 {
+	bool items_filtered = !filter_string.empty();
 	if (items_filtered)
 	{
 		// items were filtered
-		setNoItemsCommentText(mNoFilteredItemsMsg);
+		LLStringUtil::format_map_t args;
+		args["[SEARCH_TERM]"] = LLURI::escape(filter_string);
+		std::string text = mNoFilteredItemsMsg;
+		LLStringUtil::format(text, args);
+		setNoItemsCommentText(text);
 	}
 	else
 	{

File indra/llui/llflatlistview.h

 	/**
 	 * Applies a message for empty list depend on passed argument.
 	 *
-	 * @param items_filtered - if true message for filtered items will be set, otherwise for
-	 * completely empty list.
+	 * @param filter_string - if is not empty, message for filtered items will be set, otherwise for
+	 * completely empty list. Value of filter string will be passed as search_term in SLURL.
 	 */
-	void updateNoItemsMessage(bool items_filtered);
+	void updateNoItemsMessage(const std::string& filter_string);
 
 private:
 	std::string mNoFilteredItemsMsg;

File indra/llui/llloadingindicator.cpp

 
 LLPointer<LLUIImage> LLLoadingIndicator::Data::getNextImage(S8& idx) const
 {
-	// Actually selects previous image because
-	// current images seem to be in wrong order;
-	// performs array bounds checking.
-	idx = idx > 0 ? llmin(NIMAGES-1, idx-1) : NIMAGES-1;
+	// Calculate next index, performing array bounds checking.
+	idx = (idx >= NIMAGES || idx < 0) ? 0 : (idx + 1) % NIMAGES; 
 	return mImages[idx];
 }
 

File indra/newview/llagentwearables.cpp

 		msg->nextBlockFast(_PREHASH_ObjectData );
 		msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
 		msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
+#if ENABLE_MULTIATTACHMENTS
+		msg->addU8Fast(_PREHASH_AttachmentPt, 0 | ATTACHMENT_ADD );
+#else
 		msg->addU8Fast(_PREHASH_AttachmentPt, 0 );	// Wear at the previous or default attachment point
+#endif
 		pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
 		msg->addStringFast(_PREHASH_Name, item->getName());
 		msg->addStringFast(_PREHASH_Description, item->getDescription());

File indra/newview/llappearancemgr.cpp

 	}
 
 	//preparing the list of wearables in the correct order for LLAgentWearables
-	std::sort(wear_items.begin(), wear_items.end(), sort_by_description);
+	sortItemsByActualDescription(wear_items);
+
 
 	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
 
 	return result;
 }
 
+//static
+void LLAppearanceMgr::sortItemsByActualDescription(LLInventoryModel::item_array_t& items)
+{
+	if (items.size() < 2) return;
+
+	std::sort(items.begin(), items.end(), sort_by_description);
+}
 
 //#define DUMP_CAT_VERBOSE
 

File indra/newview/llappearancemgr.h

 	friend class LLSingleton<LLAppearanceMgr>;
 	
 public:
+	typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t;
+
 	void updateAppearanceFromCOF();
 	bool needToSaveCOF();
 	void updateCOF(const LLUUID& category, bool append = false);
 
 	bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body);
 
+	static void sortItemsByActualDescription(LLInventoryModel::item_array_t& items);
+
+	//Divvy items into arrays by wearable type
+	static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type);
+
 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();
 

File indra/newview/llavatarlist.cpp

 
 void LLAvatarList::setNameFilter(const std::string& filter)
 {
-	if (mNameFilter != filter)
+	std::string filter_upper = filter;
+	LLStringUtil::toUpper(filter_upper);
+	if (mNameFilter != filter_upper)
 	{
-		mNameFilter = filter;
+		mNameFilter = filter_upper;
 
 		// update message for empty state here instead of refresh() to avoid blinking when switch
 		// between tabs.
-		updateNoItemsMessage(!mNameFilter.empty());
+		updateNoItemsMessage(filter);
 		setDirty();
 	}
 }

File indra/newview/llcofwearables.cpp

 	clear();
 
 	LLInventoryModel::cat_array_t cats;
-	LLInventoryModel::item_array_t items;
+	LLInventoryModel::item_array_t cof_items;
+
+	gInventory.collectDescendents(LLAppearanceMgr::getInstance()->getCOF(), cats, cof_items, LLInventoryModel::EXCLUDE_TRASH);
+
+	populateAttachmentsAndBodypartsLists(cof_items);
+
+
+	LLAppearanceMgr::wearables_by_type_t clothing_by_type(WT_COUNT);
+	LLAppearanceMgr::getInstance()->divvyWearablesByType(cof_items, clothing_by_type);
 	
-	gInventory.collectDescendents(LLAppearanceMgr::getInstance()->getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH);
-	if (items.empty()) return;
+	populateClothingList(clothing_by_type);
+}
 
-	for (U32 i = 0; i < items.size(); ++i)
+
+void LLCOFWearables::populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items)
+{
+	for (U32 i = 0; i < cof_items.size(); ++i)
 	{
-		LLViewerInventoryItem* item = items.get(i);
+		LLViewerInventoryItem* item = cof_items.get(i);
 		if (!item) continue;
 
+		const LLAssetType::EType item_type = item->getType();
+		if (item_type == LLAssetType::AT_CLOTHING) continue;
+
 		LLPanelInventoryListItem* item_panel = LLPanelInventoryListItem::createItemPanel(item);
 		if (!item_panel) continue;
 
-		switch (item->getType())
+		if (item_type == LLAssetType::AT_OBJECT)
 		{
-			case LLAssetType::AT_OBJECT:
-				mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
-				break;
-
-			case LLAssetType::AT_BODYPART:
-				mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
-				break;
-
-			case LLAssetType::AT_CLOTHING:
-				mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
-				break;
-
-			default: break;
+			mAttachments->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
+		}
+		else if (item_type == LLAssetType::AT_BODYPART)
+		{
+			mBodyParts->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
+			addWearableTypeSeparator(mBodyParts);
 		}
 	}
 
-	mAttachments->sort(); //*TODO by Name
-	mAttachments->notify(REARRANGE); //notifying the parent about the list's size change (cause items were added with rearrange=false)
-	
-	mClothing->sort(); //*TODO by actual inventory item description
-	mClothing->notify(REARRANGE);
-	
-	mBodyParts->sort(); //*TODO by name
+	if (mAttachments->size())
+	{
+		mAttachments->sort(); //*TODO by Name
+		mAttachments->notify(REARRANGE); //notifying the parent about the list's size change (cause items were added with rearrange=false)
+	}
+
+	if (mBodyParts->size())
+	{
+		mBodyParts->sort(); //*TODO by name
+	}
+
+	addListButtonBar(mBodyParts, "panel_bodyparts_list_button_bar.xml");
 	mBodyParts->notify(REARRANGE);
 }
 
 
+void LLCOFWearables::populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
+{
+	llassert(clothing_by_type.size() == WT_COUNT);
+
+	addListButtonBar(mClothing, "panel_clothing_list_button_bar.xml");
+
+	for (U32 type = WT_SHIRT; type < WT_COUNT; ++type)
+	{
+		U32 size = clothing_by_type[type].size();
+		if (!size) continue;
+
+		LLAppearanceMgr::sortItemsByActualDescription(clothing_by_type[type]);
+
+		for (U32 i = 0; i < size; i++)
+		{
+			LLViewerInventoryItem* item = clothing_by_type[type][i];
+
+			LLPanelInventoryListItem* item_panel = LLPanelInventoryListItem::createItemPanel(item);
+			if (!item_panel) continue;
+
+			mClothing->addItem(item_panel, item->getUUID(), ADD_BOTTOM, false);
+		}
+
+		addWearableTypeSeparator(mClothing);
+	}
+
+	addClothingTypesDummies(clothing_by_type);
+
+	mClothing->notify(REARRANGE);
+}
+
+void LLCOFWearables::addListButtonBar(LLFlatListView* list, std::string xml_filename)
+{
+	llassert(list);
+	llassert(xml_filename.length());
+	
+	LLPanel::Params params;
+	LLPanel* button_bar = LLUICtrlFactory::create<LLPanel>(params);
+	LLUICtrlFactory::instance().buildPanel(button_bar, xml_filename);
+
+	LLRect rc = button_bar->getRect();
+	button_bar->reshape(list->getItemsRect().getWidth(), rc.getHeight());
+
+	list->addItem(button_bar, LLUUID::null, ADD_TOP, false);
+}
+
+//adding dummy items for missing wearable types
+void LLCOFWearables::addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type)
+{
+	llassert(clothing_by_type.size() == WT_COUNT);
+	
+	for (U32 type = WT_SHIRT; type < WT_COUNT; type++)
+	{
+		U32 size = clothing_by_type[type].size();
+		if (size) continue;
+
+		//*TODO create dummy item panel
+		
+		//*TODO add dummy item panel -> mClothing->addItem(dummy_item_panel, item->getUUID(), ADD_BOTTOM, false);
+
+		addWearableTypeSeparator(mClothing);
+	}
+}
+
+void LLCOFWearables::addWearableTypeSeparator(LLFlatListView* list)
+{
+	llassert(list);
+	
+	static LLXMLNodePtr separator_xml_node = getXMLNode("panel_wearable_type_separator.xml");
+	if (separator_xml_node->isNull()) return;
+
+	LLPanel* separator = LLUICtrlFactory::defaultBuilder<LLPanel>(separator_xml_node, NULL, NULL);
+
+	LLRect rc = separator->getRect();
+	rc.setOriginAndSize(0, 0, list->getItemsRect().getWidth(), rc.getHeight());
+	separator->setRect(rc);
+
+	list->addItem(separator, LLUUID::null, ADD_BOTTOM, false);
+}
+
 LLUUID LLCOFWearables::getSelectedUUID()
 {
 	if (!mLastSelectedList) return LLUUID::null;
 	mBodyParts->clear();
 }
 
+LLXMLNodePtr LLCOFWearables::getXMLNode(std::string xml_filename)
+{
+	LLXMLNodePtr xmlNode = NULL;
+	bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, xmlNode);
+	if (!success)
+	{
+		llwarning("Failed to read xml", 0);
+		return NULL;
+	}
+
+	return xmlNode;
+}
+
 //EOF

File indra/newview/llcofwearables.h

 #define LL_LLCOFWEARABLES_H
 
 #include "llpanel.h"
+#include "llinventorymodel.h"
+#include "llappearancemgr.h"
 
 class LLFlatListView;
 
 
 protected:
 
+	void populateAttachmentsAndBodypartsLists(const LLInventoryModel::item_array_t& cof_items);
+	void populateClothingList(LLAppearanceMgr::wearables_by_type_t& clothing_by_type);
+	
+	void addListButtonBar(LLFlatListView* list, std::string xml_filename);
+	void addClothingTypesDummies(const LLAppearanceMgr::wearables_by_type_t& clothing_by_type);
+	void addWearableTypeSeparator(LLFlatListView* list);
 	void onSelectionChange(LLFlatListView* selected_list);
 
+	LLXMLNodePtr getXMLNode(std::string xml_filename);
+
 	LLFlatListView* mAttachments;
 	LLFlatListView* mClothing;
 	LLFlatListView* mBodyParts;

File indra/newview/llfolderview.cpp

 		}
 		else
 		{
-			mStatusText = LLTrans::getString(getFilter()->getEmptyLookupMessage());
+			LLStringUtil::format_map_t args;
+			args["[SEARCH_TERM]"] = LLURI::escape(getFilter()->getFilterSubStringOrig());
+			mStatusText = LLTrans::getString(getFilter()->getEmptyLookupMessage(), args);
 			//font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL,  LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
 		}
 		mStatusTextBox->setValue(mStatusText);

File indra/newview/llgrouplist.cpp

 
 void LLGroupList::setNameFilter(const std::string& filter)
 {
-	if (mNameFilter != filter)
+	std::string filter_upper = filter;
+	LLStringUtil::toUpper(filter_upper);
+	if (mNameFilter != filter_upper)
 	{
-		mNameFilter = filter;
+		mNameFilter = filter_upper;
+
+		// set no items message depend on filter state
+		updateNoItemsMessage(filter);
+
 		setDirty();
 	}
 }
 	LLUUID				id;
 	bool				have_filter		= !mNameFilter.empty();
 
-	// set no items message depend on filter state & total count of groups
-	updateNoItemsMessage(have_filter);
-
 	clear();
 
 	for(S32 i = 0; i < count; ++i)

File indra/newview/llimview.cpp

 
 void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction)
 {
-	std::string you = LLTrans::getString("You");
-	std::string started_call = LLTrans::getString("started_call");
-	std::string joined_call = LLTrans::getString("joined_call");
+	std::string you_joined_call = LLTrans::getString("you_joined_call");
+	std::string you_started_call = LLTrans::getString("you_started_call");
 	std::string other_avatar_name = "";
 
 	std::string message;
 			switch(new_state)
 			{
 			case LLVoiceChannel::STATE_CALL_STARTED :
-				message = other_avatar_name + " " + started_call;
-				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
-				
-				break;
+				{
+					LLStringUtil::format_map_t string_args;
+					string_args["[NAME]"] = other_avatar_name;
+					message = LLTrans::getString("name_started_call", string_args);
+					LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);				
+					break;
+				}
 			case LLVoiceChannel::STATE_CONNECTED :
-				message = you + " " + joined_call;
-				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call);
 			default:
 				break;
 			}
 			switch(new_state)
 			{
 			case LLVoiceChannel::STATE_CALL_STARTED :
-				message = you + " " + started_call;
-				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call);
 				break;
 			case LLVoiceChannel::STATE_CONNECTED :
 				message = LLTrans::getString("answered_call");
 			switch(new_state)
 			{
 			case LLVoiceChannel::STATE_CONNECTED :
-				message = you + " " + joined_call;
-				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_joined_call);
 			default:
 				break;
 			}
 			switch(new_state)
 			{
 			case LLVoiceChannel::STATE_CALL_STARTED :
-				message = you + " " + started_call;
-				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+				LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, you_started_call);
 				break;
 			default:
 				break;
 				// send notification message to the corresponding chat 
 				if (mPayload["notify_box_type"].asString() == "VoiceInviteGroup" || mPayload["notify_box_type"].asString() == "VoiceInviteAdHoc")
 				{
-					std::string started_call = LLTrans::getString("started_call");
-					std::string message = mPayload["caller_name"].asString() + " " + started_call;
+					LLStringUtil::format_map_t string_args;
+					string_args["[NAME]"] = mPayload["caller_name"].asString();
+					std::string message = LLTrans::getString("name_started_call", string_args);
 					LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message);
 				}
 			}

File indra/newview/llinventorybridge.cpp

 		return FALSE;
 	}
 
-	// Disable delete from COF folder; have users explicitly choose "detach/take off".
+	// Disable delete from COF folder; have users explicitly choose "detach/take off",
+	// unless the item is not worn but in the COF (i.e. is bugged).
 	if (LLAppearanceMgr::instance().getIsProtectedCOFItem(mUUID))
 	{
-		return FALSE;
+		if (get_is_item_worn(mUUID))
+		{
+			return FALSE;
+		}
 	}
 
 	const LLInventoryObject *obj = model->getItem(mUUID);
 			}
 		}
 		const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i));
-		if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
+		if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
 		{
 			return FALSE;
 		}
 		disabled_items.push_back(std::string("Paste"));
 	}
 
-	if (gAgent.isGodlike())
-	{
-		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 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"));
 		{
 			disabled_items.push_back(std::string("Share"));
 		}
-		items.push_back(std::string("Open"));
+		
+		addOpenRightClickMenuOption(items);
 		items.push_back(std::string("Properties"));
 
 		getClipboardEntries(true, items, disabled_items, flags);
 	const LLInventoryObject *obj = getInventoryObject();
 
 	// Don't allow delete as a direct option from COF folder.
-	if (obj && obj->getIsLinkType() && isCOFFolder())
+	if (obj && obj->getIsLinkType() && isCOFFolder() && get_is_item_worn(mUUID))
 	{
 		return;
 	}
 	}
 }
 
+void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items)
+{
+	const LLInventoryObject *obj = getInventoryObject();
+	const BOOL is_link = (obj && obj->getIsLinkType());
+
+	if (is_link)
+		items.push_back(std::string("Open Original"));
+	else
+		items.push_back(std::string("Open"));
+}
+
 // *TODO: remove this
 BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
 {
 		gotoItem();
 	}
 
-	if ("open" == action)
+	if ("open" == action || "open_original" == action)
 	{
 		openItem();
 		return;
 			return FALSE;
 		}
 
-		if (gAgent.isGodlike())
-		{
-			// All items can be copied in god mode since you can
-			// at least paste-as-link the item, though you 
-			// still may not be able paste the item.
-			return TRUE;
-		}
-		else
-		{
-			return (item->getPermissions().allowCopyBy(gAgent.getID()));
-		}
+		// All items can be copied in god mode since you can
+		// at least paste-as-link the item, though you 
+		// still may not be able paste the item.
+		return TRUE;
+		// return (item->getPermissions().allowCopyBy(gAgent.getID()));
 	}
 	return FALSE;
 }
 
 BOOL LLFolderBridge::isItemCopyable() const
 {
-	return FALSE;
+	// Can copy folders to paste-as-link, but not for straight paste.
+	return TRUE;
 }
 
 BOOL LLFolderBridge::copyToClipboard() const
 					else
 					{
 						LLPointer<LLInventoryCallback> cb = NULL;
+						const std::string empty_description = "";
 						link_inventory_item(
 							gAgent.getID(),
 							inv_cat->getUUID(),
 							mUUID,
 							inv_cat->getName(),
+							empty_description,
 							LLAssetType::AT_LINK_FOLDER,
 							cb);
 					}
 			 ++iter)
 		{
 			const LLUUID &object_id = (*iter);
-#if SUPPORT_ENSEMBLES
 			if (LLInventoryCategory *cat = model->getCategory(object_id))
 			{
+				const std::string empty_description = "";
 				link_inventory_item(
 					gAgent.getID(),
 					cat->getUUID(),
 					parent_id,
 					cat->getName(),
+					empty_description,
 					LLAssetType::AT_LINK_FOLDER,
 					LLPointer<LLInventoryCallback>(NULL));
 			}
-			else
-#endif
-				if (LLInventoryItem *item = model->getItem(object_id))
-				{
-					link_inventory_item(
-						gAgent.getID(),
-						item->getLinkedUUID(),
-						parent_id,
-						item->getName(),
-						item->getDescription(),
-						LLAssetType::AT_LINK,
-						LLPointer<LLInventoryCallback>(NULL));
-				}
+			else if (LLInventoryItem *item = model->getItem(object_id))
+			{
+				link_inventory_item(
+					gAgent.getID(),
+					item->getLinkedUUID(),
+					parent_id,
+					item->getName(),
+					item->getDescription(),
+					LLAssetType::AT_LINK,
+					LLPointer<LLInventoryCallback>(NULL));
+			}
 		}
 	}
 }
 			disabled_items.push_back(std::string("Share"));
 		}
 
-		items.push_back(std::string("Open"));
+		addOpenRightClickMenuOption(items);
 		items.push_back(std::string("Properties"));
 
 		getClipboardEntries(true, items, disabled_items, flags);
 		{
 			disabled_items.push_back(std::string("Share"));
 		}
-		items.push_back(std::string("Open"));
+		addOpenRightClickMenuOption(items);
 		items.push_back(std::string("Properties"));
 
 		getClipboardEntries(true, items, disabled_items, flags);
 
 		if (!is_sidepanel)
 		{
-			items.push_back(std::string("Open"));
+			addOpenRightClickMenuOption(items);
 			items.push_back(std::string("Properties"));
 		}
 
 		
 		if (can_open && !is_sidepanel)
 		{
-			items.push_back(std::string("Open"));
+			addOpenRightClickMenuOption(items);
 		}
 
 		if (!is_sidepanel)
 
 // static
 void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type,
-								   const LLUUID& uuid,LLInventoryModel* model)
-{
-	LLInvFVBridgeAction* action = createAction(asset_type,uuid,model);
+								   const LLUUID& uuid,
+								   LLInventoryModel* model)
+{
+	// Perform indirection in case of link.
+	const LLUUID& linked_uuid = gInventory.getLinkedItemID(uuid);
+
+	LLInvFVBridgeAction* action = createAction(asset_type,linked_uuid,model);
 	if(action)
 	{
 		action->doIt();
 
 };
 
-class LLNotecardBridgeAction: public LLInvFVBridgeAction
+class LLNotecardBridgeAction
+: public LLInvFVBridgeAction
 {
 	friend class LLInvFVBridgeAction;
 public:

File indra/newview/llinventorybridge.h

 											menuentry_vec_t &disabled_items);
 	virtual void addDeleteContextMenuOptions(menuentry_vec_t &items,
 											 menuentry_vec_t &disabled_items);
-
+	virtual void addOpenRightClickMenuOption(menuentry_vec_t &items);
 protected:
 	LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid);
 

File indra/newview/llinventoryfilter.cpp

 		// appending new characters
 		const BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString);
 
-		mFilterSubString = string;
+		mFilterSubStringOrig = string;
+		LLStringUtil::trimHead(mFilterSubStringOrig);
+		mFilterSubString = mFilterSubStringOrig;
 		LLStringUtil::toUpper(mFilterSubString);
-		LLStringUtil::trimHead(mFilterSubString);
 		if (less_restrictive)
 		{
 			setModified(FILTER_LESS_RESTRICTIVE);

File indra/newview/llinventoryfilter.h

 
 	void 				setFilterSubString(const std::string& string);
 	const std::string& 	getFilterSubString(BOOL trim = FALSE) const;
+	const std::string& 	getFilterSubStringOrig() const { return mFilterSubStringOrig; } 
 	BOOL 				hasFilterString() const;
 
 	void 				setFilterPermissions(PermissionMask perms);
 
 	std::string::size_type	mSubStringMatchOffset;
 	std::string				mFilterSubString;
+	std::string				mFilterSubStringOrig;
 	const std::string		mName;
 
 	S32						mFilterGeneration;

File indra/newview/llpaneleditwearable.cpp

 #include "llagentwearables.h"
 #include "llscrollingpanelparam.h"
 
+#include "llcolorswatch.h"
+#include "lltexturectrl.h"
+#include "lltextureentry.h"
+#include "llviewercontrol.h"	// gSavedSettings
+#include "llviewertexturelist.h"
+
 // register panel with appropriate XML
 static LLRegisterPanelClassWrapper<LLPanelEditWearable> t_edit_wearable("panel_edit_wearable");
 
 	SUBPART_TATTOO
  };
 
+using namespace LLVOAvatarDefines;
+
 typedef std::vector<ESubpart> subpart_vec_t;
 
 // Locally defined classes
 		WearableEntry(EWearableType type,
 					  const std::string &title,
 					  const std::string &desc_title,
-					  U8 num_subparts, ... ); // number of subparts followed by a list of ESubparts
+					  U8 num_color_swatches,  // number of 'color_swatches'
+					  U8 num_texture_pickers, // number of 'texture_pickers'
+					  U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts
 
 
 		const EWearableType mWearableType;
 		const std::string   mTitle;
 		const std::string	mDescTitle;
 		subpart_vec_t		mSubparts;
-
+		texture_vec_t		mColorSwatchCtrls;
+		texture_vec_t		mTextureCtrls;
 	};
 
 	struct Wearables : public LLDictionary<EWearableType, WearableEntry>
 	} mSubparts;
 
 	const SubpartEntry*  getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); }
+
+	//--------------------------------------------------------------------
+	// Picker Control Entries
+	//--------------------------------------------------------------------
+public:
+	struct PickerControlEntry : public LLDictionaryEntry
+	{
+		PickerControlEntry(ETextureIndex tex_index,
+						   const std::string name,
+						   const LLUUID default_image_id = LLUUID::null,
+						   const bool allow_no_texture = false);
+		ETextureIndex		mTextureIndex;
+		const std::string	mControlName;
+		const LLUUID		mDefaultImageId;
+		const bool			mAllowNoTexture;
+	};
+
+	struct ColorSwatchCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
+	{
+		ColorSwatchCtrls();
+	} mColorSwatchCtrls;
+
+	struct TextureCtrls : public LLDictionary<ETextureIndex, PickerControlEntry>
+	{
+		TextureCtrls();
+	} mTextureCtrls;
+
+	const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); }
+	const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); }
 };
 
 LLEditWearableDictionary::LLEditWearableDictionary()
 
 LLEditWearableDictionary::Wearables::Wearables()
 {
-	addEntry(WT_SHAPE, new WearableEntry(WT_SHAPE,"edit_shape_title","shape_desc_text",9,	SUBPART_SHAPE_HEAD,	SUBPART_SHAPE_EYES,	SUBPART_SHAPE_EARS,	SUBPART_SHAPE_NOSE,	SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS, SUBPART_SHAPE_WHOLE));
-	addEntry(WT_SKIN, new WearableEntry(WT_SKIN,"edit_skin_title","skin_desc_text",4, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL));
-	addEntry(WT_HAIR, new WearableEntry(WT_HAIR,"edit_hair_title","hair_desc_text",4, SUBPART_HAIR_COLOR,	SUBPART_HAIR_STYLE,	SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL));
-	addEntry(WT_EYES, new WearableEntry(WT_EYES,"edit_eyes_title","eyes_desc_text",1, SUBPART_EYES));
-	addEntry(WT_SHIRT, new WearableEntry(WT_SHIRT,"edit_shirt_title","shirt_desc_text",1, SUBPART_SHIRT));
-	addEntry(WT_PANTS, new WearableEntry(WT_PANTS,"edit_pants_title","pants_desc_text",1, SUBPART_PANTS));
-	addEntry(WT_SHOES, new WearableEntry(WT_SHOES,"edit_shoes_title","shoes_desc_text",1, SUBPART_SHOES));
-	addEntry(WT_SOCKS, new WearableEntry(WT_SOCKS,"edit_socks_title","socks_desc_text",1, SUBPART_SOCKS));
-	addEntry(WT_JACKET, new WearableEntry(WT_JACKET,"edit_jacket_title","jacket_desc_text",1, SUBPART_JACKET));
-	addEntry(WT_GLOVES, new WearableEntry(WT_GLOVES,"edit_gloves_title","gloves_desc_text",1, SUBPART_GLOVES));
-	addEntry(WT_UNDERSHIRT, new WearableEntry(WT_UNDERSHIRT,"edit_undershirt_title","undershirt_desc_text",1, SUBPART_UNDERSHIRT));
-	addEntry(WT_UNDERPANTS, new WearableEntry(WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text",1, SUBPART_UNDERPANTS));
-	addEntry(WT_SKIRT, new WearableEntry(WT_SKIRT,"edit_skirt_title","skirt_desc_text",1, SUBPART_SKIRT));
-	addEntry(WT_ALPHA, new WearableEntry(WT_ALPHA,"edit_alpha_title","alpha_desc_text",1, SUBPART_ALPHA));
-	addEntry(WT_TATTOO, new WearableEntry(WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",1, SUBPART_TATTOO));
+	addEntry(WT_SHAPE, new WearableEntry(WT_SHAPE,"edit_shape_title","shape_desc_text",0,0,9,	SUBPART_SHAPE_HEAD,	SUBPART_SHAPE_EYES,	SUBPART_SHAPE_EARS,	SUBPART_SHAPE_NOSE,	SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS, SUBPART_SHAPE_WHOLE));
+	addEntry(WT_SKIN, new WearableEntry(WT_SKIN,"edit_skin_title","skin_desc_text",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL));
+	addEntry(WT_HAIR, new WearableEntry(WT_HAIR,"edit_hair_title","hair_desc_text",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR,	SUBPART_HAIR_STYLE,	SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL));
+	addEntry(WT_EYES, new WearableEntry(WT_EYES,"edit_eyes_title","eyes_desc_text",0,1,1, TEX_EYES_IRIS, SUBPART_EYES));
+	addEntry(WT_SHIRT, new WearableEntry(WT_SHIRT,"edit_shirt_title","shirt_desc_text",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT));
+	addEntry(WT_PANTS, new WearableEntry(WT_PANTS,"edit_pants_title","pants_desc_text",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS));
+	addEntry(WT_SHOES, new WearableEntry(WT_SHOES,"edit_shoes_title","shoes_desc_text",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES));
+	addEntry(WT_SOCKS, new WearableEntry(WT_SOCKS,"edit_socks_title","socks_desc_text",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS));
+	addEntry(WT_JACKET, new WearableEntry(WT_JACKET,"edit_jacket_title","jacket_desc_text",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET));
+	addEntry(WT_GLOVES, new WearableEntry(WT_GLOVES,"edit_gloves_title","gloves_desc_text",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES));
+	addEntry(WT_UNDERSHIRT, new WearableEntry(WT_UNDERSHIRT,"edit_undershirt_title","undershirt_desc_text",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT));
+	addEntry(WT_UNDERPANTS, new WearableEntry(WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS));
+	addEntry(WT_SKIRT, new WearableEntry(WT_SKIRT,"edit_skirt_title","skirt_desc_text",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT));
+	addEntry(WT_ALPHA, new WearableEntry(WT_ALPHA,"edit_alpha_title","alpha_desc_text",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA));
+	addEntry(WT_TATTOO, new WearableEntry(WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",0,3,1, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO));
 }
 
 LLEditWearableDictionary::WearableEntry::WearableEntry(EWearableType type,
 					  const std::string &title,
 					  const std::string &desc_title,
+					  U8 num_color_swatches,
+					  U8 num_texture_pickers,
 					  U8 num_subparts, ... ) :
 	LLDictionaryEntry(title),
 	mWearableType(type),
 	va_list argp;
 	va_start(argp, num_subparts);
 
+	for (U8 i = 0; i < num_color_swatches; ++i)
+	{
+		ETextureIndex index = (ETextureIndex)va_arg(argp,int);
+		mColorSwatchCtrls.push_back(index);
+	}
+
+	for (U8 i = 0; i < num_texture_pickers; ++i)
+	{
+		ETextureIndex index = (ETextureIndex)va_arg(argp,int);
+		mTextureCtrls.push_back(index);
+	}
+
 	for (U8 i = 0; i < num_subparts; ++i)
 	{
 		ESubpart part = (ESubpart)va_arg(argp,int);
 {
 }
 
+LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls()
+{
+	addEntry ( TEX_UPPER_SHIRT,  new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" ));
+	addEntry ( TEX_LOWER_PANTS,  new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" ));
+	addEntry ( TEX_LOWER_SHOES,  new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" ));
+	addEntry ( TEX_LOWER_SOCKS,  new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" ));
+	addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" ));
+	addEntry ( TEX_SKIRT,  new PickerControlEntry (TEX_SKIRT, "Color/Tint" ));
+	addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" ));
+	addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" ));
+	addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" ));
+}
+
+LLEditWearableDictionary::TextureCtrls::TextureCtrls()
+{
+	addEntry ( TEX_HEAD_BODYPAINT,  new PickerControlEntry (TEX_HEAD_BODYPAINT,  "Head Tattoos", LLUUID::null, TRUE ));
+	addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE ));
+	addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE ));
+	addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE ));
+	addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE ));
+	addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE ));
+	addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE ));
+	addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE ));
+	addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE ));
+	addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
+	addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE ));
+	addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE ));
+	addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE ));
+	addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
+	addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE ));
+	addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+	addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+	addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+	addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+	addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE ));
+	addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE ));
+	addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE ));
+	addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE ));
+}
+
+LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index,
+					 const std::string name,
+					 const LLUUID default_image_id,
+					 const bool allow_no_texture) :
+	LLDictionaryEntry(name),
+	mTextureIndex(tex_index),
+	mControlName(name),
+	mDefaultImageId(default_image_id),
+	mAllowNoTexture(allow_no_texture)
+{
+}
+
+// Helper functions.
+static const texture_vec_t null_texture_vec;
+
+// Specializations of this template function return a vector of texture indexes of particular control type
+// (i.e. LLColorSwatchCtrl or LLTextureCtrl) which are contained in given WearableEntry.
+template <typename T>
+const texture_vec_t&
+get_pickers_indexes(const LLEditWearableDictionary::WearableEntry *wearable_entry) { return null_texture_vec; }
+
+// Specializations of this template function return picker control entry for particular control type.
+template <typename T>
+const LLEditWearableDictionary::PickerControlEntry*
+get_picker_entry (const ETextureIndex index) { return NULL; }
+
+typedef boost::function<void(LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry*)> function_t;
+
+typedef struct PickerControlEntryNamePredicate
+{
+	PickerControlEntryNamePredicate(const std::string name) : mName (name) {};
+	bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const
+	{
+		return (entry && entry->mName == mName);
+	}
+private:
+	const std::string mName;
+} PickerControlEntryNamePredicate;
+
+// A full specialization of get_pickers_indexes for LLColorSwatchCtrl
+template <>
+const texture_vec_t&
+get_pickers_indexes<LLColorSwatchCtrl> (const LLEditWearableDictionary::WearableEntry *wearable_entry)
+{
+	if (!wearable_entry)
+	{
+		llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl;
+		return null_texture_vec;
+	}
+	return wearable_entry->mColorSwatchCtrls;
+}
+
+// A full specialization of get_pickers_indexes for LLTextureCtrl
+template <>
+const texture_vec_t&
+get_pickers_indexes<LLTextureCtrl> (const LLEditWearableDictionary::WearableEntry *wearable_entry)
+{
+	if (!wearable_entry)
+	{
+		llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl;
+		return null_texture_vec;
+	}
+	return wearable_entry->mTextureCtrls;
+}
+
+// A full specialization of get_picker_entry for LLColorSwatchCtrl
+template <>
+const LLEditWearableDictionary::PickerControlEntry*
+get_picker_entry<LLColorSwatchCtrl> (const ETextureIndex index)
+{
+	return LLEditWearableDictionary::getInstance()->getColorSwatch(index);
+}
+
+// A full specialization of get_picker_entry for LLTextureCtrl
+template <>
+const LLEditWearableDictionary::PickerControlEntry*
+get_picker_entry<LLTextureCtrl> (const ETextureIndex index)
+{
+	return LLEditWearableDictionary::getInstance()->getTexturePicker(index);
+}
+
+template <typename CtrlType, class Predicate>
+const LLEditWearableDictionary::PickerControlEntry*
+find_picker_ctrl_entry_if(EWearableType type, const Predicate pred)
+{
+	const LLEditWearableDictionary::WearableEntry *wearable_entry
+		= LLEditWearableDictionary::getInstance()->getWearable(type);
+	if (!wearable_entry)
+	{
+		llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+		return NULL;
+	}
+	const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
+	for (texture_vec_t::const_iterator
+			 iter = indexes.begin(),
+			 iter_end = indexes.end();
+		 iter != iter_end; ++iter)
+	{
+		const ETextureIndex te = *iter;
+		const LLEditWearableDictionary::PickerControlEntry*	entry
+			= get_picker_entry<CtrlType>(te);
+		if (!entry)
+		{
+			llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
+			continue;
+		}
+		if (pred(entry))
+		{
+			return entry;
+		}
+	}
+	return NULL;
+}
+
+template <typename CtrlType>
+void
+for_each_picker_ctrl_entry(LLPanel* panel, EWearableType type, function_t fun)
+{
+	if (!panel)
+	{
+		llwarns << "the panel wasn't passed for wearable of type: " << type << llendl;
+		return;
+	}
+	const LLEditWearableDictionary::WearableEntry *wearable_entry
+		= LLEditWearableDictionary::getInstance()->getWearable(type);
+	if (!wearable_entry)
+	{
+		llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl;
+		return;
+	}
+	const texture_vec_t& indexes = get_pickers_indexes<CtrlType>(wearable_entry);
+	for (texture_vec_t::const_iterator
+			 iter = indexes.begin(),
+			 iter_end = indexes.end();
+		 iter != iter_end; ++iter)
+	{
+		const ETextureIndex te = *iter;
+		const LLEditWearableDictionary::PickerControlEntry*	entry
+			= get_picker_entry<CtrlType>(te);
+		if (!entry)
+		{
+			llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl;
+			continue;
+		}
+		fun (panel, entry);
+	}
+}
+
+// The helper functions for pickers management
+static void init_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+	LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+	if (color_swatch_ctrl)
+	{
+		color_swatch_ctrl->setOriginal(self->getWearable()->getClothesColor(entry->mTextureIndex));
+	}
+}
+
+static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+	LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+	if (texture_ctrl)
+	{
+		texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId);
+		texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture);
+		// Don't allow (no copy) or (notransfer) textures to be selected.
+		texture_ctrl->setImmediateFilterPermMask(PERM_NONE);
+		texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);
+	}
+}
+
+static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+	LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+	if (color_swatch_ctrl)
+	{
+		color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex));
+	}
+}
+
+static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+	LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+	if (texture_ctrl)
+	{
+		LLUUID new_id;
+		LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex);
+		if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) )
+		{
+			new_id = lto->getID();
+		}
+		else
+		{
+			new_id = LLUUID::null;
+		}
+		LLUUID old_id = texture_ctrl->getImageAssetID();
+		if (old_id != new_id)
+		{
+			// texture has changed, close the floater to avoid DEV-22461
+			texture_ctrl->closeDependentFloater();
+		}
+		texture_ctrl->setImageAssetID(new_id);
+	}
+}
+
+static void set_enabled_color_swatch_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+	LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild<LLColorSwatchCtrl>(entry->mControlName);
+	if (color_swatch_ctrl)
+	{
+		color_swatch_ctrl->setEnabled(enabled);
+	}
+}
+
+static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry)
+{
+	LLTextureCtrl* texture_ctrl = panel->getChild<LLTextureCtrl>(entry->mControlName);
+	if (texture_ctrl)
+	{
+		texture_ctrl->setEnabled(enabled);
+	}
+}
 
 // LLPanelEditWearable
 
 	, mWearablePtr(NULL)
 	, mWearableItem(NULL)
 {
+	mCommitCallbackRegistrar.add("ColorSwatch.Commit", boost::bind(&LLPanelEditWearable::onColorSwatchCommit, this, _1));
+	mCommitCallbackRegistrar.add("TexturePicker.Commit", boost::bind(&LLPanelEditWearable::onTexturePickerCommit, this, _1));
 }
 
 //virtual
 void LLPanelEditWearable::draw()
 {
 	updateVerbs();
+	if (getWearable())
+	{
+		updatePanelPickerControls(getWearable()->getType());
+	}
 
 	LLPanel::draw();
 }
 	panel->revertChanges();
 }
 
+void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
+{
+	const LLTextureCtrl* texture_ctrl = dynamic_cast<const LLTextureCtrl*>(ctrl);
+	if (!texture_ctrl)
+	{
+		llwarns << "got commit signal from not LLTextureCtrl." << llendl;
+		return;
+	}
+
+	if (getWearable())
+	{
+		EWearableType type = getWearable()->getType();
+		const PickerControlEntryNamePredicate name_pred(texture_ctrl->getName());
+		const LLEditWearableDictionary::PickerControlEntry* entry
+			= find_picker_ctrl_entry_if<LLTextureCtrl, PickerControlEntryNamePredicate>(type, name_pred);
+		if (entry)
+		{
+			// Set the new version
+			LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID());
+			if( image->getID().isNull() )
+			{
+				image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
+			}
+			if (getWearable())
+			{
+				U32 index = gAgentWearables.getWearableIndex(getWearable());
+				gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
+				LLVisualParamHint::requestHintUpdates();
+				gAgentAvatarp->wearableUpdated(type, FALSE);
+			}
+		}
+		else
+		{
+			llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl;
+		}
+	}
+}
+
+void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl)
+{
+	if (getWearable())
+	{
+		EWearableType type = getWearable()->getType();
+		const PickerControlEntryNamePredicate name_pred(ctrl->getName());
+		const LLEditWearableDictionary::PickerControlEntry* entry
+			= find_picker_ctrl_entry_if<LLColorSwatchCtrl, PickerControlEntryNamePredicate>(type, name_pred);
+		if (entry)
+		{
+			const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex);
+			const LLColor4& new_color = LLColor4(ctrl->getValue());
+			if( old_color != new_color )
+			{
+				getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE);
+				LLVisualParamHint::requestHintUpdates();
+				gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+			}
+		}
+		else
+		{
+			llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl;
+		}
+	}
+}
+
+void LLPanelEditWearable::updatePanelPickerControls(EWearableType type)
+{
+	LLPanel* panel = getPanel(type);
+	if (!panel)
+		return;
+
+	bool is_modifiable = false;
+	bool is_complete   = false;
+	bool is_copyable   = false;
+
+	if(mWearableItem)
+	{
+		const LLPermissions& perm = mWearableItem->getPermissions();
+		is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
+		is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID());
+		is_complete = mWearableItem->isFinished();
+	}
+
+	if (is_modifiable && is_complete)
+	{
+		// Update picker controls
+		for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(update_color_swatch_ctrl, this, _1, _2));
+		for_each_picker_ctrl_entry <LLTextureCtrl>     (panel, type, boost::bind(update_texture_ctrl, this, _1, _2));
+	}
+
+	if (!is_modifiable || !is_complete || !is_copyable)
+	{
+		// Disable controls
+		for_each_picker_ctrl_entry <LLColorSwatchCtrl> (panel, type, boost::bind(set_enabled_color_swatch_ctrl, false, _1, _2));
+		for_each_picker_ctrl_entry <LLTextureCtrl>     (panel, type, boost::bind(set_enabled_texture_ctrl, false, _1, _2));
+	}
+}
 
 void LLPanelEditWearable::saveChanges()
 {
 		mDescTitle->setText(description_title);
 	}
 
+	// Update picker controls state
+	for_each_picker_ctrl_entry <LLColorSwatchCtrl> (targetPanel, type, boost::bind(set_enabled_color_swatch_ctrl, show, _1, _2));
+	for_each_picker_ctrl_entry <LLTextureCtrl>     (targetPanel, type, boost::bind(set_enabled_texture_ctrl, show, _1, _2));
 }
 
 void LLPanelEditWearable::initializePanel()
 
 		updateScrollingPanelUI();
 	}
+
+	// initialize texture and color picker controls
+	for_each_picker_ctrl_entry <LLColorSwatchCtrl> (getPanel(type), type, boost::bind(init_color_swatch_ctrl, this, _1, _2));
+	for_each_picker_ctrl_entry <LLTextureCtrl>     (getPanel(type), type, boost::bind(init_texture_ctrl, this, _1, _2));
+
 	updateVerbs();
 }
 

File indra/newview/llpaneleditwearable.h

 	// update bottom bar buttons ("Save", "Revert", etc)
 	void				updateVerbs();
 
+	void				onColorSwatchCommit(const LLUICtrl*);
+	void				onTexturePickerCommit(const LLUICtrl*);
+	void				updatePanelPickerControls(EWearableType type);
+
 	// the pointer to the wearable we're editing. NULL means we're not editing a wearable.
 	LLWearable *mWearablePtr;
 	LLViewerInventoryItem* mWearableItem;
 	LLPanel *mPanelSkirt;
 	LLPanel *mPanelAlpha;
 	LLPanel *mPanelTattoo;
-
 };
 
 #endif

File indra/newview/llpanellandmarks.cpp

 	if (!inventory_list->getFilter())
 		return;
 
+	inventory_list->getFilter()->setEmptyLookupMessage("PlacesNoMatchingItems");
 	inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK);
 	inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2));
 

File indra/newview/llpanelpeople.cpp

 LLPanelPeople::LLPanelPeople()
 	:	LLPanel(),
 		mFilterSubString(LLStringUtil::null),
+		mFilterSubStringOrig(LLStringUtil::null),
 		mFilterEditor(NULL),
 		mTabContainer(NULL),
 		mOnlineFriendList(NULL),
 	{
 		//update help text for empty lists
 		std::string message_name = mFilterSubString.empty() ? "no_friends_msg" : "no_filtered_friends_msg";
-		no_friends_text->setText(getString(message_name));
+		LLStringUtil::format_map_t args;
+		args["[SEARCH_TERM]"] = LLURI::escape(mFilterSubStringOrig);
+		no_friends_text->setText(getString(message_name, args));
 	}
 }
 
 
 void LLPanelPeople::onFilterEdit(const std::string& search_string)
 {
-	std::string search_upper = search_string;
+	mFilterSubStringOrig = search_string;
+	LLStringUtil::trimHead(mFilterSubStringOrig);
 	// Searches are case-insensitive
+	std::string search_upper = mFilterSubStringOrig;
 	LLStringUtil::toUpper(search_upper);
-	LLStringUtil::trimHead(search_upper);
 
 	if (mFilterSubString == search_upper)
 		return;
 
 
 	// Apply new filter.
-	mNearbyList->setNameFilter(mFilterSubString);
-	mOnlineFriendList->setNameFilter(mFilterSubString);
-	mAllFriendList->setNameFilter(mFilterSubString);
-	mRecentList->setNameFilter(mFilterSubString);
-	mGroupList->setNameFilter(mFilterSubString);
+	mNearbyList->setNameFilter(mFilterSubStringOrig);
+	mOnlineFriendList->setNameFilter(mFilterSubStringOrig);
+	mAllFriendList->setNameFilter(mFilterSubStringOrig);
+	mRecentList->setNameFilter(mFilterSubStringOrig);
+	mGroupList->setNameFilter(mFilterSubStringOrig);
 
 	setAccordionCollapsedByUser("tab_online", false);
 	setAccordionCollapsedByUser("tab_all", false);

File indra/newview/llpanelpeople.h

 	Updater*				mRecentListUpdater;
 
 	std::string				mFilterSubString;
+	std::string				mFilterSubStringOrig;
 };
 
 #endif //LL_LLPANELPEOPLE_H

File indra/newview/llpanelplaces.cpp

 		std::string string = search_string;
 
 		// Searches are case-insensitive
-		LLStringUtil::toUpper(string);
-		LLStringUtil::trimHead(string);
+		// but we don't convert the typed string to upper-case so that it can be fed to the web search as-is.
 
 		mActivePanel->onSearchEdit(string);
 	}

File indra/newview/llselectmgr.cpp

 		return;
 	}
 
-#if ENABLE_MULTIATTACHMENTS
-	attachment_point |= ATTACHMENT_ADD;
-#endif
 	BOOL build_mode = LLToolMgr::getInstance()->inEdit();
 	// Special case: Attach to default location for this object.
 	if (0 == attachment_point ||
 		get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)attachment_point, (LLViewerJointAttachment*)NULL))
 	{
+#if ENABLE_MULTIATTACHMENTS
+		attachment_point |= ATTACHMENT_ADD;
+#endif
 		sendListToRegions(
 			"ObjectAttach",
 			packAgentIDAndSessionAndAttachment, 

File indra/newview/llsidepanelappearance.cpp

 		mFilterSubString = search_string;
 
 		// Searches are case-insensitive
-		LLStringUtil::toUpper(mFilterSubString);
-		LLStringUtil::trimHead(mFilterSubString);
+		// but we don't convert the typed string to upper-case so that it can be fed to the web search as-is.
 
 		mPanelOutfitsInventory->onSearchEdit(mFilterSubString);
 	}

File indra/newview/lltexturefetch.cpp

 	}
 
 protected:
-	LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
-						 F32 priority, S32 discard, S32 size);
 	LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
 						 F32 priority, S32 discard, S32 size);
 
 		QUEUED = 1,
 		SENT_SIM = 2
 	};
+	enum e_write_to_cache_state //mWriteToCacheState
+	{
+		NOT_WRITE = 0,